SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf) : mId(aSurf->XDrawable()) , mSize(aSurf->GetSize()) { const XRenderPictFormat *pictFormat = aSurf->XRenderFormat(); if (pictFormat) { mFormat = pictFormat->id; } else { mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid; } }
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); }
SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf, bool aForwardGLX) : mId(aSurf->XDrawable()) , mSize(aSurf->GetSize()) , mGLXPixmap(None) { const XRenderPictFormat *pictFormat = aSurf->XRenderFormat(); if (pictFormat) { mFormat = pictFormat->id; } else { mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid; } #ifdef GL_PROVIDER_GLX if (aForwardGLX) { mGLXPixmap = aSurf->GetGLXPixmap(); } #endif }
/* 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 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_visual (cairo_surface_t *surface) { Visual *visual = cairo_xlib_surface_get_visual (surface); return visual == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; }
/** * 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; }