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); }
/* 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()); }
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; }