Пример #1
0
PRBool
gfxXlibSurface::GetColormapAndVisual(Colormap* aColormap, Visual** aVisual)
{
    if (!mSurfaceValid)
        return PR_FALSE;

    XRenderPictFormat* format =
        cairo_xlib_surface_get_xrender_format(CairoSurface());
    Screen* screen = cairo_xlib_surface_get_screen(CairoSurface());
    Visual* visual = cairo_xlib_surface_get_visual(CairoSurface());

    return DisplayTable::GetColormapAndVisual(screen, format, visual,
                                              aColormap, aVisual);
}
Пример #2
0
/* Vladimir Vukicevic reported that surfaces were being created with
 * mismatching Visuals and XRenderPictFormats.
 */
static cairo_bool_t
surface_compare_visual_and_format (cairo_surface_t *surface)
{
    Display *dpy;
    Visual *visual;
    XRenderPictFormat *format;

    dpy = cairo_xlib_surface_get_display (surface);

    visual = cairo_xlib_surface_get_visual (surface);
    if (visual == NULL)
        return TRUE;

    format = cairo_xlib_surface_get_xrender_format (surface);
    if (format == NULL)
        return TRUE;

    return format == XRenderFindVisualFormat (dpy, visual);

}
static already_AddRefed<gfxXlibSurface>
CreateTempXlibSurface (gfxASurface *destination, nsIntSize size,
                       bool canDrawOverBackground,
                       PRUint32 flags, Screen *screen, Visual *visual,
                       DrawingMethod *method)
{
    bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0;
    bool supportsAlternateVisual =
        (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
    bool supportsAlternateScreen = supportsAlternateVisual &&
        (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN);

    cairo_surface_t *target = destination->CairoSurface();
    cairo_surface_type_t target_type = cairo_surface_get_type (target);
    cairo_content_t target_content = cairo_surface_get_content (target);

    Screen *target_screen = target_type == CAIRO_SURFACE_TYPE_XLIB ?
        cairo_xlib_surface_get_screen (target) : screen;

    // When the background has an alpha channel, we need to draw with an alpha
    // channel anyway, so there is no need to copy the background.  If
    // doCopyBackground is set here, we'll also need to check below that the
    // background can copied without any loss in format conversions.
    bool doCopyBackground = !drawIsOpaque && canDrawOverBackground &&
        target_content == CAIRO_CONTENT_COLOR;

    if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) {
        // Prefer a visual on the target screen.
        // (If !drawIsOpaque, we'll need doCopyBackground or an alpha channel.)
        visual = DefaultVisualOfScreen(target_screen);
        screen = target_screen;

    } else if (doCopyBackground || (supportsAlternateVisual && drawIsOpaque)) {
        // Analyse the pixel formats either to check whether we can
        // doCopyBackground or to see if we can find a better visual for
        // opaque drawing.
        Visual *target_visual = NULL;
        XRenderPictFormat *target_format = NULL;
        switch (target_type) {
        case CAIRO_SURFACE_TYPE_XLIB:
            target_visual = cairo_xlib_surface_get_visual (target);
            target_format = cairo_xlib_surface_get_xrender_format (target);
            break;
        case CAIRO_SURFACE_TYPE_IMAGE: {
            gfxASurface::gfxImageFormat imageFormat =
                static_cast<gfxImageSurface*>(destination)->Format();
            target_visual = gfxXlibSurface::FindVisual(screen, imageFormat);
            Display *dpy = DisplayOfScreen(screen);
            if (target_visual) {
                target_format = XRenderFindVisualFormat(dpy, target_visual);
            } else {
                target_format =
                    gfxXlibSurface::FindRenderFormat(dpy, imageFormat);
            }                
            break;
        }
        default:
            break;
        }

        if (supportsAlternateVisual &&
            (supportsAlternateScreen || screen == target_screen)) {
            if (target_visual) {
                visual = target_visual;
                screen = target_screen;
            }
        }
        // Could try harder to match formats across screens for background
        // copying when !supportsAlternateScreen, if we cared.  Preferably
        // we'll find a visual below with an alpha channel anyway; if so, the
        // background won't need to be copied.

        if (doCopyBackground && visual != target_visual &&
            !FormatConversionIsExact(screen, visual, target_format)) {
            doCopyBackground = false;
        }
    }

    if (supportsAlternateVisual && !drawIsOpaque &&
        (screen != target_screen ||
         !(doCopyBackground || VisualHasAlpha(screen, visual)))) {
        // Try to find a visual with an alpha channel.
        Screen *visualScreen =
            supportsAlternateScreen ? target_screen : screen;
        Visual *argbVisual =
            gfxXlibSurface::FindVisual(visualScreen,
                                       gfxASurface::ImageFormatARGB32);
        if (argbVisual) {
            visual = argbVisual;
            screen = visualScreen;
        } else if (!doCopyBackground &&
                   gfxXlibSurface::DepthOfVisual(screen, visual) != 24) {
            // Will need to do alpha extraction; prefer a 24-bit visual.
            // No advantage in using the target screen.
            Visual *rgb24Visual =
                gfxXlibSurface::FindVisual(screen,
                                           gfxASurface::ImageFormatRGB24);
            if (rgb24Visual) {
                visual = rgb24Visual;
            }
        }
    }

    Drawable drawable =
        (screen == target_screen && target_type == CAIRO_SURFACE_TYPE_XLIB) ?
        cairo_xlib_surface_get_drawable (target) : RootWindowOfScreen(screen);

    nsRefPtr<gfxXlibSurface> surface =
        gfxXlibSurface::Create(screen, visual,
                               gfxIntSize(size.width, size.height),
                               drawable);

    if (drawIsOpaque ||
        surface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
        NATIVE_DRAWING_NOTE(drawIsOpaque ?
                            ", SIMPLE OPAQUE\n" : ", SIMPLE WITH ALPHA");
        *method = eSimple;
    } else if (doCopyBackground) {
        NATIVE_DRAWING_NOTE(", COPY BACKGROUND\n");
        *method = eCopyBackground;
    } else {
        NATIVE_DRAWING_NOTE(", SLOW ALPHA EXTRACTION\n");
        *method = eAlphaExtraction;
    }

    return surface.forget();
}
/**
 * Try the direct path.
 * @return True if we took the direct path
 */
bool
gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size,
                                  PRUint32 flags,
                                  Screen *screen, Visual *visual)
{
    cairo_t *cr = ctx->GetCairo();

    /* Check that the target surface is an xlib surface. */
    cairo_surface_t *target = cairo_get_group_target (cr);
    if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) {
        NATIVE_DRAWING_NOTE("FALLBACK: non-X surface");
        return false;
    }
    
    cairo_matrix_t matrix;
    cairo_get_matrix (cr, &matrix);
    double device_offset_x, device_offset_y;
    cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y);

    /* Draw() checked that the matrix contained only a very-close-to-integer
       translation.  Here (and in several other places and thebes) device
       offsets are assumed to be integer. */
    NS_ASSERTION(PRInt32(device_offset_x) == device_offset_x &&
                 PRInt32(device_offset_y) == device_offset_y,
                 "Expected integer device offsets");
    nsIntPoint offset(NS_lroundf(matrix.x0 + device_offset_x),
                      NS_lroundf(matrix.y0 + device_offset_y));
    
    int max_rectangles = 0;
    if (flags & DRAW_SUPPORTS_CLIP_RECT) {
      max_rectangles = 1;
    }
    if (flags & DRAW_SUPPORTS_CLIP_LIST) {
      max_rectangles = MAX_STATIC_CLIP_RECTANGLES;
    }

    /* The client won't draw outside the surface so consider this when
       analysing clip rectangles. */
    nsIntRect bounds(offset, size);
    bounds.IntersectRect(bounds,
                         nsIntRect(0, 0,
                                   cairo_xlib_surface_get_width(target),
                                   cairo_xlib_surface_get_height(target)));

    bool needs_clip = true;
    nsIntRect rectangles[MAX_STATIC_CLIP_RECTANGLES];
    int rect_count = 0;

    /* Check that the clip is rectangular and aligned on unit boundaries. */
    /* Temporarily set the matrix for _get_rectangular_clip. It's basically
       the identity matrix, but we must adjust for the fact that our
       offset-rect is in device coordinates. */
    cairo_identity_matrix (cr);
    cairo_translate (cr, -device_offset_x, -device_offset_y);
    bool have_rectangular_clip =
        _get_rectangular_clip (cr, bounds, &needs_clip,
                               rectangles, max_rectangles, &rect_count);
    cairo_set_matrix (cr, &matrix);
    if (!have_rectangular_clip)
        return false;

    /* Stop now if everything is clipped out */
    if (needs_clip && rect_count == 0)
        return true;
      
    /* Check that the screen is supported.
       Visuals belong to screens, so, if alternate visuals are not supported,
       then alternate screens cannot be supported. */  
    bool supports_alternate_visual =
        (flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
    bool supports_alternate_screen = supports_alternate_visual &&
        (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN);
    if (!supports_alternate_screen &&
        cairo_xlib_surface_get_screen (target) != screen) {
        NATIVE_DRAWING_NOTE("FALLBACK: non-default screen");
        return false;
    }
        
    /* Check that there is a visual */
    Visual *target_visual = cairo_xlib_surface_get_visual (target);
    if (!target_visual) {
        NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface");
        return false;
    }        
    /* Check that the visual is supported */
    if (!supports_alternate_visual && target_visual != visual) {
        // Only the format of the visual is important (not the GLX properties)
        // for Xlib or XRender drawing.
        XRenderPictFormat *target_format =
            cairo_xlib_surface_get_xrender_format (target);
        if (!target_format ||
            (target_format !=
             XRenderFindVisualFormat (DisplayOfScreen(screen), visual))) {
            NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual");
            return false;
        }
    }
  
    /* we're good to go! */
    NATIVE_DRAWING_NOTE("TAKING FAST PATH\n");
    cairo_surface_flush (target);
    nsRefPtr<gfxASurface> surface = gfxASurface::Wrap(target);
    nsresult rv = DrawWithXlib(static_cast<gfxXlibSurface*>(surface.get()),
                               offset, rectangles,
                               needs_clip ? rect_count : 0);
    if (NS_SUCCEEDED(rv)) {
        cairo_surface_mark_dirty (target);
        return true;
    }
    return false;
}
XRenderPictFormat*
gfxXlibSurface::XRenderFormat()
{
    return cairo_xlib_surface_get_xrender_format(CairoSurface());
}
Пример #6
0
static cairo_test_status_t
preamble (cairo_test_context_t *ctx)
{
    Display *dpy;
    XRenderPictFormat *orig_format, *format;
    cairo_surface_t *surface;
    Pixmap pixmap;
    int screen;
    cairo_test_status_t result;

    result = CAIRO_TEST_UNTESTED;

    if (! cairo_test_is_target_enabled (ctx, "xlib"))
	goto CLEANUP_TEST;

    dpy = XOpenDisplay (NULL);
    if (! dpy) {
	cairo_test_log (ctx, "Error: Cannot open display: %s, skipping.\n",
			XDisplayName (NULL));
	goto CLEANUP_TEST;
    }

    result = CAIRO_TEST_FAILURE;

    screen = DefaultScreen (dpy);

    cairo_test_log (ctx, "Testing with image surface.\n");

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);

    format = cairo_xlib_surface_get_xrender_format (surface);
    if (format != NULL) {
	cairo_test_log (ctx, "Error: expected NULL for image surface\n");
	goto CLEANUP_SURFACE;
    }

    cairo_surface_destroy (surface);

    cairo_test_log (ctx, "Testing with non-xrender xlib surface.\n");

    pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
			    1, 1, DefaultDepth (dpy, screen));
    surface = cairo_xlib_surface_create (dpy, pixmap,
					 DefaultVisual (dpy, screen),
					 1, 1);
    orig_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
    format = cairo_xlib_surface_get_xrender_format (surface);
    if (format != orig_format) {
	cairo_test_log (ctx, "Error: did not receive the same format as XRenderFindVisualFormat\n");
	goto CLEANUP_PIXMAP;
    }
    cairo_surface_destroy (surface);
    XFreePixmap (dpy, pixmap);

    cairo_test_log (ctx, "Testing with xlib xrender surface.\n");

    orig_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
    pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy),
			    1, 1, 32);
    surface = cairo_xlib_surface_create_with_xrender_format (dpy,
							     pixmap,
							     DefaultScreenOfDisplay (dpy),
							     orig_format,
							     1, 1);
    format = cairo_xlib_surface_get_xrender_format (surface);
    if (format != orig_format) {
	cairo_test_log (ctx, "Error: did not receive the same format originally set\n");
	goto CLEANUP_PIXMAP;
    }

    cairo_test_log (ctx, "Testing without the X Render extension.\n");

    cairo_boilerplate_xlib_surface_disable_render (surface);

    format = cairo_xlib_surface_get_xrender_format (surface);
    if (format != NULL) {
	cairo_test_log (ctx, "Error: did not receive a NULL format as expected\n");
	goto CLEANUP_PIXMAP;
    }

    result = CAIRO_TEST_SUCCESS;

  CLEANUP_PIXMAP:
    XFreePixmap (dpy, pixmap);
  CLEANUP_SURFACE:
    cairo_surface_destroy (surface);

    XCloseDisplay (dpy);

  CLEANUP_TEST:
    return result;
}