Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxXlibNativeRenderer.cpp
blob75883f1ba9f3a54f4c2b934a9bfedc1c79e5f2e2
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...
62 static cairo_bool_t
63 _convert_coord_to_int (double coord, int32_t *v)
65 *v = (int32_t)coord;
66 /* XXX allow some tolerance here? */
67 return *v == coord;
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)
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;
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))
100 retval = false;
101 NATIVE_DRAWING_NOTE("FALLBACK: non-integer clip");
102 goto FINISH;
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;
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;
120 rectangles[i] = rect;
123 *need_clip = true;
124 *num_rectangles = cliplist->num_rectangles;
126 FINISH:
127 cairo_rectangle_list_destroy (cliplist);
129 return retval;
132 #define MAX_STATIC_CLIP_RECTANGLES 50
135 * Try the direct path.
136 * @return True if we took the direct path
138 bool
139 gfxXlibNativeRenderer::DrawDirect(gfxContext *ctx, nsIntSize size,
140 uint32_t flags,
141 Screen *screen, Visual *visual)
143 // We need to actually borrow the context because we want to read out the
144 // clip rectangles.
145 BorrowedCairoContext borrowed(ctx->GetDrawTarget());
146 if (!borrowed.mCairo) {
147 return false;
150 bool direct = DrawCairo(borrowed.mCairo, size, flags, screen, visual);
151 borrowed.Finish();
153 return direct;
156 bool
157 gfxXlibNativeRenderer::DrawCairo(cairo_t* cr, nsIntSize size,
158 uint32_t flags,
159 Screen *screen, Visual *visual)
161 /* Check that the target surface is an xlib surface. */
162 cairo_surface_t *target = cairo_get_group_target (cr);
163 if (cairo_surface_get_type (target) != CAIRO_SURFACE_TYPE_XLIB) {
164 NATIVE_DRAWING_NOTE("FALLBACK: non-X surface");
165 return false;
168 cairo_matrix_t matrix;
169 cairo_get_matrix (cr, &matrix);
170 double device_offset_x, device_offset_y;
171 cairo_surface_get_device_offset (target, &device_offset_x, &device_offset_y);
173 /* Draw() checked that the matrix contained only a very-close-to-integer
174 translation. Here (and in several other places and thebes) device
175 offsets are assumed to be integer. */
176 NS_ASSERTION(int32_t(device_offset_x) == device_offset_x &&
177 int32_t(device_offset_y) == device_offset_y,
178 "Expected integer device offsets");
179 nsIntPoint offset(NS_lroundf(matrix.x0 + device_offset_x),
180 NS_lroundf(matrix.y0 + device_offset_y));
182 int max_rectangles = 0;
183 if (flags & DRAW_SUPPORTS_CLIP_RECT) {
184 max_rectangles = 1;
186 if (flags & DRAW_SUPPORTS_CLIP_LIST) {
187 max_rectangles = MAX_STATIC_CLIP_RECTANGLES;
190 /* The client won't draw outside the surface so consider this when
191 analysing clip rectangles. */
192 nsIntRect bounds(offset, size);
193 bounds.IntersectRect(bounds,
194 nsIntRect(0, 0,
195 cairo_xlib_surface_get_width(target),
196 cairo_xlib_surface_get_height(target)));
198 bool needs_clip = true;
199 nsIntRect rectangles[MAX_STATIC_CLIP_RECTANGLES];
200 int rect_count = 0;
202 /* Check that the clip is rectangular and aligned on unit boundaries. */
203 /* Temporarily set the matrix for _get_rectangular_clip. It's basically
204 the identity matrix, but we must adjust for the fact that our
205 offset-rect is in device coordinates. */
206 cairo_identity_matrix (cr);
207 cairo_translate (cr, -device_offset_x, -device_offset_y);
208 bool have_rectangular_clip =
209 _get_rectangular_clip (cr, bounds, &needs_clip,
210 rectangles, max_rectangles, &rect_count);
211 cairo_set_matrix (cr, &matrix);
212 if (!have_rectangular_clip)
213 return false;
215 /* Stop now if everything is clipped out */
216 if (needs_clip && rect_count == 0)
217 return true;
219 /* Check that the screen is supported.
220 Visuals belong to screens, so, if alternate visuals are not supported,
221 then alternate screens cannot be supported. */
222 bool supports_alternate_visual =
223 (flags & DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
224 bool supports_alternate_screen = supports_alternate_visual &&
225 (flags & DRAW_SUPPORTS_ALTERNATE_SCREEN);
226 if (!supports_alternate_screen &&
227 cairo_xlib_surface_get_screen (target) != screen) {
228 NATIVE_DRAWING_NOTE("FALLBACK: non-default screen");
229 return false;
232 /* Check that there is a visual */
233 Visual *target_visual = cairo_xlib_surface_get_visual (target);
234 if (!target_visual) {
235 NATIVE_DRAWING_NOTE("FALLBACK: no Visual for surface");
236 return false;
238 /* Check that the visual is supported */
239 if (!supports_alternate_visual && target_visual != visual) {
240 // Only the format of the visual is important (not the GLX properties)
241 // for Xlib or XRender drawing.
242 XRenderPictFormat *target_format =
243 cairo_xlib_surface_get_xrender_format (target);
244 if (!target_format ||
245 (target_format !=
246 XRenderFindVisualFormat (DisplayOfScreen(screen), visual))) {
247 NATIVE_DRAWING_NOTE("FALLBACK: unsupported Visual");
248 return false;
252 /* we're good to go! */
253 NATIVE_DRAWING_NOTE("TAKING FAST PATH\n");
254 cairo_surface_flush (target);
255 nsresult rv = DrawWithXlib(target,
256 offset, rectangles,
257 needs_clip ? rect_count : 0);
258 if (NS_SUCCEEDED(rv)) {
259 cairo_surface_mark_dirty (target);
260 return true;
262 return false;
265 static bool
266 VisualHasAlpha(Screen *screen, Visual *visual) {
267 // There may be some other visuals format with alpha but usually this is
268 // the only one we care about.
269 return visual->c_class == TrueColor &&
270 visual->bits_per_rgb == 8 &&
271 visual->red_mask == 0xff0000 &&
272 visual->green_mask == 0xff00 &&
273 visual->blue_mask == 0xff &&
274 gfxXlibSurface::DepthOfVisual(screen, visual) == 32;
277 // Returns whether pixel conversion between visual and format is exact (in
278 // both directions).
279 static bool
280 FormatConversionIsExact(Screen *screen, Visual *visual, XRenderPictFormat *format) {
281 if (!format ||
282 visual->c_class != TrueColor ||
283 format->type != PictTypeDirect ||
284 gfxXlibSurface::DepthOfVisual(screen, visual) != format->depth)
285 return false;
287 XRenderPictFormat *visualFormat =
288 XRenderFindVisualFormat(DisplayOfScreen(screen), visual);
290 if (visualFormat->type != PictTypeDirect )
291 return false;
293 const XRenderDirectFormat& a = visualFormat->direct;
294 const XRenderDirectFormat& b = format->direct;
295 return a.redMask == b.redMask &&
296 a.greenMask == b.greenMask &&
297 a.blueMask == b.blueMask;
300 // The 3 non-direct strategies described above.
301 // The surface format and strategy are inter-dependent.
302 enum DrawingMethod {
303 eSimple,
304 eCopyBackground,
305 eAlphaExtraction
308 static cairo_surface_t*
309 CreateTempXlibSurface (cairo_surface_t* cairoTarget,
310 DrawTarget* drawTarget,
311 nsIntSize size,
312 bool canDrawOverBackground,
313 uint32_t flags, Screen *screen, Visual *visual,
314 DrawingMethod *method)
316 NS_ASSERTION(cairoTarget || drawTarget, "Must have some type");
318 bool drawIsOpaque = (flags & gfxXlibNativeRenderer::DRAW_IS_OPAQUE) != 0;
319 bool supportsAlternateVisual =
320 (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_VISUAL) != 0;
321 bool supportsAlternateScreen = supportsAlternateVisual &&
322 (flags & gfxXlibNativeRenderer::DRAW_SUPPORTS_ALTERNATE_SCREEN);
324 cairo_surface_type_t cairoTargetType =
325 cairoTarget ? cairo_surface_get_type (cairoTarget) : (cairo_surface_type_t)0xFF;
327 Screen *target_screen = cairoTargetType == CAIRO_SURFACE_TYPE_XLIB ?
328 cairo_xlib_surface_get_screen (cairoTarget) : screen;
330 // When the background has an alpha channel, we need to draw with an alpha
331 // channel anyway, so there is no need to copy the background. If
332 // doCopyBackground is set here, we'll also need to check below that the
333 // background can copied without any loss in format conversions.
334 bool doCopyBackground = !drawIsOpaque && canDrawOverBackground &&
335 cairoTarget && cairo_surface_get_content (cairoTarget) == CAIRO_CONTENT_COLOR;
337 if (supportsAlternateScreen && screen != target_screen && drawIsOpaque) {
338 // Prefer a visual on the target screen.
339 // (If !drawIsOpaque, we'll need doCopyBackground or an alpha channel.)
340 visual = DefaultVisualOfScreen(target_screen);
341 screen = target_screen;
343 } else if (doCopyBackground || (supportsAlternateVisual && drawIsOpaque)) {
344 // Analyse the pixel formats either to check whether we can
345 // doCopyBackground or to see if we can find a better visual for
346 // opaque drawing.
347 Visual *target_visual = nullptr;
348 XRenderPictFormat *target_format = nullptr;
349 if (cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) {
350 target_visual = cairo_xlib_surface_get_visual (cairoTarget);
351 target_format = cairo_xlib_surface_get_xrender_format (cairoTarget);
352 } else if (cairoTargetType == CAIRO_SURFACE_TYPE_IMAGE || drawTarget) {
353 gfxImageFormat imageFormat =
354 drawTarget ? SurfaceFormatToImageFormat(drawTarget->GetFormat()) :
355 (gfxImageFormat)cairo_image_surface_get_format(cairoTarget);
356 target_visual = gfxXlibSurface::FindVisual(screen, imageFormat);
357 Display *dpy = DisplayOfScreen(screen);
358 if (target_visual) {
359 target_format = XRenderFindVisualFormat(dpy, target_visual);
360 } else {
361 target_format =
362 gfxXlibSurface::FindRenderFormat(dpy, imageFormat);
366 if (supportsAlternateVisual &&
367 (supportsAlternateScreen || screen == target_screen)) {
368 if (target_visual) {
369 visual = target_visual;
370 screen = target_screen;
373 // Could try harder to match formats across screens for background
374 // copying when !supportsAlternateScreen, if we cared. Preferably
375 // we'll find a visual below with an alpha channel anyway; if so, the
376 // background won't need to be copied.
378 if (doCopyBackground && visual != target_visual &&
379 !FormatConversionIsExact(screen, visual, target_format)) {
380 doCopyBackground = false;
384 if (supportsAlternateVisual && !drawIsOpaque &&
385 (screen != target_screen ||
386 !(doCopyBackground || VisualHasAlpha(screen, visual)))) {
387 // Try to find a visual with an alpha channel.
388 Screen *visualScreen =
389 supportsAlternateScreen ? target_screen : screen;
390 Visual *argbVisual =
391 gfxXlibSurface::FindVisual(visualScreen,
392 gfxImageFormat::ARGB32);
393 if (argbVisual) {
394 visual = argbVisual;
395 screen = visualScreen;
396 } else if (!doCopyBackground &&
397 gfxXlibSurface::DepthOfVisual(screen, visual) != 24) {
398 // Will need to do alpha extraction; prefer a 24-bit visual.
399 // No advantage in using the target screen.
400 Visual *rgb24Visual =
401 gfxXlibSurface::FindVisual(screen,
402 gfxImageFormat::RGB24);
403 if (rgb24Visual) {
404 visual = rgb24Visual;
409 Drawable drawable =
410 (screen == target_screen && cairoTargetType == CAIRO_SURFACE_TYPE_XLIB) ?
411 cairo_xlib_surface_get_drawable (cairoTarget) : RootWindowOfScreen(screen);
413 cairo_surface_t *surface =
414 gfxXlibSurface::CreateCairoSurface(screen, visual,
415 gfxIntSize(size.width, size.height),
416 drawable);
417 if (!surface) {
418 return nullptr;
421 if (drawIsOpaque ||
422 cairo_surface_get_content(surface) == CAIRO_CONTENT_COLOR_ALPHA) {
423 NATIVE_DRAWING_NOTE(drawIsOpaque ?
424 ", SIMPLE OPAQUE\n" : ", SIMPLE WITH ALPHA");
425 *method = eSimple;
426 } else if (doCopyBackground) {
427 NATIVE_DRAWING_NOTE(", COPY BACKGROUND\n");
428 *method = eCopyBackground;
429 } else {
430 NATIVE_DRAWING_NOTE(", SLOW ALPHA EXTRACTION\n");
431 *method = eAlphaExtraction;
434 return surface;
437 bool
438 gfxXlibNativeRenderer::DrawOntoTempSurface(cairo_surface_t *tempXlibSurface,
439 nsIntPoint offset)
441 cairo_surface_flush(tempXlibSurface);
442 /* no clipping is needed because the callback can't draw outside the native
443 surface anyway */
444 nsresult rv = DrawWithXlib(tempXlibSurface, offset, nullptr, 0);
445 cairo_surface_mark_dirty(tempXlibSurface);
446 return NS_SUCCEEDED(rv);
449 static already_AddRefed<gfxImageSurface>
450 CopyXlibSurfaceToImage(cairo_surface_t *tempXlibSurface,
451 gfxIntSize size,
452 gfxImageFormat format)
454 nsRefPtr<gfxImageSurface> result = new gfxImageSurface(size, format);
456 cairo_t* copyCtx = cairo_create(result->CairoSurface());
457 cairo_set_source_surface(copyCtx, tempXlibSurface, 0, 0);
458 cairo_set_operator(copyCtx, CAIRO_OPERATOR_SOURCE);
459 cairo_paint(copyCtx);
460 cairo_destroy(copyCtx);
462 return result.forget();
465 void
466 gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
467 uint32_t flags, Screen *screen, Visual *visual)
469 gfxMatrix matrix = ctx->CurrentMatrix();
471 // We can only draw direct or onto a copied background if pixels align and
472 // native drawing is compatible with the current operator. (The matrix is
473 // actually also pixel-exact for flips and right-angle rotations, which
474 // would permit copying the background but not drawing direct.)
475 bool matrixIsIntegerTranslation = !matrix.HasNonIntegerTranslation();
476 bool canDrawOverBackground = matrixIsIntegerTranslation &&
477 ctx->CurrentOperator() == gfxContext::OPERATOR_OVER;
479 // The padding of 0.5 for non-pixel-exact transformations used here is
480 // the same as what _cairo_pattern_analyze_filter uses.
481 const gfxFloat filterRadius = 0.5;
482 gfxRect affectedRect(0.0, 0.0, size.width, size.height);
483 if (!matrixIsIntegerTranslation) {
484 // The filter footprint means that the affected rectangle is a
485 // little larger than the drawingRect;
486 affectedRect.Inflate(filterRadius);
488 NATIVE_DRAWING_NOTE("FALLBACK: matrix not integer translation");
489 } else if (!canDrawOverBackground) {
490 NATIVE_DRAWING_NOTE("FALLBACK: unsupported operator");
493 // Clipping to the region affected by drawing allows us to consider only
494 // the portions of the clip region that will be affected by drawing.
495 gfxRect clipExtents;
497 gfxContextAutoSaveRestore autoSR(ctx);
498 ctx->Clip(affectedRect);
500 clipExtents = ctx->GetClipExtents();
501 if (clipExtents.IsEmpty())
502 return; // nothing to do
504 if (canDrawOverBackground &&
505 DrawDirect(ctx, size, flags, screen, visual))
506 return;
509 nsIntRect drawingRect(nsIntPoint(0, 0), size);
510 // Drawing need only be performed within the clip extents
511 // (and padding for the filter).
512 if (!matrixIsIntegerTranslation) {
513 // The source surface may need to be a little larger than the clip
514 // extents due to the filter footprint.
515 clipExtents.Inflate(filterRadius);
517 clipExtents.RoundOut();
519 nsIntRect intExtents(int32_t(clipExtents.X()),
520 int32_t(clipExtents.Y()),
521 int32_t(clipExtents.Width()),
522 int32_t(clipExtents.Height()));
523 drawingRect.IntersectRect(drawingRect, intExtents);
525 gfxPoint offset(drawingRect.x, drawingRect.y);
527 DrawingMethod method;
528 DrawTarget* drawTarget = ctx->GetDrawTarget();
529 Matrix dtTransform = drawTarget->GetTransform();
530 gfxPoint deviceTranslation = gfxPoint(dtTransform._31, dtTransform._32);
531 cairo_surface_t* cairoTarget = static_cast<cairo_surface_t*>
532 (drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_SURFACE));
534 cairo_surface_t* tempXlibSurface =
535 CreateTempXlibSurface(cairoTarget, drawTarget, size,
536 canDrawOverBackground, flags, screen, visual,
537 &method);
538 if (!tempXlibSurface)
539 return;
541 bool drawIsOpaque = (flags & DRAW_IS_OPAQUE) != 0;
542 if (!drawIsOpaque) {
543 cairo_t* tmpCtx = cairo_create(tempXlibSurface);
544 if (method == eCopyBackground) {
545 NS_ASSERTION(cairoTarget, "eCopyBackground only used when there's a cairoTarget");
546 cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
547 gfxPoint pt = -(offset + deviceTranslation);
548 cairo_set_source_surface(tmpCtx, cairoTarget, pt.x, pt.y);
549 // The copy from the tempXlibSurface to the target context should
550 // use operator SOURCE, but that would need a mask to bound the
551 // operation. Here we only copy opaque backgrounds so operator
552 // OVER will behave like SOURCE masked by the surface.
553 NS_ASSERTION(cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR,
554 "Don't copy background with a transparent surface");
555 } else {
556 cairo_set_operator(tmpCtx, CAIRO_OPERATOR_CLEAR);
558 cairo_paint(tmpCtx);
559 cairo_destroy(tmpCtx);
562 if (!DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft())) {
563 cairo_surface_destroy(tempXlibSurface);
564 return;
567 SurfaceFormat moz2DFormat =
568 cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
569 SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
570 if (method != eAlphaExtraction) {
571 if (drawTarget) {
572 NativeSurface native;
573 native.mFormat = moz2DFormat;
574 native.mType = NativeSurfaceType::CAIRO_SURFACE;
575 native.mSurface = tempXlibSurface;
576 native.mSize = ToIntSize(size);
577 RefPtr<SourceSurface> sourceSurface =
578 drawTarget->CreateSourceSurfaceFromNativeSurface(native);
579 if (sourceSurface) {
580 drawTarget->DrawSurface(sourceSurface,
581 Rect(offset.x, offset.y, size.width, size.height),
582 Rect(0, 0, size.width, size.height));
584 } else {
585 nsRefPtr<gfxASurface> tmpSurf = gfxASurface::Wrap(tempXlibSurface);
586 ctx->SetSource(tmpSurf, offset);
587 ctx->Paint();
589 cairo_surface_destroy(tempXlibSurface);
590 return;
593 nsRefPtr<gfxImageSurface> blackImage =
594 CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormat::ARGB32);
596 cairo_t* tmpCtx = cairo_create(tempXlibSurface);
597 cairo_set_source_rgba(tmpCtx, 1.0, 1.0, 1.0, 1.0);
598 cairo_set_operator(tmpCtx, CAIRO_OPERATOR_SOURCE);
599 cairo_paint(tmpCtx);
600 cairo_destroy(tmpCtx);
601 DrawOntoTempSurface(tempXlibSurface, -drawingRect.TopLeft());
602 nsRefPtr<gfxImageSurface> whiteImage =
603 CopyXlibSurfaceToImage(tempXlibSurface, size, gfxImageFormat::RGB24);
605 if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
606 whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
607 if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage)) {
608 cairo_surface_destroy(tempXlibSurface);
609 return;
612 gfxASurface* paintSurface = blackImage;
613 if (drawTarget) {
614 NativeSurface native;
615 native.mFormat = moz2DFormat;
616 native.mType = NativeSurfaceType::CAIRO_SURFACE;
617 native.mSurface = paintSurface->CairoSurface();
618 native.mSize = ToIntSize(size);
619 RefPtr<SourceSurface> sourceSurface =
620 drawTarget->CreateSourceSurfaceFromNativeSurface(native);
621 if (sourceSurface) {
622 drawTarget->DrawSurface(sourceSurface,
623 Rect(offset.x, offset.y, size.width, size.height),
624 Rect(0, 0, size.width, size.height));
626 } else {
627 ctx->SetSource(paintSurface, offset);
628 ctx->Paint();
631 cairo_surface_destroy(tempXlibSurface);