gfx/thebes/gfxXlibNativeRenderer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial