26-quartz-surface-mask.patch (3953B)
1 # HG changeset patch 2 # User Jonathan Kew <jkew@mozilla.com> 3 # Date 1717237382 -3600 4 # Sat Jun 01 11:23:02 2024 +0100 5 # Node ID d5f7b9fd904e04406c56899c5cac9248b122ea35 6 # Parent c8d3e447c892474e061c9ffd22ec1823f06ecffa 7 Bug 1900028 - Handle CAIRO_FORMAT_A8 in _cairo_surface_to_cgimage for masking operations. 8 9 Differential Revision: https://phabricator.services.mozilla.com/D212354 10 11 diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c 12 --- a/gfx/cairo/cairo/src/cairo-quartz-surface.c 13 +++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c 14 @@ -684,6 +684,55 @@ CairoQuartzCreateGradientFunction (const 15 &gradient_callbacks); 16 } 17 18 +static CGImageRef 19 +CairoQuartzCreateCGImageMask (cairo_format_t format, 20 + unsigned int width, 21 + unsigned int height, 22 + unsigned int stride, 23 + void *data, 24 + cairo_bool_t interpolate, 25 + CGDataProviderReleaseDataCallback releaseCallback, 26 + void *releaseInfo) 27 +{ 28 + CGImageRef image = NULL; 29 + CGDataProviderRef dataProvider = NULL; 30 + int bitsPerComponent = 8, bitsPerPixel = 8; 31 + 32 + if (format != CAIRO_FORMAT_A8) 33 + return NULL; 34 + 35 + dataProvider = CGDataProviderCreateWithData (releaseInfo, 36 + data, 37 + height * stride, 38 + releaseCallback); 39 + 40 + if (unlikely (!dataProvider)) { 41 + // manually release 42 + if (releaseCallback) 43 + releaseCallback (releaseInfo, data, height * stride); 44 + goto FINISH; 45 + } 46 + 47 + cairo_quartz_float_t decode[] = {1.0, 0.0}; 48 + image = CGImageMaskCreate (width, height, 49 + bitsPerComponent, 50 + bitsPerPixel, 51 + stride, 52 + dataProvider, 53 + decode, 54 + interpolate); 55 + 56 +FINISH: 57 + CGDataProviderRelease (dataProvider); 58 + return image; 59 +} 60 + 61 +static void 62 +DataProviderReleaseCallback (void *info, const void *data, size_t size) 63 +{ 64 + free (info); 65 +} 66 + 67 static cairo_status_t 68 _cairo_surface_to_cgimage (cairo_surface_t *source, 69 cairo_rectangle_int_t *extents, 70 @@ -742,13 +791,48 @@ static cairo_status_t 71 &image_extra); 72 if (unlikely (status)) 73 return status; 74 - image_surface = 75 - (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base); 76 - status = image_surface->base.status; 77 - if (status) 78 + 79 + if (surface->format == CAIRO_FORMAT_A8) { 80 + /* cairo_quartz_image_surface_create doesn't handle CAIRO_FORMAT_A8, 81 + * so we create a CGImage manually here for masking operations. 82 + */ 83 + void* image_data = _cairo_malloc_ab (surface->height, surface->stride); 84 + if (unlikely (!image_data)) 85 + { 86 + _cairo_surface_release_source_image (source, surface, image_extra); 87 + return _cairo_error (CAIRO_STATUS_NO_MEMORY); 88 + } 89 + 90 + /* The last row of data may have less than stride bytes so make sure we 91 + * only copy the minimum amount required from that row. 92 + */ 93 + memcpy (image_data, surface->data, 94 + (surface->height - 1) * surface->stride + 95 + cairo_format_stride_for_width (surface->format, 96 + surface->width)); 97 + *image_out = CairoQuartzCreateCGImageMask (surface->format, 98 + surface->width, 99 + surface->height, 100 + surface->stride, 101 + image_data, 102 + TRUE, 103 + DataProviderReleaseCallback, 104 + image_data); 105 + /* TODO: differentiate memory error and unsupported surface type */ 106 + if (unlikely (*image_out == NULL)) 107 + status = CAIRO_INT_STATUS_UNSUPPORTED; 108 + 109 _cairo_surface_release_source_image (source, surface, image_extra); 110 - else 111 - acquired = TRUE; 112 + return status; 113 + } else { 114 + image_surface = 115 + (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base); 116 + status = image_surface->base.status; 117 + if (status) 118 + _cairo_surface_release_source_image (source, surface, image_extra); 119 + else 120 + acquired = TRUE; 121 + } 122 } 123 124 *image_out = NULL;