gfx/cairo/quartz-cglayers.patch

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 changeset:   42959:e1964291f8ff
     2 user:        Robert O'Callahan <robert@ocallahan.org>
     3 date:        Tue Jun 01 11:33:23 2010 +1200
     4 summary:     Bug 568189. Implement CGLayer-backed cairo-quartz surfaces. r=jrmuizel
     6 diff --git a/gfx/cairo/cairo/src/cairo-quartz-private.h b/gfx/cairo/cairo/src/cairo-quartz-private.h
     7 --- a/gfx/cairo/cairo/src/cairo-quartz-private.h
     8 +++ b/gfx/cairo/cairo/src/cairo-quartz-private.h
     9 @@ -57,16 +57,21 @@ typedef struct cairo_quartz_surface {
    11      /**
    12       * If non-null, this is a CGImage representing the contents of the surface.
    13       * We clear this out before any painting into the surface, so that we
    14       * don't force a copy to be created.
    15       */
    16      CGImageRef bitmapContextImage;
    18 +    /**
    19 +     * If non-null, this is the CGLayer for the surface.
    20 +     */
    21 +    CGLayerRef cgLayer;
    22 +
    23      cairo_rectangle_int_t extents;
    24  } cairo_quartz_surface_t;
    26  typedef struct cairo_quartz_image_surface {
    27      cairo_surface_t base;
    29      cairo_rectangle_int_t extents;
    31 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
    32 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
    33 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
    34 @@ -1110,18 +1110,17 @@ CreateRepeatingRadialGradientFunction (c
    35  static void
    36  DataProviderReleaseCallback (void *info, const void *data, size_t size)
    37  {
    38      cairo_surface_t *surface = (cairo_surface_t *) info;
    39      cairo_surface_destroy (surface);
    40  }
    42  static cairo_status_t
    43 -_cairo_surface_to_cgimage (cairo_surface_t *target,
    44 -			   cairo_surface_t *source,
    45 +_cairo_surface_to_cgimage (cairo_surface_t *source,
    46  			   CGImageRef *image_out)
    47  {
    48      cairo_status_t status = CAIRO_STATUS_SUCCESS;
    49      cairo_surface_type_t stype = cairo_surface_get_type (source);
    50      cairo_image_surface_t *isurf;
    51      CGImageRef image;
    52      void *image_extra;
    54 @@ -1267,17 +1266,17 @@ _cairo_quartz_cairo_repeating_surface_pa
    55  	return CAIRO_INT_STATUS_UNSUPPORTED;
    57      spattern = (cairo_surface_pattern_t *) apattern;
    58      pat_surf = spattern->surface;
    60      is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
    61      assert (is_bounded);
    63 -    status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
    64 +    status = _cairo_surface_to_cgimage (pat_surf, &image);
    65      if (status)
    66  	return status;
    67      if (image == NULL)
    68  	return CAIRO_INT_STATUS_NOTHING_TO_DO;
    70      info = malloc(sizeof(SurfacePatternDrawInfo));
    71      if (!info)
    72  	return CAIRO_STATUS_NO_MEMORY;
    73 @@ -1339,33 +1338,39 @@ _cairo_quartz_cairo_repeating_surface_pa
    74  }
    76  typedef enum {
    77      DO_SOLID,
    78      DO_SHADING,
    79      DO_PATTERN,
    80      DO_IMAGE,
    81      DO_TILED_IMAGE,
    82 +    DO_LAYER,
    83      DO_UNSUPPORTED,
    84      DO_NOTHING
    85  } cairo_quartz_action_t;
    87  /* State used during a drawing operation. */
    88  typedef struct {
    89      CGContextRef context;
    90      cairo_quartz_action_t action;
    92 -    // Used with DO_SHADING, DO_IMAGE and DO_TILED_IMAGE
    93 +    // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
    94      CGAffineTransform transform;
    96      // Used with DO_IMAGE and DO_TILED_IMAGE
    97      CGImageRef image;
    98      cairo_surface_t *imageSurface;
    99 +
   100 +    // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
   101      CGRect imageRect;
   103 +    // Used with DO_LAYER
   104 +    CGLayerRef layer;
   105 +
   106      // Used with DO_SHADING
   107      CGShadingRef shading;
   109      // Used with DO_PATTERN
   110      CGPatternRef pattern;
   111  } cairo_quartz_drawing_state_t;
   113  static void
   114 @@ -1423,17 +1428,17 @@ _cairo_quartz_setup_fallback_source (cai
   115  	_cairo_pattern_transform (&pattern.base,
   116  				  &fallback->device_transform_inverse);
   117  	status = _cairo_surface_paint (fallback,
   118  				       CAIRO_OPERATOR_SOURCE,
   119  				       &pattern.base, NULL);
   120      }
   121  #endif
   123 -    status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
   124 +    status = _cairo_surface_to_cgimage (fallback, &img);
   125      if (status) {
   126          state->action = DO_UNSUPPORTED;
   127  	return;
   128      }
   129      if (img == NULL) {
   130          state->action = DO_NOTHING;
   131  	return;
   132      }
   133 @@ -1624,16 +1629,17 @@ _cairo_quartz_setup_state (cairo_quartz_
   134  {
   135      CGContextRef context = surface->cgContext;
   136      cairo_quartz_drawing_state_t state;
   137      cairo_status_t status;
   139      state.context = context;
   140      state.image = NULL;
   141      state.imageSurface = NULL;
   142 +    state.layer = NULL;
   143      state.shading = NULL;
   144      state.pattern = NULL;
   146      _cairo_quartz_surface_will_change (surface);
   148      // Save before we change the pattern, colorspace, etc. so that
   149      // we can restore and make sure that quartz releases our
   150      // pattern (which may be stack allocated)
   151 @@ -1689,33 +1695,43 @@ _cairo_quartz_setup_state (cairo_quartz_
   152  	CGImageRef img;
   153  	cairo_matrix_t m = spat->base.matrix;
   154  	cairo_rectangle_int_t extents;
   155  	CGAffineTransform xform;
   156  	CGRect srcRect;
   157  	cairo_fixed_t fw, fh;
   158  	cairo_bool_t is_bounded;
   160 -	status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
   161 +        cairo_matrix_invert(&m);
   162 +        _cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform);
   163 +
   164 +        if (cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
   165 +            cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf;
   166 +            if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) {
   167 +         	state.imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height);
   168 +                state.layer = quartz_surf->cgLayer;
   169 +                state.action = DO_LAYER;
   170 +                return state;
   171 +            }
   172 +        }
   173 +
   174 +	status = _cairo_surface_to_cgimage (pat_surf, &img);
   175          if (status) {
   176              state.action = DO_UNSUPPORTED;
   177  	    return state;
   178          }
   179          if (img == NULL) {
   180              state.action = DO_NOTHING;
   181  	    return state;
   182          }
   184  	CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
   186  	state.image = img;
   188 -	cairo_matrix_invert(&m);
   189 -	_cairo_quartz_cairo_matrix_to_quartz (&m, &state.transform);
   190 -
   191  	is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
   192  	assert (is_bounded);
   194  	if (source->extend == CAIRO_EXTEND_NONE) {
   195  	    state.imageRect = CGRectMake (0, 0, extents.width, extents.height);
   196  	    state.action = DO_IMAGE;
   197  	    return state;
   198  	}
   199 @@ -1820,33 +1836,48 @@ _cairo_quartz_teardown_state (cairo_quar
   201      CGContextRestoreGState(state->context);
   202  }
   205  static void
   206  _cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op)
   207  {
   208 -    assert (state && state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE));
   209 +    assert (state &&
   210 +            ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) ||
   211 +             (state->layer && state->action == DO_LAYER)));
   213      CGContextConcatCTM (state->context, state->transform);
   214      CGContextTranslateCTM (state->context, 0, state->imageRect.size.height);
   215      CGContextScaleCTM (state->context, 1, -1);
   217 -    if (state->action == DO_IMAGE) {
   218 -	CGContextDrawImage (state->context, state->imageRect, state->image);
   219 +    if (state->action == DO_TILED_IMAGE) {
   220 +	CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image);
   221 +	/* no need to worry about unbounded operators, since tiled images
   222 +	   fill the entire clip region */
   223 +    } else {
   224 +        if (state->action == DO_LAYER) {
   225 +            /* Note that according to Apple docs it's completely legal
   226 +             * to draw a CGLayer to any CGContext, even one it wasn't
   227 +             * created for.
   228 +             */
   229 +            CGContextDrawLayerAtPoint (state->context, state->imageRect.origin,
   230 +                                       state->layer);
   231 +        } else {
   232 +            CGContextDrawImage (state->context, state->imageRect, state->image);
   233 +        }
   234 +
   235  	if (!_cairo_operator_bounded_by_source (op)) {
   236  	    CGContextBeginPath (state->context);
   237  	    CGContextAddRect (state->context, state->imageRect);
   238  	    CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context));
   239  	    CGContextSetRGBFillColor (state->context, 0, 0, 0, 0);
   240  	    CGContextEOFillPath (state->context);
   241  	}
   242 -    } else
   243 -	CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image);
   244 +    }
   245  }
   248  /*
   249   * get source/dest image implementation
   250   */
   252  /* Read the image from the surface's front buffer */
   253 @@ -1971,95 +2002,153 @@ _cairo_quartz_surface_finish (void *abst
   254  	surface->imageSurfaceEquiv = NULL;
   255      }
   257      if (surface->imageData) {
   258  	free (surface->imageData);
   259  	surface->imageData = NULL;
   260      }
   262 +    if (surface->cgLayer) {
   263 +        CGLayerRelease (surface->cgLayer);
   264 +    }
   265 +
   266      return CAIRO_STATUS_SUCCESS;
   267  }
   269  static cairo_status_t
   270 -_cairo_quartz_surface_acquire_source_image (void *abstract_surface,
   271 -					     cairo_image_surface_t **image_out,
   272 -					     void **image_extra)
   273 +_cairo_quartz_surface_acquire_image (void *abstract_surface,
   274 +                                     cairo_image_surface_t **image_out,
   275 +                                     void **image_extra)
   276  {
   277      cairo_int_status_t status;
   278      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   280 -    //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
   281 +    *image_extra = NULL;
   282 +
   283 +    /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */
   285      status = _cairo_quartz_get_image (surface, image_out);
   286 +
   287 +    if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) {
   288 +        /* copy the layer into a Quartz bitmap context so we can get the data */
   289 +        cairo_surface_t *tmp =
   290 +            cairo_quartz_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
   291 +                                         surface->extents.width,
   292 +                                         surface->extents.height);
   293 +        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp;
   294 +
   295 +        /* if surface creation failed, we won't have a Quartz surface here */
   296 +        if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ &&
   297 +            tmp_surface->imageSurfaceEquiv) {
   298 +            CGContextSaveGState (tmp_surface->cgContext);
   299 +            CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height);
   300 +            CGContextScaleCTM (tmp_surface->cgContext, 1, -1);
   301 +            /* Note that according to Apple docs it's completely legal
   302 +             * to draw a CGLayer to any CGContext, even one it wasn't
   303 +             * created for.
   304 +             */
   305 +            CGContextDrawLayerAtPoint (tmp_surface->cgContext,
   306 +                                       CGPointMake (0.0, 0.0),
   307 +                                       surface->cgLayer);
   308 +            CGContextRestoreGState (tmp_surface->cgContext);
   309 +
   310 +            *image_out = (cairo_image_surface_t*)
   311 +                cairo_surface_reference(tmp_surface->imageSurfaceEquiv);
   312 +            *image_extra = tmp;
   313 +        } else {
   314 +            cairo_surface_destroy (tmp);
   315 +        }
   316 +    }
   317 +
   318      if (status)
   319  	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
   321 -    *image_extra = NULL;
   322 -
   323      return CAIRO_STATUS_SUCCESS;
   324  }
   326  static void
   327  _cairo_quartz_surface_release_source_image (void *abstract_surface,
   328  					     cairo_image_surface_t *image,
   329  					     void *image_extra)
   330  {
   331      cairo_surface_destroy ((cairo_surface_t *) image);
   332 +
   333 +    if (image_extra) {
   334 +        cairo_surface_destroy ((cairo_surface_t *) image_extra);
   335 +    }
   336  }
   339  static cairo_status_t
   340  _cairo_quartz_surface_acquire_dest_image (void *abstract_surface,
   341  					  cairo_rectangle_int_t *interest_rect,
   342  					  cairo_image_surface_t **image_out,
   343  					  cairo_rectangle_int_t *image_rect,
   344  					  void **image_extra)
   345  {
   346      cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   347 -    cairo_int_status_t status;
   349      ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface));
   351 -    _cairo_quartz_surface_will_change (surface);
   352 -
   353 -    status = _cairo_quartz_get_image (surface, image_out);
   354 -    if (status)
   355 -	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
   356 -
   357      *image_rect = surface->extents;
   358      *image_extra = NULL;
   360 -    return CAIRO_STATUS_SUCCESS;
   361 +    _cairo_quartz_surface_will_change (surface);
   362 +
   363 +    return _cairo_quartz_surface_acquire_image (abstract_surface,
   364 +        image_out, image_extra);
   365  }
   367  static void
   368  _cairo_quartz_surface_release_dest_image (void *abstract_surface,
   369  					  cairo_rectangle_int_t *interest_rect,
   370  					  cairo_image_surface_t *image,
   371  					  cairo_rectangle_int_t *image_rect,
   372  					  void *image_extra)
   373  {
   374 -    //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   375 -
   376 -    //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
   377 +    /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */
   379      cairo_surface_destroy ((cairo_surface_t *) image);
   380 +
   381 +    if (image_extra) {
   382 +        /* we need to write the data from the temp surface back to the layer */
   383 +        cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   384 +        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra;
   385 +        CGImageRef img;
   386 +        cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img);
   387 +        if (status) {
   388 +            cairo_surface_destroy (&tmp_surface->base);
   389 +            return;
   390 +        }
   391 +
   392 +        CGContextSaveGState (surface->cgContext);
   393 +        CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height);
   394 +        CGContextScaleCTM (surface->cgContext, 1, -1);
   395 +        CGContextDrawImage (surface->cgContext,
   396 +                            CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height),
   397 +                            img);
   398 +        CGContextRestoreGState (surface->cgContext);
   399 +
   400 +        cairo_surface_destroy (&tmp_surface->base);
   401 +    }
   402  }
   404  static cairo_surface_t *
   405  _cairo_quartz_surface_create_similar (void *abstract_surface,
   406  				       cairo_content_t content,
   407  				       int width,
   408  				       int height)
   409  {
   410 -    /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/
   411 -
   412 +    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
   413      cairo_format_t format;
   415 +    if (surface->cgLayer)
   416 +        return cairo_quartz_surface_create_cg_layer (abstract_surface, width, height);
   417 +
   418      if (content == CAIRO_CONTENT_COLOR_ALPHA)
   419  	format = CAIRO_FORMAT_ARGB32;
   420      else if (content == CAIRO_CONTENT_COLOR)
   421  	format = CAIRO_FORMAT_RGB24;
   422      else if (content == CAIRO_CONTENT_ALPHA)
   423  	format = CAIRO_FORMAT_A8;
   424      else
   425  	return NULL;
   426 @@ -2113,17 +2202,17 @@ _cairo_quartz_surface_clone_similar (voi
   427  		_cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
   428  						       qsurf->extents.width, qsurf->extents.height);
   429  	    *clone_offset_x = 0;
   430  	    *clone_offset_y = 0;
   431  	    return CAIRO_STATUS_SUCCESS;
   432  	}
   433      }
   435 -    status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image);
   436 +    status = _cairo_surface_to_cgimage (src, &quartz_image);
   437      if (status)
   438  	return CAIRO_INT_STATUS_UNSUPPORTED;
   440      new_format = CAIRO_FORMAT_ARGB32;  /* assumed */
   441      if (_cairo_surface_is_image (src)) {
   442  	new_format = ((cairo_image_surface_t *) src)->format;
   443      }
   445 @@ -2194,17 +2283,18 @@ _cairo_quartz_surface_paint (void *abstr
   446      if (state.action == DO_SOLID || state.action == DO_PATTERN) {
   447  	CGContextFillRect (state.context, CGRectMake(surface->extents.x,
   448  						     surface->extents.y,
   449  						     surface->extents.width,
   450  						     surface->extents.height));
   451      } else if (state.action == DO_SHADING) {
   452  	CGContextConcatCTM (state.context, state.transform);
   453  	CGContextDrawShading (state.context, state.shading);
   454 -    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
   455 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   456 +               state.action == DO_LAYER) {
   457  	_cairo_quartz_draw_image (&state, op);
   458      } else if (state.action != DO_NOTHING) {
   459  	rv = CAIRO_INT_STATUS_UNSUPPORTED;
   460      }
   462      _cairo_quartz_teardown_state (&state);
   464      ND((stderr, "-- paint\n"));
   465 @@ -2291,17 +2381,18 @@ _cairo_quartz_surface_fill (void *abstra
   466  	// with the shading
   467  	if (fill_rule == CAIRO_FILL_RULE_WINDING)
   468  	    CGContextClip (state.context);
   469  	else
   470              CGContextEOClip (state.context);
   472  	CGContextConcatCTM (state.context, state.transform);
   473  	CGContextDrawShading (state.context, state.shading);
   474 -    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
   475 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   476 +               state.action == DO_LAYER) {
   477  	if (fill_rule == CAIRO_FILL_RULE_WINDING)
   478  	    CGContextClip (state.context);
   479  	else
   480  	    CGContextEOClip (state.context);
   482  	_cairo_quartz_draw_image (&state, op);
   483      } else if (state.action != DO_NOTHING) {
   484  	rv = CAIRO_INT_STATUS_UNSUPPORTED;
   485 @@ -2416,17 +2507,18 @@ _cairo_quartz_surface_stroke (void *abst
   486      if (rv)
   487  	goto BAIL;
   489      if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
   490  	path_for_unbounded = CGContextCopyPathPtr (state.context);
   492      if (state.action == DO_SOLID || state.action == DO_PATTERN) {
   493  	CGContextStrokePath (state.context);
   494 -    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
   495 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   496 +               state.action == DO_LAYER) {
   497  	CGContextReplacePathWithStrokedPath (state.context);
   498  	CGContextClip (state.context);
   500  	CGContextSetCTM (state.context, origCTM);
   501  	_cairo_quartz_draw_image (&state, op);
   502      } else if (state.action == DO_SHADING) {
   503  	CGContextReplacePathWithStrokedPath (state.context);
   504  	CGContextClip (state.context);
   505 @@ -2511,17 +2603,18 @@ _cairo_quartz_surface_show_glyphs (void 
   506                                                   &glyph_extents, NULL);
   507          state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents);
   508      } else {
   509          state = _cairo_quartz_setup_state (surface, source, op, NULL);
   510      }
   512      if (state.action == DO_SOLID || state.action == DO_PATTERN) {
   513  	CGContextSetTextDrawingMode (state.context, kCGTextFill);
   514 -    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE || state.action == DO_SHADING) {
   515 +    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   516 +               state.action == DO_SHADING || state.action == DO_LAYER) {
   517  	CGContextSetTextDrawingMode (state.context, kCGTextClip);
   518  	isClipping = TRUE;
   519      } else {
   520  	if (state.action != DO_NOTHING)
   521  	    rv = CAIRO_INT_STATUS_UNSUPPORTED;
   522  	goto BAIL;
   523      }
   525 @@ -2622,17 +2715,18 @@ _cairo_quartz_surface_show_glyphs (void 
   527      CGContextShowGlyphsWithAdvances (state.context,
   528  				     cg_glyphs,
   529  				     cg_advances,
   530  				     num_glyphs);
   532      CGContextSetCTM (state.context, ctm);
   534 -    if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE) {
   535 +    if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
   536 +        state.action == DO_LAYER) {
   537  	_cairo_quartz_draw_image (&state, op);
   538      } else if (state.action == DO_SHADING) {
   539  	CGContextConcatCTM (state.context, state.transform);
   540  	CGContextDrawShading (state.context, state.shading);
   541      }
   543  BAIL:
   544      if (didForceFontSmoothing)
   545 @@ -2679,17 +2773,17 @@ _cairo_quartz_surface_mask_with_surface 
   546  					 cairo_clip_t *clip)
   547  {
   548      CGRect rect;
   549      CGImageRef img;
   550      cairo_surface_t *pat_surf = mask->surface;
   551      cairo_status_t status = CAIRO_STATUS_SUCCESS;
   552      CGAffineTransform ctm, mask_matrix;
   554 -    status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
   555 +    status = _cairo_surface_to_cgimage (pat_surf, &img);
   556      if (status)
   557  	return status;
   558      if (img == NULL) {
   559  	if (!_cairo_operator_bounded_by_mask (op))
   560  	    CGContextClearRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
   561  	return CAIRO_STATUS_SUCCESS;
   562      }
   564 @@ -2869,17 +2963,17 @@ _cairo_quartz_surface_clipper_intersect_
   565  }
   567  // XXXtodo implement show_page; need to figure out how to handle begin/end
   569  static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
   570      CAIRO_SURFACE_TYPE_QUARTZ,
   571      _cairo_quartz_surface_create_similar,
   572      _cairo_quartz_surface_finish,
   573 -    _cairo_quartz_surface_acquire_source_image,
   574 +    _cairo_quartz_surface_acquire_image,
   575      _cairo_quartz_surface_release_source_image,
   576      _cairo_quartz_surface_acquire_dest_image,
   577      _cairo_quartz_surface_release_dest_image,
   578      _cairo_quartz_surface_clone_similar,
   579      NULL, /* composite */
   580      NULL, /* fill_rectangles */
   581      NULL, /* composite_trapezoids */
   582      NULL, /* create_span_renderer */
   583 @@ -2950,16 +3044,17 @@ _cairo_quartz_surface_create_internal (C
   584      CGContextSaveGState (cgContext);
   586      surface->cgContext = cgContext;
   587      surface->cgContextBaseCTM = CGContextGetCTM (cgContext);
   589      surface->imageData = NULL;
   590      surface->imageSurfaceEquiv = NULL;
   591      surface->bitmapContextImage = NULL;
   592 +    surface->cgLayer = NULL;
   594      return surface;
   595  }
   597  /**
   598   * cairo_quartz_surface_create_for_cg_context
   599   * @cgContext: the existing CGContext for which to create the surface
   600   * @width: width of the surface, in pixels
   601 @@ -3002,16 +3097,88 @@ cairo_quartz_surface_create_for_cg_conte
   602  	// create_internal will have set an error
   603  	return (cairo_surface_t*) surf;
   604      }
   606      return (cairo_surface_t *) surf;
   607  }
   609  /**
   610 + * cairo_quartz_cglayer_surface_create_similar
   611 + * @surface: The returned surface can be efficiently drawn into this
   612 + * destination surface (if tiling is not used)."
   613 + * @width: width of the surface, in pixels
   614 + * @height: height of the surface, in pixels
   615 + *
   616 + * Creates a Quartz surface backed by a CGLayer, if the given surface
   617 + * is a Quartz surface; the CGLayer is created to match the surface's
   618 + * Quartz context. Otherwise just calls cairo_surface_create_similar
   619 + * with CAIRO_CONTENT_COLOR_ALPHA.
   620 + * The returned surface can be efficiently blitted to the given surface,
   621 + * but tiling and 'extend' modes other than NONE are not so efficient.
   622 + *
   623 + * Return value: the newly created surface.
   624 + *
   625 + * Since: 1.10
   626 + **/
   627 +cairo_surface_t *
   628 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
   629 +                                      unsigned int width,
   630 +                                      unsigned int height)
   631 +{
   632 +    cairo_quartz_surface_t *surf;
   633 +    CGLayerRef layer;
   634 +    CGContextRef ctx;
   635 +    CGContextRef cgContext;
   636 +
   637 +    cgContext = cairo_quartz_surface_get_cg_context (surface);
   638 +    if (!cgContext)
   639 +        return cairo_surface_create_similar (surface, CAIRO_CONTENT_COLOR_ALPHA,
   640 +                                             width, height);
   641 +
   642 +    if (!_cairo_quartz_verify_surface_size(width, height))
   643 +        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
   644 +
   645 +    /* If we pass zero width or height into CGLayerCreateWithContext below,
   646 +     * it will fail.
   647 +     */
   648 +    if (width == 0 || height == 0) {
   649 +        return (cairo_surface_t*)
   650 +            _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
   651 +                                                   width, height);
   652 +    }
   653 +
   654 +    layer = CGLayerCreateWithContext (cgContext,
   655 +                                      CGSizeMake (width, height),
   656 +                                      NULL);
   657 +    if (!layer)
   658 +      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
   659 +
   660 +    ctx = CGLayerGetContext (layer);
   661 +    /* Flip it when we draw into it, so that when we finally composite it
   662 +     * to a flipped target, the directions match and Quartz will optimize
   663 +     * the composition properly
   664 +     */
   665 +    CGContextTranslateCTM (ctx, 0, height);
   666 +    CGContextScaleCTM (ctx, 1, -1);
   667 +
   668 +    CGContextRetain (ctx);
   669 +    surf = _cairo_quartz_surface_create_internal (ctx, CAIRO_CONTENT_COLOR_ALPHA,
   670 +              width, height);
   671 +    if (surf->base.status) {
   672 +        CGLayerRelease (layer);
   673 +        // create_internal will have set an error
   674 +        return (cairo_surface_t*) surf;
   675 +    }
   676 +    surf->cgLayer = layer;
   677 +
   678 +    return (cairo_surface_t *) surf;
   679 +}
   680 +
   681 +/**
   682   * cairo_quartz_surface_create
   683   * @format: format of pixels in the surface to create
   684   * @width: width of the surface, in pixels
   685   * @height: height of the surface, in pixels
   686   *
   687   * Creates a Quartz surface backed by a CGBitmap.  The surface is
   688   * created using the Device RGB (or Device Gray, for A8) color space.
   689   * All Cairo operations, including those that require software
   690 diff --git a/gfx/cairo/cairo/src/cairo-quartz.h b/gfx/cairo/cairo/src/cairo-quartz.h
   691 --- a/gfx/cairo/cairo/src/cairo-quartz.h
   692 +++ b/gfx/cairo/cairo/src/cairo-quartz.h
   693 @@ -45,16 +45,21 @@
   694  CAIRO_BEGIN_DECLS
   696  cairo_public cairo_surface_t *
   697  cairo_quartz_surface_create (cairo_format_t format,
   698                               unsigned int width,
   699                               unsigned int height);
   701  cairo_public cairo_surface_t *
   702 +cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
   703 +                                      unsigned int width,
   704 +                                      unsigned int height);
   705 +
   706 +cairo_public cairo_surface_t *
   707  cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
   708                                              unsigned int width,
   709                                              unsigned int height);
   711  cairo_public CGContextRef
   712  cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
   714  cairo_public CGContextRef

mercurial