LCOV - code coverage report
Current view: top level - gfx/thebes - gfxXlibNativeRenderer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 269 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "gfxXlibNativeRenderer.h"
       7             : 
       8             : #include "gfxXlibSurface.h"
       9             : #include "gfxImageSurface.h"
      10             : #include "gfxContext.h"
      11             : #include "gfxPlatform.h"
      12             : #include "gfxAlphaRecovery.h"
      13             : #include "cairo-xlib.h"
      14             : #include "cairo-xlib-xrender.h"
      15             : #include "mozilla/gfx/BorrowedContext.h"
      16             : #include "mozilla/gfx/HelpersCairo.h"
      17             : #include "gfx2DGlue.h"
      18             : 
      19             : using namespace mozilla;
      20             : using namespace mozilla::gfx;
      21             : 
      22             : #if 0
      23             : #include <stdio.h>
      24             : #define NATIVE_DRAWING_NOTE(m) fprintf(stderr, m)
      25             : #else
      26             : #define NATIVE_DRAWING_NOTE(m) do {} while (0)
      27             : #endif
      28             : 
      29             : /* We have four basic strategies available:
      30             : 
      31             :    1) 'direct': If the target is an xlib surface, and other conditions are met,
      32             :       we can pass the underlying drawable directly to the callback.
      33             : 
      34             :    2) 'simple': If the drawing is opaque, or we can draw to a surface with an
      35             :       alpha channel, then we can create a temporary xlib surface, pass its
      36             :       underlying drawable to the callback, and composite the result using
      37             :       cairo.
      38             : 
      39             :    3) 'copy-background': If the drawing is not opaque but the target is
      40             :       opaque, and we can draw to a surface with format such that pixel
      41             :       conversion to and from the target format is exact, we can create a
      42             :       temporary xlib surface, copy the background from the target, pass the
      43             :       underlying drawable to the callback, and copy back to the target.
      44             : 
      45             :       This strategy is not used if the pixel format conversion is not exact,
      46             :       because that would mean that drawing intended to be very transparent
      47             :       messes with other content.
      48             : 
      49             :       The strategy is prefered over simple for non-opaque drawing and opaque
      50             :       targets on the same screen as compositing without alpha is a simpler
      51             :       operation.
      52             : 
      53             :    4) 'alpha-extraction': create a temporary xlib surface, fill with black,
      54             :       pass its underlying drawable to the callback, copy the results to a
      55             :       cairo image surface, repeat with a white background, update the on-black
      56             :       image alpha values by comparing the two images, then paint the on-black
      57             :       image using cairo.
      58             : 
      59             :       Sure would be nice to have an X extension or GL to do this for us on the
      60             :       server...
      61             : */
      62             : 
      63             : static cairo_bool_t
      64           0 : _convert_coord_to_int (double coord, int32_t *v)
      65             : {
      66           0 :     *v = (int32_t)coord;
      67             :     /* XXX allow some tolerance here? */
      68           0 :     return *v == coord;
      69             : }
      70             : 
      71             : static bool
      72           0 : _get_rectangular_clip (cairo_t *cr,
      73             :                        const IntRect& bounds,
      74             :                        bool *need_clip,
      75             :                        IntRect *rectangles, int max_rectangles,
      76             :                        int *num_rectangles)
      77             : {
      78             :     cairo_rectangle_list_t *cliplist;
      79             :     cairo_rectangle_t *clips;
      80             :     int i;
      81           0 :     bool retval = true;
      82             : 
      83           0 :     cliplist = cairo_copy_clip_rectangle_list (cr);
      84           0 :     if (cliplist->status != CAIRO_STATUS_SUCCESS) {
      85           0 :         retval = false;
      86             :         NATIVE_DRAWING_NOTE("FALLBACK: non-rectangular clip");
      87           0 :         goto FINISH;
      88             :     }
      89             : 
      90             :     /* the clip is always in surface backend coordinates (i.e. native backend coords) */
      91           0 :     clips = cliplist->rectangles;
      92             : 
      93           0 :     for (i = 0; i < cliplist->num_rectangles; ++i) {
      94             : 
      95           0 :         IntRect rect;
      96           0 :         if (!_convert_coord_to_int (clips[i].x, &rect.x) ||
      97           0 :             !_convert_coord_to_int (clips[i].y, &rect.y) ||
      98           0 :             !_convert_coord_to_int (clips[i].width, &rect.width) ||
      99           0 :             !_convert_coord_to_int (clips[i].height, &rect.height))
     100             :         {
     101           0 :             retval = false;
     102             :             NATIVE_DRAWING_NOTE("FALLBACK: non-integer clip");
     103           0 :             goto FINISH;
     104             :         }
     105             : 
     106           0 :         if (rect.IsEqualInterior(bounds)) {
     107             :             /* the bounds are entirely inside the clip region so we don't need to clip. */
     108           0 :             *need_clip = false;
     109           0 :             goto FINISH;
     110             :         }
     111             : 
     112           0 :         NS_ASSERTION(bounds.Contains(rect),
     113             :                      "Was expecting to be clipped to bounds");
     114             : 
     115           0 :         if (i >= max_rectangles) {
     116           0 :             retval = false;
     117             :             NATIVE_DRAWING_NOTE("FALLBACK: unsupported clip rectangle count");
     118           0 :             goto FINISH;
     119             :         }
     120             : 
     121           0 :         rectangles[i] = rect;
     122             :     }
     123             :   
     124           0 :     *need_clip = true;
     125           0 :     *num_rectangles = cliplist->num_rectangles;
     126             : 
     127             : FINISH:
     128           0 :     cairo_rectangle_list_destroy (cliplist);
     129             : 
     130           0 :     return retval;
     131             : }
     132             : 
     133             : #define MAX_STATIC_CLIP_RECTANGLES 50
     134             : 
     135             : /**
     136             :  * Try the direct path.
     137             :  * @return True if we took the direct path
     138             :  */
     139             : bool
     140           0 : gfxXlibNativeRenderer::DrawDirect(DrawTarget* aDT, IntSize size,
     141             :                                   uint32_t flags,
     142             :                                   Screen *screen, Visual *visual)
     143             : {
     144             :     // We need to actually borrow the context because we want to read out the
     145             :     // clip rectangles.
     146           0 :     BorrowedCairoContext borrowed(aDT);
     147           0 :     if (!borrowed.mCairo) {
     148           0 :       return false;
     149             :     }
     150             : 
     151           0 :     bool direct = DrawCairo(borrowed.mCairo, size, flags, screen, visual);
     152           0 :     borrowed.Finish();
     153             : 
     154           0 :     return direct;
     155             : }
     156             : 
     157             : bool
     158           0 : gfxXlibNativeRenderer::DrawCairo(cairo_t* cr, IntSize size,
     159             :                                  uint32_t flags,
     160             :                                  Screen *screen, Visual *visual)
     161             : {
     162             :     /* Check that the target surface is an xlib surface. */
     163           0 :     cairo_surface_t *target = cairo_get_group_target (cr);
     164           0 :     if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) {
     165             :         NATIVE_DRAWING_NOTE("FALLBACK: non-X surface");
     166           0 :         return false;
     167             :     }
     168             : 
     169             :     cairo_matrix_t matrix;
     170           0 :     cairo_get_matrix (cr, &matrix);
     171             :     double device_offset_x, device_offset_y;
     172           0 :     cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y);
     173             : 
     174             :     /* Draw() checked that the matrix contained only a very-close-to-integer
     175             :        translation.  Here (and in several other places and thebes) device
     176             :        offsets are assumed to be integer. */
     177           0 :     NS_ASSERTION(int32_t(device_offset_x) == device_offset_x &&
     178             :                  int32_t(device_offset_y) == device_offset_y,
     179             :                  "Expected integer device offsets");
     180           0 :     IntPoint offset(NS_lroundf(matrix.x0 + device_offset_x),
     181           0 :                       NS_lroundf(matrix.y0 + device_offset_y));
     182             : 
     183           0 :     int max_rectangles = 0;
     184           0 :     if (flags & DRAW_SUPPORTS_CLIP_RECT) {
     185           0 :       max_rectangles = 1;
     186             :     }
     187           0 :     if (flags & DRAW_SUPPORTS_CLIP_LIST) {
     188           0 :       max_rectangles = MAX_STATIC_CLIP_RECTANGLES;
     189             :     }
     190             : 
     191             :     /* The client won't draw outside the surface so consider this when
     192             :        analysing clip rectangles. */
     193           0 :     IntRect bounds(offset, size);
     194             :     bounds.IntersectRect(bounds,
     195           0 :                          IntRect(0, 0,
     196             :                                    cairo_xlib_surface_get_width(target),
     197           0 :                                    cairo_xlib_surface_get_height(target)));
     198             : 
     199           0 :     bool needs_clip = true;
     200           0 :     IntRect rectangles[MAX_STATIC_CLIP_RECTANGLES];
     201           0 :     int rect_count = 0;
     202             : 
     203             :     /* Check that the clip is rectangular and aligned on unit boundaries. */
     204             :     /* Temporarily set the matrix for _get_rectangular_clip. It's basically
     205             :        the identity matrix, but we must adjust for the fact that our
     206             :        offset-rect is in device coordinates. */
     207           0 :     cairo_identity_matrix (cr);
     208           0 :     cairo_translate (cr, -device_offset_x, -device_offset_y);
     209             :     bool have_rectangular_clip =
     210             :         _get_rectangular_clip (cr, bounds, &needs_clip,
     211           0 :                                rectangles, max_rectangles, &rect_count);
     212           0 :     cairo_set_matrix (cr, &matrix);
     213           0 :     if (!have_rectangular_clip)
     214           0 :         return false;
     215             : 
     216             :     /* Stop now if everything is clipped out */
     217           0 :     if (needs_clip && rect_count == 0)
     218           0 :         return true;
     219             : 
     220             :     /* Check that the screen is supported.
     221             :        Visuals belong to screens, so, if alternate visuals are not supported,
     222             :        then alternate screens cannot be supported. */
     223             :     bool supports_alternate_visual =
     224           0 :         (flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
     225           0 :     bool supports_alternate_screen = supports_alternate_visual &&
     226           0 :         (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN);
     227           0 :     if (!supports_alternate_screen &&
     228           0 :         cairo_xlib_surface_get_screen (target) != screen) {
     229             :         NATIVE_DRAWING_NOTE("FALLBACK: non-default screen");
     230           0 :         return false;
     231             :     }
     232             : 
     233             :     /* Check that there is a visual */
     234           0 :     Visual *target_visual = cairo_xlib_surface_get_visual (target);
     235           0 :     if (!target_visual) {
     236             :         NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface");
     237           0 :         return false;
     238             :     }
     239             :     /* Check that the visual is supported */
     240           0 :     if (!supports_alternate_visual && target_visual != visual) {
     241             :         // Only the format of the visual is important (not the GLX properties)
     242             :         // for Xlib or XRender drawing.
     243             :         XRenderPictFormat *target_format =
     244           0 :             cairo_xlib_surface_get_xrender_format (target);
     245           0 :         if (!target_format ||
     246             :             (target_format !=
     247           0 :              XRenderFindVisualFormat (DisplayOfScreen(screen), visual))) {
     248             :             NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual");
     249           0 :             return false;
     250             :         }
     251             :     }
     252             : 
     253             :     /* we're good to go! */
     254             :     NATIVE_DRAWING_NOTE("TAKING FAST PATH\n");
     255           0 :     cairo_surface_flush (target);
     256           0 :     nsresult rv = DrawWithXlib(target,
     257             :                                offset, rectangles,
     258           0 :                                needs_clip ? rect_count : 0);
     259           0 :     if (NS_SUCCEEDED(rv)) {
     260           0 :         cairo_surface_mark_dirty (target);
     261           0 :         return true;
     262             :     }
     263           0 :     return false;
     264             : }
     265             : 
     266             : static bool
     267           0 : VisualHasAlpha(Screen *screen, Visual *visual) {
     268             :     // There may be some other visuals format with alpha but usually this is
     269             :     // the only one we care about.
     270           0 :     return visual->c_class == TrueColor &&
     271           0 :         visual->bits_per_rgb == 8 &&
     272           0 :         visual->red_mask == 0xff0000 &&
     273           0 :         visual->green_mask == 0xff00 &&
     274           0 :         visual->blue_mask == 0xff &&
     275           0 :         gfxXlibSurface::DepthOfVisual(screen, visual) == 32;
     276             : }
     277             : 
     278             : // Returns whether pixel conversion between visual and format is exact (in
     279             : // both directions).
     280             : static bool
     281           0 : FormatConversionIsExact(Screen *screen, Visual *visual, XRenderPictFormat *format) {
     282           0 :     if (!format ||
     283           0 :         visual->c_class != TrueColor ||
     284           0 :         format->type != PictTypeDirect ||
     285           0 :         gfxXlibSurface::DepthOfVisual(screen, visual) != format->depth)
     286           0 :         return false;
     287             : 
     288             :     XRenderPictFormat *visualFormat =
     289           0 :         XRenderFindVisualFormat(DisplayOfScreen(screen), visual);
     290             : 
     291           0 :     if (visualFormat->type != PictTypeDirect )
     292           0 :         return false;
     293             : 
     294           0 :     const XRenderDirectFormat& a = visualFormat->direct;
     295           0 :     const XRenderDirectFormat& b = format->direct;
     296           0 :     return a.redMask == b.redMask &&
     297           0 :         a.greenMask == b.greenMask &&
     298           0 :         a.blueMask == b.blueMask;
     299             : }
     300             : 
     301             : // The 3 non-direct strategies described above.
     302             : // The surface format and strategy are inter-dependent.
     303             : enum DrawingMethod {
     304             :     eSimple,
     305             :     eCopyBackground,
     306             :     eAlphaExtraction
     307             : };
     308             : 
     309             : static cairo_surface_t*
     310           0 : CreateTempXlibSurface (cairo_surface_t* cairoTarget,
     311             :                        DrawTarget* drawTarget,
     312             :                        IntSize size,
     313             :                        bool canDrawOverBackground,
     314             :                        uint32_t flags, Screen *screen, Visual *visual,
     315             :                        DrawingMethod *method)
     316             : {
     317           0 :     NS_ASSERTION(cairoTarget || drawTarget, "Must have some type");
     318             : 
     319           0 :     bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0;
     320             :     bool supportsAlternateVisual =
     321           0 :         (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
     322           0 :     bool supportsAlternateScreen = supportsAlternateVisual &&
     323           0 :         (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN);
     324             : 
     325             :     cairo_surface_type_t cairoTargetType =
     326           0 :         cairoTarget ? cairo_surface_get_type (cairoTarget) : (cairo_surface_type_t)0xFF;
     327             : 
     328           0 :     Screen *target_screen = cairoTargetType == CAIRO_SURFACE_TYPE_XLIB ?
     329           0 :         cairo_xlib_surface_get_screen (cairoTarget) : screen;
     330             : 
     331             :     // When the background has an alpha channel, we need to draw with an alpha
     332             :     // channel anyway, so there is no need to copy the background.  If
     333             :     // doCopyBackground is set here, we'll also need to check below that the
     334             :     // background can copied without any loss in format conversions.
     335           0 :     bool doCopyBackground = !drawIsOpaque && canDrawOverBackground &&
     336           0 :         cairoTarget && cairo_surface_get_content (cairoTarget) == CAIRO_CONTENT_COLOR;
     337             : 
     338           0 :     if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) {
     339             :         // Prefer a visual on the target screen.
     340             :         // (If !drawIsOpaque, we'll need doCopyBackground or an alpha channel.)
     341           0 :         visual = DefaultVisualOfScreen(target_screen);
     342           0 :         screen = target_screen;
     343             : 
     344           0 :     } else if (doCopyBackground || (supportsAlternateVisual && drawIsOpaque)) {
     345             :         // Analyse the pixel formats either to check whether we can
     346             :         // doCopyBackground or to see if we can find a better visual for
     347             :         // opaque drawing.
     348           0 :         Visual *target_visual = nullptr;
     349           0 :         XRenderPictFormat *target_format = nullptr;
     350           0 :         if (cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) {
     351           0 :             target_visual = cairo_xlib_surface_get_visual (cairoTarget);
     352           0 :             target_format = cairo_xlib_surface_get_xrender_format (cairoTarget);
     353           0 :         } else if (cairoTargetType == CAIRO_SURFACE_TYPE_IMAGE || drawTarget) {
     354             :             gfxImageFormat imageFormat =
     355           0 :                 drawTarget ? SurfaceFormatToImageFormat(drawTarget->GetFormat()) :
     356           0 :                     CairoFormatToGfxFormat(cairo_image_surface_get_format(cairoTarget));
     357           0 :             target_visual = gfxXlibSurface::FindVisual(screen, imageFormat);
     358           0 :             Display *dpy = DisplayOfScreen(screen);
     359           0 :             if (target_visual) {
     360           0 :                 target_format = XRenderFindVisualFormat(dpy, target_visual);
     361             :             } else {
     362             :                 target_format =
     363           0 :                     gfxXlibSurface::FindRenderFormat(dpy, imageFormat);
     364             :             }
     365             :         }
     366             : 
     367           0 :         if (supportsAlternateVisual &&
     368           0 :             (supportsAlternateScreen || screen == target_screen)) {
     369           0 :             if (target_visual) {
     370           0 :                 visual = target_visual;
     371           0 :                 screen = target_screen;
     372             :             }
     373             :         }
     374             :         // Could try harder to match formats across screens for background
     375             :         // copying when !supportsAlternateScreen, if we cared.  Preferably
     376             :         // we'll find a visual below with an alpha channel anyway; if so, the
     377             :         // background won't need to be copied.
     378             : 
     379           0 :         if (doCopyBackground && visual != target_visual &&
     380           0 :             !FormatConversionIsExact(screen, visual, target_format)) {
     381           0 :             doCopyBackground = false;
     382             :         }
     383             :     }
     384             : 
     385           0 :     if (supportsAlternateVisual && !drawIsOpaque &&
     386           0 :         (screen != target_screen ||
     387           0 :          !(doCopyBackground || VisualHasAlpha(screen, visual)))) {
     388             :         // Try to find a visual with an alpha channel.
     389             :         Screen *visualScreen =
     390           0 :             supportsAlternateScreen ? target_screen : screen;
     391             :         Visual *argbVisual =
     392             :             gfxXlibSurface::FindVisual(visualScreen,
     393           0 :                                        SurfaceFormat::A8R8G8B8_UINT32);
     394           0 :         if (argbVisual) {
     395           0 :             visual = argbVisual;
     396           0 :             screen = visualScreen;
     397           0 :         } else if (!doCopyBackground &&
     398           0 :                    gfxXlibSurface::DepthOfVisual(screen, visual) != 24) {
     399             :             // Will need to do alpha extraction; prefer a 24-bit visual.
     400             :             // No advantage in using the target screen.
     401             :             Visual *rgb24Visual =
     402             :                 gfxXlibSurface::FindVisual(screen,
     403           0 :                                            SurfaceFormat::X8R8G8B8_UINT32);
     404           0 :             if (rgb24Visual) {
     405           0 :                 visual = rgb24Visual;
     406             :             }
     407             :         }
     408             :     }
     409             : 
     410             :     Drawable drawable =
     411           0 :         (screen == target_screen && cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) ?
     412           0 :         cairo_xlib_surface_get_drawable (cairoTarget) : RootWindowOfScreen(screen);
     413             : 
     414             :     cairo_surface_t *surface =
     415             :         gfxXlibSurface::CreateCairoSurface(screen, visual,
     416           0 :                                            IntSize(size.width, size.height),
     417           0 :                                            drawable);
     418           0 :     if (!surface) {
     419           0 :         return nullptr;
     420             :     }
     421             : 
     422           0 :     if (drawIsOpaque ||
     423           0 :         cairo_surface_get_content(surface) == CAIRO_CONTENT_COLOR_ALPHA) {
     424             :         NATIVE_DRAWING_NOTE(drawIsOpaque ?
     425             :                             ", SIMPLE OPAQUE\n" : ", SIMPLE WITH ALPHA");
     426           0 :         *method = eSimple;
     427           0 :     } else if (doCopyBackground) {
     428             :         NATIVE_DRAWING_NOTE(", COPY BACKGROUND\n");
     429           0 :         *method = eCopyBackground;
     430             :     } else {
     431             :         NATIVE_DRAWING_NOTE(", SLOW ALPHA EXTRACTION\n");
     432           0 :         *method = eAlphaExtraction;
     433             :     }
     434             : 
     435           0 :     return surface;
     436             : }
     437             : 
     438             : bool
     439           0 : gfxXlibNativeRenderer::DrawOntoTempSurface(cairo_surface_t *tempXlibSurface,
     440             :                                            IntPoint offset)
     441             : {
     442           0 :     cairo_surface_flush(tempXlibSurface);
     443             :     /* no clipping is needed because the callback can't draw outside the native
     444             :        surface anyway */
     445           0 :     nsresult rv = DrawWithXlib(tempXlibSurface, offset, nullptr, 0);
     446           0 :     cairo_surface_mark_dirty(tempXlibSurface);
     447           0 :     return NS_SUCCEEDED(rv);
     448             : }
     449             : 
     450             : static already_AddRefed<gfxImageSurface>
     451           0 : CopyXlibSurfaceToImage(cairo_surface_t *tempXlibSurface,
     452             :                        IntSize size,
     453             :                        gfxImageFormat format)
     454             : {
     455           0 :     RefPtr<gfxImageSurface> result = new gfxImageSurface(size, format);
     456             : 
     457           0 :     cairo_t* copyCtx = cairo_create(result->CairoSurface());
     458           0 :     cairo_set_source_surface(copyCtx, tempXlibSurface, 0, 0);
     459           0 :     cairo_set_operator(copyCtx, CAIRO_OPERATOR_SOURCE);
     460           0 :     cairo_paint(copyCtx);
     461           0 :     cairo_destroy(copyCtx);
     462             : 
     463           0 :     return result.forget();
     464             : }
     465             : 
     466             : void
     467           0 : gfxXlibNativeRenderer::Draw(gfxContext* ctx, IntSize size,
     468             :                             uint32_t flags, Screen *screen, Visual *visual)
     469             : {
     470           0 :     gfxMatrix matrix = ctx->CurrentMatrix();
     471             : 
     472             :     // We can only draw direct or onto a copied background if pixels align and
     473             :     // native drawing is compatible with the current operator.  (The matrix is
     474             :     // actually also pixel-exact for flips and right-angle rotations, which
     475             :     // would permit copying the background but not drawing direct.)
     476           0 :     bool matrixIsIntegerTranslation = !matrix.HasNonIntegerTranslation();
     477           0 :     bool canDrawOverBackground = matrixIsIntegerTranslation &&
     478           0 :          ctx->CurrentOp() == CompositionOp::OP_OVER;
     479             : 
     480             :     // The padding of 0.5 for non-pixel-exact transformations used here is
     481             :     // the same as what _cairo_pattern_analyze_filter uses.
     482           0 :     const gfxFloat filterRadius = 0.5;
     483           0 :     gfxRect affectedRect(0.0, 0.0, size.width, size.height);
     484           0 :     if (!matrixIsIntegerTranslation) {
     485             :         // The filter footprint means that the affected rectangle is a
     486             :         // little larger than the drawingRect;
     487           0 :         affectedRect.Inflate(filterRadius);
     488             : 
     489             :         NATIVE_DRAWING_NOTE("FALLBACK: matrix not integer translation");
     490           0 :     } else if (!canDrawOverBackground) {
     491             :         NATIVE_DRAWING_NOTE("FALLBACK: unsupported operator");
     492             :     }
     493             : 
     494           0 :     DrawTarget* drawTarget = ctx->GetDrawTarget();
     495           0 :     if (!drawTarget) {
     496           0 :         gfxCriticalError() << "gfxContext without a DrawTarget";
     497           0 :         return;
     498             :     }
     499             : 
     500             :     // Clipping to the region affected by drawing allows us to consider only
     501             :     // the portions of the clip region that will be affected by drawing.
     502           0 :     gfxRect clipExtents;
     503             :     {
     504           0 :         gfxContextAutoSaveRestore autoSR(ctx);
     505           0 :         ctx->Clip(affectedRect);
     506             : 
     507           0 :         clipExtents = ctx->GetClipExtents();
     508           0 :         if (clipExtents.IsEmpty()) {
     509           0 :             return; // nothing to do
     510             :         }
     511           0 :         if (canDrawOverBackground &&
     512           0 :             DrawDirect(drawTarget, size, flags, screen, visual)) {
     513           0 :           return;
     514             :         }
     515             :     }
     516             : 
     517           0 :     IntRect drawingRect(IntPoint(0, 0), size);
     518             :     // Drawing need only be performed within the clip extents
     519             :     // (and padding for the filter).
     520           0 :     if (!matrixIsIntegerTranslation) {
     521             :         // The source surface may need to be a little larger than the clip
     522             :         // extents due to the filter footprint.
     523           0 :         clipExtents.Inflate(filterRadius);
     524             :     }
     525           0 :     clipExtents.RoundOut();
     526             : 
     527           0 :     IntRect intExtents(int32_t(clipExtents.X()),
     528           0 :                          int32_t(clipExtents.Y()),
     529           0 :                          int32_t(clipExtents.Width()),
     530           0 :                          int32_t(clipExtents.Height()));
     531           0 :     drawingRect.IntersectRect(drawingRect, intExtents);
     532             : 
     533           0 :     gfxPoint offset(drawingRect.x, drawingRect.y);
     534             : 
     535             :     DrawingMethod method;
     536           0 :     Matrix dtTransform = drawTarget->GetTransform();
     537           0 :     gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
     538             :     cairo_t* cairo = static_cast<cairo_t*>
     539           0 :         (drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
     540           0 :     cairo_surface_t* cairoTarget = cairo ? cairo_get_group_target(cairo) : nullptr;
     541             :     cairo_surface_t* tempXlibSurface =
     542           0 :         CreateTempXlibSurface(cairoTarget, drawTarget, size,
     543             :                               canDrawOverBackground, flags, screen, visual,
     544           0 :                               &method);
     545           0 :     if (!tempXlibSurface) {
     546           0 :         return;
     547             :     }
     548             : 
     549           0 :     bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
     550           0 :     if (!drawIsOpaque) {
     551           0 :         cairo_t* tmpCtx = cairo_create(tempXlibSurface);
     552           0 :         if (method == eCopyBackground) {
     553           0 :             NS_ASSERTION(cairoTarget, "eCopyBackground only used when there's a cairoTarget");
     554           0 :             cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
     555           0 :             gfxPoint pt = -(offset + deviceTranslation);
     556           0 :             cairo_set_source_surface(tmpCtx, cairoTarget, pt.x, pt.y);
     557             :             // The copy from the tempXlibSurface to the target context should
     558             :             // use operator SOURCE, but that would need a mask to bound the
     559             :             // operation.  Here we only copy opaque backgrounds so operator
     560             :             // OVER will behave like SOURCE masked by the surface.
     561           0 :             NS_ASSERTION(cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR,
     562             :                          "Don't copy background with a transparent surface");
     563             :         } else {
     564           0 :             cairo_set_operator(tmpCtx, CAIRO_OPERATOR_CLEAR);
     565             :         }
     566           0 :         cairo_paint(tmpCtx);
     567           0 :         cairo_destroy(tmpCtx);
     568             :     }
     569             : 
     570           0 :     if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
     571           0 :         cairo_surface_destroy(tempXlibSurface);
     572           0 :         return;
     573             :     }
     574             : 
     575             :     SurfaceFormat moz2DFormat =
     576           0 :         cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
     577           0 :             SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
     578           0 :     if (method != eAlphaExtraction) {
     579             :         RefPtr<SourceSurface> sourceSurface =
     580           0 :             Factory::CreateSourceSurfaceForCairoSurface(tempXlibSurface, size, moz2DFormat);
     581           0 :         if (sourceSurface) {
     582           0 :             drawTarget->DrawSurface(sourceSurface,
     583           0 :                 Rect(offset.x, offset.y, size.width, size.height),
     584           0 :                 Rect(0, 0, size.width, size.height));
     585             :         }
     586           0 :         cairo_surface_destroy(tempXlibSurface);
     587           0 :         return;
     588             :     }
     589             : 
     590             :     RefPtr<gfxImageSurface> blackImage =
     591           0 :         CopyXlibSurfaceToImage(tempXlibSurface, size, SurfaceFormat::A8R8G8B8_UINT32);
     592             : 
     593           0 :     cairo_t* tmpCtx = cairo_create(tempXlibSurface);
     594           0 :     cairo_set_source_rgba(tmpCtx, 1.0, 1.0, 1.0, 1.0);
     595           0 :     cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
     596           0 :     cairo_paint(tmpCtx);
     597           0 :     cairo_destroy(tmpCtx);
     598           0 :     DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft());
     599             :     RefPtr<gfxImageSurface> whiteImage =
     600           0 :         CopyXlibSurfaceToImage(tempXlibSurface, size, SurfaceFormat::X8R8G8B8_UINT32);
     601             : 
     602           0 :     if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
     603           0 :         whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
     604           0 :         if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
     605           0 :             cairo_surface_destroy(tempXlibSurface);
     606           0 :             return;
     607             :         }
     608             : 
     609           0 :         gfxASurface* paintSurface = blackImage;
     610             :         RefPtr<SourceSurface> sourceSurface =
     611           0 :             Factory::CreateSourceSurfaceForCairoSurface(paintSurface->CairoSurface(),
     612           0 :                                                         size, moz2DFormat);
     613           0 :         if (sourceSurface) {
     614           0 :             drawTarget->DrawSurface(sourceSurface,
     615           0 :                 Rect(offset.x, offset.y, size.width, size.height),
     616           0 :                 Rect(0, 0, size.width, size.height));
     617             :         }
     618             :     }
     619           0 :     cairo_surface_destroy(tempXlibSurface);
     620             : }

Generated by: LCOV version 1.13