static cairo_surface_t * _create_temp_xlib_surface (cairo_t *cr, Display *dpy, int width, int height, cairo_xlib_drawing_support_t capabilities) { /* base the temp surface on the *screen* surface, not any intermediate * group surface, because the screen surface is more likely to have * characteristics that the xlib-using code is likely to be happy with */ cairo_surface_t *target = cairo_get_target (cr); Drawable target_drawable = cairo_xlib_surface_get_drawable (target); int screen_index = DefaultScreen (dpy); Drawable drawable = RootWindow (dpy, screen_index); Screen *screen = DefaultScreenOfDisplay (dpy); Visual *visual = DefaultVisual (dpy, screen_index); int depth = DefaultDepth (dpy, screen_index); Pixmap pixmap; cairo_surface_t *result; pixmap_free_struct *pfs; /* make the temporary surface match target_drawable to the extent supported by the native rendering code */ if (target_drawable) { Screen *target_screen = cairo_xlib_surface_get_screen (target); Visual *target_visual = cairo_xlib_surface_get_visual (target); if ((target_screen == screen || (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN)) && target_visual && (target_visual == DefaultVisualOfScreen (target_screen) || (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL))) { drawable = target_drawable; dpy = cairo_xlib_surface_get_display (target); visual = target_visual; depth = cairo_xlib_surface_get_depth (target); } } pfs = malloc (sizeof(pixmap_free_struct)); if (pfs == NULL) return NULL; pixmap = XCreatePixmap (dpy, drawable, width, height, depth); if (!pixmap) { free (pfs); return NULL; } pfs->dpy = dpy; pfs->pixmap = pixmap; result = cairo_xlib_surface_create (dpy, pixmap, visual, width, height); if (cairo_surface_status (result) != CAIRO_STATUS_SUCCESS) { pixmap_free_func (pfs); return NULL; } cairo_surface_set_user_data (result, &pixmap_free_key, pfs, pixmap_free_func); return result; }
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); }
already_AddRefed<gfxASurface> gfxXlibSurface::CreateSimilarSurface(gfxContentType aContent, const gfxIntSize& aSize) { if (!mSurface || !mSurfaceValid) { return nsnull; } if (aContent == CONTENT_COLOR) { // cairo_surface_create_similar will use a matching visual if it can. // However, systems with 16-bit or indexed default visuals may benefit // from rendering with 24-bit formats. static PRBool force24bpp = GetForce24bppPref(); if (force24bpp && cairo_xlib_surface_get_depth(CairoSurface()) != 24) { XRenderPictFormat* format = XRenderFindStandardFormat(mDisplay, PictStandardRGB24); if (format) { // Cairo only performs simple self-copies as desired if it // knows that this is a Pixmap surface. It only knows that // surfaces are pixmap surfaces if it creates the Pixmap // itself, so we use cairo_surface_create_similar with a // temporary reference surface to indicate the format. Screen* screen = cairo_xlib_surface_get_screen(CairoSurface()); nsRefPtr<gfxXlibSurface> depth24reference = gfxXlibSurface::Create(screen, format, gfxIntSize(1, 1), mDrawable); if (depth24reference) return depth24reference-> gfxASurface::CreateSimilarSurface(aContent, aSize); } } } return gfxASurface::CreateSimilarSurface(aContent, aSize); }
static cairo_bool_t _draw_onto_temp_xlib_surface (cairo_surface_t *temp_xlib_surface, cairo_xlib_drawing_callback callback, void *closure, double background_gray_value) { Drawable d = cairo_xlib_surface_get_drawable (temp_xlib_surface); Screen *screen = cairo_xlib_surface_get_screen (temp_xlib_surface); Visual *visual = cairo_xlib_surface_get_visual (temp_xlib_surface); cairo_bool_t result; cairo_t *cr = cairo_create (temp_xlib_surface); cairo_set_source_rgb (cr, background_gray_value, background_gray_value, background_gray_value); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_destroy (cr); cairo_surface_flush (temp_xlib_surface); /* no clipping is needed because the callback can't draw outside the native surface anyway */ result = callback (closure, screen, d, visual, 0, 0, NULL, 0); cairo_surface_mark_dirty (temp_xlib_surface); return result; }
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; }
static cairo_test_status_t test_cairo_xlib_surface_get_screen (cairo_surface_t *surface) { Screen *screen = cairo_xlib_surface_get_screen (surface); return screen == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; }
Screen* gfxXlibSurface::XScreen() { return cairo_xlib_surface_get_screen(CairoSurface()); }
/** * Try the direct path. * @param status the status returned by the callback, if we took the direct path * @return True if we took the direct path */ static cairo_bool_t _draw_with_xlib_direct (cairo_t *cr, Display *default_display, cairo_xlib_drawing_callback callback, void *closure, int bounds_width, int bounds_height, cairo_xlib_drawing_support_t capabilities) { cairo_surface_t *target; Drawable d; cairo_matrix_t matrix; short offset_x, offset_y; cairo_bool_t needs_clip; XRectangle rectangles[MAX_STATIC_CLIP_RECTANGLES]; int rect_count; double device_offset_x, device_offset_y; int max_rectangles; Screen *screen; Visual *visual; cairo_bool_t have_rectangular_clip; target = cairo_get_group_target (cr); cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y); d = cairo_xlib_surface_get_drawable (target); cairo_get_matrix (cr, &matrix); /* Check that the matrix is a pure translation */ /* XXX test some approximation to == 1.0 here? */ if (matrix.xx != 1.0 || matrix.yy != 1.0 || matrix.xy != 0.0 || matrix.yx != 0.0) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: matrix not a pure translation\n"); return False; } /* Check that the matrix translation offsets (adjusted for device offset) are integers */ if (!_convert_coord_to_short (matrix.x0 + device_offset_x, &offset_x) || !_convert_coord_to_short (matrix.y0 + device_offset_y, &offset_y)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-integer offset\n"); return False; } max_rectangles = 0; if (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_RECT) { max_rectangles = 1; } if (capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_CLIP_LIST) { max_rectangles = MAX_STATIC_CLIP_RECTANGLES; } /* 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); have_rectangular_clip = _get_rectangular_clip (cr, offset_x, offset_y, bounds_width, bounds_height, &needs_clip, rectangles, max_rectangles, &rect_count); cairo_set_matrix (cr, &matrix); if (!have_rectangular_clip) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: unsupported clip\n"); return False; } /* Stop now if everything is clipped out */ if (needs_clip && rect_count == 0) { CAIRO_XLIB_DRAWING_NOTE("TAKING FAST PATH: all clipped\n"); return True; } /* Check that the operator is OVER */ if (cairo_get_operator (cr) != CAIRO_OPERATOR_OVER) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-OVER operator\n"); return False; } /* Check that the offset is supported */ if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_OFFSET) && (offset_x != 0 || offset_y != 0)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: unsupported offset\n"); return False; } /* Check that the target surface is an xlib surface. Do this late because we might complete early above when when the object to be drawn is completely clipped out. */ if (!d) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-X surface\n"); return False; } /* Check that the display is supported */ screen = cairo_xlib_surface_get_screen (target); if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_ALTERNATE_SCREEN) && screen != DefaultScreenOfDisplay (default_display)) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-default display\n"); return False; } /* Check that there is a visual */ visual = cairo_xlib_surface_get_visual (target); if (!visual) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: no Visual for surface\n"); return False; } /* Check that the visual is supported */ if (!(capabilities & CAIRO_XLIB_DRAWING_SUPPORTS_NONDEFAULT_VISUAL) && DefaultVisualOfScreen (screen) != visual) { CAIRO_XLIB_DRAWING_NOTE("TAKING SLOW PATH: non-default visual\n"); return False; } /* we're good to go! */ CAIRO_XLIB_DRAWING_NOTE("TAKING FAST PATH\n"); cairo_surface_flush (target); callback (closure, screen, d, visual, offset_x, offset_y, rectangles, needs_clip ? rect_count : 0); cairo_surface_mark_dirty (target); return True; }