forked from mirrors/gecko-dev
Bug 1900028 - Handle CAIRO_FORMAT_A8 in _cairo_surface_to_cgimage for masking operations. r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D212354
This commit is contained in:
parent
ef05d7cc23
commit
50d383bca2
2 changed files with 214 additions and 6 deletions
124
gfx/cairo/26-quartz-surface-mask.patch
Normal file
124
gfx/cairo/26-quartz-surface-mask.patch
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
# HG changeset patch
|
||||||
|
# User Jonathan Kew <jkew@mozilla.com>
|
||||||
|
# Date 1717237382 -3600
|
||||||
|
# Sat Jun 01 11:23:02 2024 +0100
|
||||||
|
# Node ID d5f7b9fd904e04406c56899c5cac9248b122ea35
|
||||||
|
# Parent c8d3e447c892474e061c9ffd22ec1823f06ecffa
|
||||||
|
Bug 1900028 - Handle CAIRO_FORMAT_A8 in _cairo_surface_to_cgimage for masking operations.
|
||||||
|
|
||||||
|
Differential Revision: https://phabricator.services.mozilla.com/D212354
|
||||||
|
|
||||||
|
diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
|
||||||
|
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
|
||||||
|
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
|
||||||
|
@@ -684,6 +684,55 @@ CairoQuartzCreateGradientFunction (const
|
||||||
|
&gradient_callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static CGImageRef
|
||||||
|
+CairoQuartzCreateCGImageMask (cairo_format_t format,
|
||||||
|
+ unsigned int width,
|
||||||
|
+ unsigned int height,
|
||||||
|
+ unsigned int stride,
|
||||||
|
+ void *data,
|
||||||
|
+ cairo_bool_t interpolate,
|
||||||
|
+ CGDataProviderReleaseDataCallback releaseCallback,
|
||||||
|
+ void *releaseInfo)
|
||||||
|
+{
|
||||||
|
+ CGImageRef image = NULL;
|
||||||
|
+ CGDataProviderRef dataProvider = NULL;
|
||||||
|
+ int bitsPerComponent = 8, bitsPerPixel = 8;
|
||||||
|
+
|
||||||
|
+ if (format != CAIRO_FORMAT_A8)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ dataProvider = CGDataProviderCreateWithData (releaseInfo,
|
||||||
|
+ data,
|
||||||
|
+ height * stride,
|
||||||
|
+ releaseCallback);
|
||||||
|
+
|
||||||
|
+ if (unlikely (!dataProvider)) {
|
||||||
|
+ // manually release
|
||||||
|
+ if (releaseCallback)
|
||||||
|
+ releaseCallback (releaseInfo, data, height * stride);
|
||||||
|
+ goto FINISH;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cairo_quartz_float_t decode[] = {1.0, 0.0};
|
||||||
|
+ image = CGImageMaskCreate (width, height,
|
||||||
|
+ bitsPerComponent,
|
||||||
|
+ bitsPerPixel,
|
||||||
|
+ stride,
|
||||||
|
+ dataProvider,
|
||||||
|
+ decode,
|
||||||
|
+ interpolate);
|
||||||
|
+
|
||||||
|
+FINISH:
|
||||||
|
+ CGDataProviderRelease (dataProvider);
|
||||||
|
+ return image;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+DataProviderReleaseCallback (void *info, const void *data, size_t size)
|
||||||
|
+{
|
||||||
|
+ free (info);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static cairo_status_t
|
||||||
|
_cairo_surface_to_cgimage (cairo_surface_t *source,
|
||||||
|
cairo_rectangle_int_t *extents,
|
||||||
|
@@ -742,13 +791,48 @@ static cairo_status_t
|
||||||
|
&image_extra);
|
||||||
|
if (unlikely (status))
|
||||||
|
return status;
|
||||||
|
- image_surface =
|
||||||
|
- (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
|
||||||
|
- status = image_surface->base.status;
|
||||||
|
- if (status)
|
||||||
|
+
|
||||||
|
+ if (surface->format == CAIRO_FORMAT_A8) {
|
||||||
|
+ /* cairo_quartz_image_surface_create doesn't handle CAIRO_FORMAT_A8,
|
||||||
|
+ * so we create a CGImage manually here for masking operations.
|
||||||
|
+ */
|
||||||
|
+ void* image_data = _cairo_malloc_ab (surface->height, surface->stride);
|
||||||
|
+ if (unlikely (!image_data))
|
||||||
|
+ {
|
||||||
|
+ _cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
|
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* The last row of data may have less than stride bytes so make sure we
|
||||||
|
+ * only copy the minimum amount required from that row.
|
||||||
|
+ */
|
||||||
|
+ memcpy (image_data, surface->data,
|
||||||
|
+ (surface->height - 1) * surface->stride +
|
||||||
|
+ cairo_format_stride_for_width (surface->format,
|
||||||
|
+ surface->width));
|
||||||
|
+ *image_out = CairoQuartzCreateCGImageMask (surface->format,
|
||||||
|
+ surface->width,
|
||||||
|
+ surface->height,
|
||||||
|
+ surface->stride,
|
||||||
|
+ image_data,
|
||||||
|
+ TRUE,
|
||||||
|
+ DataProviderReleaseCallback,
|
||||||
|
+ image_data);
|
||||||
|
+ /* TODO: differentiate memory error and unsupported surface type */
|
||||||
|
+ if (unlikely (*image_out == NULL))
|
||||||
|
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
+
|
||||||
|
_cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
|
- else
|
||||||
|
- acquired = TRUE;
|
||||||
|
+ return status;
|
||||||
|
+ } else {
|
||||||
|
+ image_surface =
|
||||||
|
+ (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
|
||||||
|
+ status = image_surface->base.status;
|
||||||
|
+ if (status)
|
||||||
|
+ _cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
|
+ else
|
||||||
|
+ acquired = TRUE;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
*image_out = NULL;
|
||||||
|
|
@ -684,6 +684,55 @@ CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient,
|
||||||
&gradient_callbacks);
|
&gradient_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CGImageRef
|
||||||
|
CairoQuartzCreateCGImageMask (cairo_format_t format,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height,
|
||||||
|
unsigned int stride,
|
||||||
|
void *data,
|
||||||
|
cairo_bool_t interpolate,
|
||||||
|
CGDataProviderReleaseDataCallback releaseCallback,
|
||||||
|
void *releaseInfo)
|
||||||
|
{
|
||||||
|
CGImageRef image = NULL;
|
||||||
|
CGDataProviderRef dataProvider = NULL;
|
||||||
|
int bitsPerComponent = 8, bitsPerPixel = 8;
|
||||||
|
|
||||||
|
if (format != CAIRO_FORMAT_A8)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dataProvider = CGDataProviderCreateWithData (releaseInfo,
|
||||||
|
data,
|
||||||
|
height * stride,
|
||||||
|
releaseCallback);
|
||||||
|
|
||||||
|
if (unlikely (!dataProvider)) {
|
||||||
|
// manually release
|
||||||
|
if (releaseCallback)
|
||||||
|
releaseCallback (releaseInfo, data, height * stride);
|
||||||
|
goto FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_quartz_float_t decode[] = {1.0, 0.0};
|
||||||
|
image = CGImageMaskCreate (width, height,
|
||||||
|
bitsPerComponent,
|
||||||
|
bitsPerPixel,
|
||||||
|
stride,
|
||||||
|
dataProvider,
|
||||||
|
decode,
|
||||||
|
interpolate);
|
||||||
|
|
||||||
|
FINISH:
|
||||||
|
CGDataProviderRelease (dataProvider);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DataProviderReleaseCallback (void *info, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
free (info);
|
||||||
|
}
|
||||||
|
|
||||||
static cairo_status_t
|
static cairo_status_t
|
||||||
_cairo_surface_to_cgimage (cairo_surface_t *source,
|
_cairo_surface_to_cgimage (cairo_surface_t *source,
|
||||||
cairo_rectangle_int_t *extents,
|
cairo_rectangle_int_t *extents,
|
||||||
|
|
@ -742,13 +791,48 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
|
||||||
&image_extra);
|
&image_extra);
|
||||||
if (unlikely (status))
|
if (unlikely (status))
|
||||||
return status;
|
return status;
|
||||||
image_surface =
|
|
||||||
(cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
|
if (surface->format == CAIRO_FORMAT_A8) {
|
||||||
status = image_surface->base.status;
|
/* cairo_quartz_image_surface_create doesn't handle CAIRO_FORMAT_A8,
|
||||||
if (status)
|
* so we create a CGImage manually here for masking operations.
|
||||||
|
*/
|
||||||
|
void* image_data = _cairo_malloc_ab (surface->height, surface->stride);
|
||||||
|
if (unlikely (!image_data))
|
||||||
|
{
|
||||||
|
_cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The last row of data may have less than stride bytes so make sure we
|
||||||
|
* only copy the minimum amount required from that row.
|
||||||
|
*/
|
||||||
|
memcpy (image_data, surface->data,
|
||||||
|
(surface->height - 1) * surface->stride +
|
||||||
|
cairo_format_stride_for_width (surface->format,
|
||||||
|
surface->width));
|
||||||
|
*image_out = CairoQuartzCreateCGImageMask (surface->format,
|
||||||
|
surface->width,
|
||||||
|
surface->height,
|
||||||
|
surface->stride,
|
||||||
|
image_data,
|
||||||
|
TRUE,
|
||||||
|
DataProviderReleaseCallback,
|
||||||
|
image_data);
|
||||||
|
/* TODO: differentiate memory error and unsupported surface type */
|
||||||
|
if (unlikely (*image_out == NULL))
|
||||||
|
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
_cairo_surface_release_source_image (source, surface, image_extra);
|
_cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
else
|
return status;
|
||||||
acquired = TRUE;
|
} else {
|
||||||
|
image_surface =
|
||||||
|
(cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
|
||||||
|
status = image_surface->base.status;
|
||||||
|
if (status)
|
||||||
|
_cairo_surface_release_source_image (source, surface, image_extra);
|
||||||
|
else
|
||||||
|
acquired = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*image_out = NULL;
|
*image_out = NULL;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue