diff options
Diffstat (limited to 'src')
30 files changed, 697 insertions, 880 deletions
diff --git a/src/cairo-array.c b/src/cairo-array.c index db7b6de7a..1c91b7c73 100644 --- a/src/cairo-array.c +++ b/src/cairo-array.c @@ -143,7 +143,6 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements) /** * _cairo_array_index: * @array: a #cairo_array_t - * Returns: A pointer to the object stored at @index. * * If the resulting value is assigned to a pointer to an object of the same * element_size as initially passed to _cairo_array_init() then that @@ -161,6 +160,8 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements) * for (i = 0; i < _cairo_array_num_elements (&array); i++) * ... use values[i] here ... * </programlisting></informalexample> + * + * Returns: A pointer to the object stored at @index. **/ void * _cairo_array_index (cairo_array_t *array, unsigned int index) @@ -187,7 +188,6 @@ _cairo_array_index (cairo_array_t *array, unsigned int index) /** * _cairo_array_index_const: * @array: a #cairo_array_t - * Returns: A pointer to the object stored at @index. * * If the resulting value is assigned to a pointer to an object of the same * element_size as initially passed to _cairo_array_init() then that @@ -205,6 +205,8 @@ _cairo_array_index (cairo_array_t *array, unsigned int index) * for (i = 0; i < _cairo_array_num_elements (&array); i++) * ... read values[i] here ... * </programlisting></informalexample> + * + * Returns: A pointer to the object stored at @index. **/ const void * _cairo_array_index_const (const cairo_array_t *array, unsigned int index) @@ -330,9 +332,10 @@ _cairo_array_allocate (cairo_array_t *array, /** * _cairo_array_num_elements: * @array: a #cairo_array_t - * Returns: The number of elements stored in @array. * * This space was left intentionally blank, but gtk-doc filled it. + * + * Returns: The number of elements stored in @array. **/ unsigned int _cairo_array_num_elements (const cairo_array_t *array) @@ -343,10 +346,11 @@ _cairo_array_num_elements (const cairo_array_t *array) /** * _cairo_array_size: * @array: a #cairo_array_t - * Returns: The number of elements for which there is currently space - * allocated in @array. * * This space was left intentionally blank, but gtk-doc filled it. + * + * Returns: The number of elements for which there is currently space + * allocated in @array. **/ unsigned int _cairo_array_size (const cairo_array_t *array) diff --git a/src/cairo-cache.c b/src/cairo-cache.c index be1285a20..afdca984e 100644 --- a/src/cairo-cache.c +++ b/src/cairo-cache.c @@ -56,7 +56,6 @@ _cairo_cache_entry_is_non_zero (const void *entry) * @keys_equal: a function to return %TRUE if two keys are equal * @entry_destroy: destroy notifier for cache entries * @max_size: the maximum size for this cache - * Returns: the newly created #cairo_cache_t * * Creates a new cache using the keys_equal() function to determine * the equality of entries. @@ -84,6 +83,8 @@ _cairo_cache_entry_is_non_zero (const void *entry) * _cairo_cache_freeze() and _cairo_cache_thaw() calls can be * used to establish a window during which no automatic removal of * entries will occur. + * + * Returns: the newly created #cairo_cache_t **/ cairo_status_t _cairo_cache_init (cairo_cache_t *cache, diff --git a/src/cairo-dwrite.h b/src/cairo-dwrite.h index 630fcf280..b1ff718a0 100644 --- a/src/cairo-dwrite.h +++ b/src/cairo-dwrite.h @@ -51,7 +51,7 @@ cairo_public IDWriteRenderingParams * cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face); cairo_public void -cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *param); +cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params); cairo_public DWRITE_MEASURING_MODE cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face); diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c index 361882ae5..33ee617b8 100644 --- a/src/cairo-font-options.c +++ b/src/cairo-font-options.c @@ -105,6 +105,41 @@ _cairo_font_options_init_copy (cairo_font_options_t *options, } } +cairo_bool_t +_cairo_font_options_compare (const cairo_font_options_t *a, + const cairo_font_options_t *b) +{ + if (a->antialias != b->antialias || + a->subpixel_order != b->subpixel_order || + a->lcd_filter != b->lcd_filter || + a->hint_style != b->hint_style || + a->hint_metrics != b->hint_metrics || + a->round_glyph_positions != b->round_glyph_positions || + a->color_mode != b->color_mode || + a->palette_index != b->palette_index || + a->custom_palette_size != b->custom_palette_size) + { + return FALSE; + } + + if (a->variations && b->variations && strcmp (a->variations, b->variations) != 0) + return FALSE; + else if (a->variations != b->variations) + return FALSE; + + if (a->custom_palette && b->custom_palette && + memcmp (a->custom_palette, b->custom_palette, sizeof (cairo_palette_color_t) * a->custom_palette_size) != 0) + { + return FALSE; + } + else if (a->custom_palette != b->custom_palette) + { + return FALSE; + } + + return TRUE; +} + /** * cairo_font_options_create: * @@ -662,7 +697,7 @@ cairo_font_options_get_variations (cairo_font_options_t *options) /** * cairo_font_options_set_color_mode: * @options: a #cairo_font_options_t - * @font_color: the new color mode + * @color_mode: the new color mode * * Sets the color mode for the font options object. This controls * whether color fonts are to be rendered in color or as outlines. diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 75d6f8c16..22a6a622b 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -3408,7 +3408,6 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, int load_flags = scaled_font->ft_options.load_flags; cairo_bool_t vertical_layout = FALSE; cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_bool_t scaled_glyph_loaded = FALSE; cairo_ft_glyph_private_t *glyph_priv; int color_flag = 0; @@ -3528,46 +3527,20 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { cairo_path_fixed_t *path = NULL; /* hide compiler warning */ - if (scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) { - path = _cairo_path_fixed_create (); - if (!path) { - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - goto FAIL; - } - - status = _cairo_recording_surface_get_path (scaled_glyph->recording_surface, path); - if (unlikely (status)) { - _cairo_path_fixed_destroy (path); - goto FAIL; - } - - } else { - /* - * A kludge -- the above code will trash the outline, - * so reload it. This will probably never occur though - */ - if ((info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) != 0) { - scaled_glyph_loaded = FALSE; - load_flags |= FT_LOAD_NO_BITMAP; - } - - if (!scaled_glyph_loaded) { - status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, - scaled_glyph, - face, - load_flags, - FALSE, - vertical_layout); - if (unlikely (status)) - goto FAIL; - } + /* Load non-color glyph */ + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags, + FALSE, + vertical_layout); + if (unlikely (status)) + goto FAIL; - if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { - status = _cairo_ft_face_decompose_glyph_outline (face, &path); - } else { - status = CAIRO_INT_STATUS_UNSUPPORTED; - } - } + if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + status = _cairo_ft_face_decompose_glyph_outline (face, &path); + else + status = CAIRO_INT_STATUS_UNSUPPORTED; if (unlikely (status)) goto FAIL; diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 0f4fd541a..8a253468d 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1748,7 +1748,7 @@ void _cairo_gstate_set_font_options (cairo_gstate_t *gstate, const cairo_font_options_t *options) { - if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0) + if (_cairo_font_options_compare (options, &gstate->font_options)) return; _cairo_gstate_unset_scaled_font (gstate); diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c index cb49adcbe..e8fd097ae 100644 --- a/src/cairo-matrix.c +++ b/src/cairo-matrix.c @@ -373,15 +373,10 @@ _cairo_matrix_multiply (cairo_matrix_t *r, * the returned vector is as follows: * * <programlisting> - * dx2 = dx1 * a + dy1 * c; - * dy2 = dx1 * b + dy1 * d; + * dx_new = xx * dx + xy * dy; + * dy_new = yx * dx + yy * dy; * </programlisting> * - * Affine transformations are position invariant, so the same vector - * always transforms to the same vector. If (@x1,@y1) transforms - * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to - * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. - * * Since: 1.0 **/ void diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index d16ed2836..2c0ba31f8 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -3439,9 +3439,10 @@ use_bilinear(double x, double y, double t) /** * _cairo_pattern_analyze_filter: * @pattern: surface pattern - * Returns: the optimized #cairo_filter_t to use with @pattern. * * Possibly optimize the filter to a simpler value depending on transformation + * + * Returns: the optimized #cairo_filter_t to use with @pattern. **/ cairo_filter_t _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern) diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 772828eb8..2b1bf72e4 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -2556,7 +2556,7 @@ _cairo_pdf_surface_finish (void *abstract_surface) cairo_pdf_surface_t *surface = abstract_surface; long long offset; cairo_pdf_resource_t catalog; - cairo_status_t status, status2; + cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; int size, i; cairo_pdf_jbig2_global_t *global; char *label; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index abc9407ee..381b4cf75 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -148,7 +148,7 @@ static char *ctime_r(const time_t *timep, char *buf) * ury]" that specifies the bounding box (in PS coordinates) of the * EPS graphics. The parameters are: lower left x, lower left y, upper * right x, upper right y. Normally the bbox data is identical to the - * %%%BoundingBox data in the EPS file. + * \%\%\%BoundingBox data in the EPS file. * **/ diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c index 30d92d6be..d09f5b5bc 100644 --- a/src/cairo-quartz-image-surface.c +++ b/src/cairo-quartz-image-surface.c @@ -49,12 +49,6 @@ #define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE))) #define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT))) -static void -DataProviderReleaseCallback (void *image_info, const void *data, size_t size) -{ - free (image_info); -} - static cairo_surface_t * _cairo_quartz_image_surface_create_similar (void *asurface, cairo_content_t content, @@ -87,8 +81,9 @@ _cairo_quartz_image_surface_finish (void *asurface) { cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; - CGImageRelease (surface->image); - cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface); + CGContextRelease (surface->cgContext); + if (surface->imageSurface) + cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface); return CAIRO_STATUS_SUCCESS; } @@ -134,47 +129,6 @@ _cairo_quartz_image_surface_get_extents (void *asurface, return TRUE; } -/* we assume some drawing happened to the image buffer; make sure it's - * represented in the CGImage on flush() - */ - -static cairo_status_t -_cairo_quartz_image_surface_flush (void *asurface, - unsigned flags) -{ - cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; - CGImageRef oldImage = surface->image; - CGImageRef newImage = NULL; - void *image_data; - const unsigned int size = surface->imageSurface->height * surface->imageSurface->stride; - if (flags) - return CAIRO_STATUS_SUCCESS; - - /* XXX only flush if the image has been modified. */ - - image_data = _cairo_malloc_ab ( surface->imageSurface->height, - surface->imageSurface->stride); - if (unlikely (!image_data)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - - memcpy (image_data, surface->imageSurface->data, - surface->imageSurface->height * surface->imageSurface->stride); - newImage = CairoQuartzCreateCGImage (surface->imageSurface->format, - surface->imageSurface->width, - surface->imageSurface->height, - surface->imageSurface->stride, - image_data, - TRUE, - NULL, - DataProviderReleaseCallback, - image_data); - - surface->image = newImage; - CGImageRelease (oldImage); - - return CAIRO_STATUS_SUCCESS; -} - static cairo_int_status_t _cairo_quartz_image_surface_paint (void *abstract_surface, cairo_operator_t op, @@ -275,7 +229,7 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { _cairo_quartz_image_surface_get_extents, NULL, /* get_font_options */ - _cairo_quartz_image_surface_flush, + NULL, /*surface_flush */ NULL, /* mark_dirty_rectangle */ _cairo_quartz_image_surface_paint, @@ -290,12 +244,9 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { * cairo_quartz_image_surface_create: * @image_surface: a cairo image surface to wrap with a quartz image surface * - * Creates a Quartz surface backed by a CGImageRef that references the + * Creates a Quartz surface backed by a CGBitmapContext that references the * given image surface. The resulting surface can be rendered quickly - * when used as a source when rendering to a #cairo_quartz_surface. If - * the data in the image surface is ever updated, cairo_surface_flush() - * must be called on the #cairo_quartz_image_surface to ensure that the - * CGImageRef refers to the updated data. + * when used as a source when rendering to a #cairo_quartz_surface. * * Return value: the newly created surface. * @@ -305,13 +256,11 @@ cairo_surface_t * cairo_quartz_image_surface_create (cairo_surface_t *surface) { cairo_quartz_image_surface_t *qisurf; - - CGImageRef image; - cairo_image_surface_t *image_surface; int width, height, stride; cairo_format_t format; - void *image_data; + CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host; + CGColorSpaceRef colorspace; if (surface->status) return surface; @@ -338,54 +287,100 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface) if (qisurf == NULL) return SURFACE_ERROR_NO_MEMORY; - memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t)); - - image_data = _cairo_malloc_ab (height, stride); - if (unlikely (!image_data)) { - free(qisurf); - return SURFACE_ERROR_NO_MEMORY; - } - - memcpy (image_data, image_surface->data, height * stride); - image = CairoQuartzCreateCGImage (format, - width, height, - stride, - image_data, - TRUE, - NULL, - DataProviderReleaseCallback, - image_data); - - if (!image) { - free (qisurf); - return SURFACE_ERROR_NO_MEMORY; - } - _cairo_surface_init (&qisurf->base, &cairo_quartz_image_surface_backend, NULL, /* device */ _cairo_content_from_format (format), FALSE); /* is_vector */ + if (_cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface)) { + CGContextRef context = cairo_quartz_surface_get_cg_context(surface); + colorspace = _cairo_quartz_create_color_space (context); + } + else { + colorspace = CGDisplayCopyColorSpace (CGMainDisplayID ()); + } + + bitinfo |= format == CAIRO_FORMAT_ARGB32 ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + qisurf->width = width; qisurf->height = height; - qisurf->image = image; + qisurf->cgContext = CGBitmapContextCreate (image_surface->data, width, height, 8, image_surface->stride, + colorspace, bitinfo); qisurf->imageSurface = (cairo_image_surface_t*) cairo_surface_reference(surface); + CGColorSpaceRelease (colorspace); return &qisurf->base; } +/** + * cairo_quartz_image_surface_get_image: + * @surface: a #cairo_surface_t + * + * Returns a #cairo_surface_t image surface that refers to the same bits + * as the image of the quartz surface. + * + * Return value: a #cairo_surface_t (owned by the quartz #cairo_surface_t), + * or %NULL if the quartz surface is not an image surface. + * + * Since: 1.6 + */ cairo_surface_t * -cairo_quartz_image_surface_get_image (cairo_surface_t *asurface) +cairo_quartz_image_surface_get_image (cairo_surface_t *surface) { - cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface; + cairo_quartz_image_surface_t *qsurface = (cairo_quartz_image_surface_t*) surface; /* Throw an error for a non-quartz surface */ - if (! _cairo_surface_is_quartz (asurface)) { + if (! _cairo_surface_is_quartz (surface)) { return SURFACE_ERROR_TYPE_MISMATCH; } - return (cairo_surface_t*) surface->imageSurface; + return (cairo_surface_t*) qsurface->imageSurface; +} + +/* + * _cairo_quartz_image_surface_get_cg_context: + * @surface: the Cairo Quartz surface + * + * Returns the CGContextRef that the given Quartz surface is backed + * by. + * + * A call to cairo_surface_flush() is required before using the + * CGContextRef to ensure that all pending drawing operations are + * finished and to restore any temporary modification cairo has made + * to its state. A call to cairo_surface_mark_dirty() is required + * after the state or the content of the CGContextRef has been + * modified. + * + * Return value: the CGContextRef for the given surface. + * + **/ +CGContextRef +_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface) +{ + if (surface && _cairo_surface_is_quartz_image (surface)) { + cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface; + return quartz->cgContext; + } else + return NULL; +} + +/* + * _cairo_surface_is_quartz_image: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_quartz_surface_t + * + * Return value: True if the surface is an quartz surface + **/ +cairo_bool_t +_cairo_surface_is_quartz_image (const cairo_surface_t *surface) { + return surface->backend == &cairo_quartz_image_surface_backend; +} + +cairo_bool_t +_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface) { + return surface->width == 0 || surface->height == 0; } diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h index f142f8471..bdfdf8c2b 100644 --- a/src/cairo-quartz-private.h +++ b/src/cairo-quartz-private.h @@ -81,8 +81,7 @@ typedef struct cairo_quartz_image_surface { cairo_surface_t base; int width, height; - - CGImageRef image; + CGContextRef cgContext; cairo_image_surface_t *imageSurface; } cairo_quartz_image_surface_t; @@ -92,16 +91,15 @@ _cairo_quartz_verify_surface_size(int width, int height); cairo_private cairo_bool_t _cairo_surface_is_quartz (const cairo_surface_t *surface); -cairo_private CGImageRef -CairoQuartzCreateCGImage (cairo_format_t format, - unsigned int width, - unsigned int height, - unsigned int stride, - void *data, - cairo_bool_t interpolate, - CGColorSpaceRef colorSpaceOverride, - CGDataProviderReleaseDataCallback releaseCallback, - void *releaseInfo); +cairo_private cairo_bool_t +_cairo_surface_is_quartz_image (const cairo_surface_t *surface); +cairo_private cairo_bool_t +_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface); + +cairo_private CGColorSpaceRef +_cairo_quartz_create_color_space (CGContextRef context); +cairo_private CGContextRef +_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface); cairo_private CGFontRef _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont); @@ -112,6 +110,9 @@ _cairo_quartz_font_face_create_for_ctfont (CTFontRef ctFont); cairo_private void _cairo_quartz_set_antialiasing (CGContextRef context, cairo_antialias_t antialias); +cairo_status_t _cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest); +cairo_private void _cairo_quartz_image_to_png (CGImageRef, const char *dest); + #else # error Cairo was not compiled with support for the quartz backend diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c index dbb6aa46f..d8a8065d0 100644 --- a/src/cairo-quartz-surface.c +++ b/src/cairo-quartz-surface.c @@ -37,6 +37,7 @@ #include "cairoint.h" #include "cairo-quartz-private.h" +#include "cairo-quartz-image.h" #include "cairo-composite-rectangles-private.h" #include "cairo-compositor-private.h" @@ -55,6 +56,7 @@ #endif #include <limits.h> +#include <assert.h> #undef QUARTZ_DEBUG @@ -64,13 +66,30 @@ #define ND(_x) do {} while(0) #endif -#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0) #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 #define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation #else #define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal #endif +static inline cairo_bool_t +_is_quartz_surface (cairo_surface_t *surface) { + return _cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface); +} + +static inline cairo_bool_t +_cairo_quartz_surface_is_zero (cairo_quartz_surface_t* surface) { + return surface->extents.width == 0 || surface->extents.height == 0; +} + +static inline cairo_bool_t +_cairo_quartz_is_zero_surface (cairo_surface_t* surface) { + assert (_is_quartz_surface (surface)); + if (_cairo_surface_is_quartz (surface)) + return (_cairo_quartz_surface_is_zero ((cairo_quartz_surface_t*) surface)); + else + return (_cairo_quartz_image_surface_is_zero ((cairo_quartz_image_surface_t*) surface)); +} /** * SECTION:cairo-quartz @@ -94,6 +113,20 @@ /* * macOS Private functions */ +typedef enum { + kCGContextTypeUnknown, + kCGContextTypePDF, + kCGContextTypePostScript, + kCGContextTypeWindow, + kCGContextTypeBitmap, + kCGContextTypeGL, + kCGContextTypeDisplayList, + kCGContextTypeKSeparation, + kCGContextTypeIOSurface, + kCGContextTypeCount +} CGContextType; + + static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL; static void @@ -108,20 +141,15 @@ quartz_ensure_symbols() } } -#ifdef QUARTZ_DEBUG -static void quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest); -static void quartz_image_to_png (CGImageRef, const char *dest); -#endif - typedef struct { cairo_surface_t base; CGImageRef image; } cairo_quartz_snapshot_t; -static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface); -static cairo_status_t _cairo_quartz_snapshot_finish (void* surface); -static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface); +static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_surface_t *surface); +static cairo_status_t _cairo_quartz_snapshot_finish (void *surface); +static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface); static const cairo_surface_backend_t cairo_quartz_snapshot_backend = { CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT, @@ -134,102 +162,72 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, unsigned int width, unsigned int height); -CGImageRef -CairoQuartzCreateCGImage (cairo_format_t format, - unsigned int width, - unsigned int height, - unsigned int stride, - void *data, - cairo_bool_t interpolate, - CGColorSpaceRef colorSpaceOverride, - CGDataProviderReleaseDataCallback releaseCallback, - void *releaseInfo) +CGColorSpaceRef +_cairo_quartz_create_color_space (CGContextRef context) { - CGImageRef image = NULL; - CGDataProviderRef dataProvider = NULL; - CGColorSpaceRef colorSpace = colorSpaceOverride; - CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host; - int bitsPerComponent, bitsPerPixel; - - switch (format) { - case CAIRO_FORMAT_ARGB32: - if (colorSpace == NULL) - colorSpace = CGColorSpaceCreateDeviceRGB (); - bitinfo |= kCGImageAlphaPremultipliedFirst; - bitsPerComponent = 8; - bitsPerPixel = 32; - break; - - case CAIRO_FORMAT_RGB24: - if (colorSpace == NULL) - colorSpace = CGColorSpaceCreateDeviceRGB (); - bitinfo |= kCGImageAlphaNoneSkipFirst; - bitsPerComponent = 8; - bitsPerPixel = 32; - break; - - case CAIRO_FORMAT_A8: - bitsPerComponent = 8; - bitsPerPixel = 8; - break; + CGColorSpaceRef color_space = NULL; + CGContextType cgtype = kCGContextTypeUnknown; - case CAIRO_FORMAT_A1: -#ifdef WORDS_BIGENDIAN - bitsPerComponent = 1; - bitsPerPixel = 1; - break; -#endif - - case CAIRO_FORMAT_RGB30: - case CAIRO_FORMAT_RGB16_565: - case CAIRO_FORMAT_RGB96F: - case CAIRO_FORMAT_RGBA128F: - case CAIRO_FORMAT_INVALID: - default: - return NULL; - } - - dataProvider = CGDataProviderCreateWithData (releaseInfo, - data, - height * stride, - releaseCallback); - - if (unlikely (!dataProvider)) { - // manually release - if (releaseCallback) - releaseCallback (releaseInfo, data, height * stride); - goto FINISH; + if (context) + { + if (CGBitmapContextGetBitsPerPixel (context) < 24) + return 0; + + quartz_ensure_symbols(); + cgtype = CGContextGetTypePtr (context); + switch (cgtype) + { + case kCGContextTypeUnknown: + break; + case kCGContextTypePDF: + color_space = CGColorSpaceCreateDeviceRGB (); + break; + case kCGContextTypePostScript: + case kCGContextTypeWindow: + break; + case kCGContextTypeBitmap: + color_space = CGBitmapContextGetColorSpace (context); + color_space = CGColorSpaceRetain (color_space); + break; + case kCGContextTypeGL: + case kCGContextTypeDisplayList: + case kCGContextTypeKSeparation: + case kCGContextTypeIOSurface: + case kCGContextTypeCount: + default: + break; + } + if (color_space) + return color_space; } + if (!color_space) + color_space = CGDisplayCopyColorSpace (CGMainDisplayID ()); - if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) { - cairo_quartz_float_t decode[] = {1.0, 0.0}; - image = CGImageMaskCreate (width, height, - bitsPerComponent, - bitsPerPixel, - stride, - dataProvider, - decode, - interpolate); - } else - image = CGImageCreate (width, height, - bitsPerComponent, - bitsPerPixel, - stride, - colorSpace, - bitinfo, - dataProvider, - NULL, - interpolate, - kCGRenderingIntentDefault); - -FINISH: + if (!color_space) + color_space = CGColorSpaceCreateDeviceRGB (); - CGDataProviderRelease (dataProvider); + return color_space; +} - if (colorSpace != colorSpaceOverride) - CGColorSpaceRelease (colorSpace); +static CGColorRef +_cairo_quartz_create_cgcolor (CGColorSpaceRef cs, CGFloat red, CGFloat green, + CGFloat blue, CGFloat alpha) +{ + CGFloat colors[4] = { red, green, blue, alpha }; + CGColorRef cgc; + if (!CGColorSpaceRetain(cs)) + { + cs = _cairo_quartz_create_color_space (NULL); + } + cgc = CGColorCreate (cs, colors); + CGColorSpaceRelease (cs); + return cgc; +} - return image; +static CGColorRef +_cairo_quartz_black (CGColorSpaceRef cs) +{ + return _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 1.0); } static inline cairo_bool_t @@ -241,7 +239,7 @@ _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc) quartz_ensure_symbols (); if (likely (CGContextGetTypePtr)) { /* 4 is the type value of a bitmap context */ - return CGContextGetTypePtr (cgc) == 4; + return CGContextGetTypePtr (cgc) == kCGContextTypeBitmap; } /* This will cause a (harmless) warning to be printed if called on a non-bitmap context */ @@ -682,12 +680,6 @@ CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient, &gradient_callbacks); } -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, @@ -697,25 +689,19 @@ _cairo_surface_to_cgimage (cairo_surface_t *source, CGImageRef *image_out) { cairo_status_t status; - cairo_image_surface_t *image_surface; - void *image_data, *image_extra; + cairo_quartz_image_surface_t *image_surface; + void *image_extra; cairo_bool_t acquired = FALSE; - if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) { - cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source; - *image_out = CGImageRetain (surface->image); - return CAIRO_STATUS_SUCCESS; - } - - if (_cairo_surface_is_quartz (source)) { - cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source; - if (IS_EMPTY (surface)) { + if (_is_quartz_surface (source)) { + CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source); + if (_cairo_quartz_is_zero_surface (source)) { *image_out = NULL; return CAIRO_INT_STATUS_NOTHING_TO_DO; } - if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) { - *image_out = _cairo_quartz_surface_snapshot_get_image (surface); + if (_cairo_quartz_is_cgcontext_bitmap_context (cgContext)) { + *image_out = _cairo_quartz_surface_snapshot_get_image (source); return CAIRO_STATUS_SUCCESS; } @@ -724,80 +710,60 @@ _cairo_surface_to_cgimage (cairo_surface_t *source, } if (source->type == CAIRO_SURFACE_TYPE_RECORDING) { - image_surface = (cairo_image_surface_t *) - cairo_image_surface_create (format, extents->width, extents->height); - if (unlikely (image_surface->base.status)) { - status = image_surface->base.status; - cairo_surface_destroy (&image_surface->base); + cairo_image_surface_t *surface = + (cairo_image_surface_t*)cairo_image_surface_create (format, extents->width, + extents->height); + if (unlikely (surface->base.status)) { + status = surface->base.status; + cairo_surface_destroy (&surface->base); return status; } status = _cairo_recording_surface_replay_with_clip (source, matrix, - &image_surface->base, + &surface->base, NULL, FALSE); if (unlikely (status)) { - cairo_surface_destroy (&image_surface->base); + cairo_surface_destroy (&surface->base); return status; } + image_surface = + (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base); cairo_matrix_init_identity (matrix); } else { - status = _cairo_surface_acquire_source_image (source, &image_surface, + cairo_image_surface_t *surface; + status = _cairo_surface_acquire_source_image (source, &surface, &image_extra); if (unlikely (status)) return status; - acquired = TRUE; - } - - if (image_surface->width == 0 || image_surface->height == 0) { - *image_out = NULL; - if (acquired) - _cairo_surface_release_source_image (source, image_surface, image_extra); + 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 - cairo_surface_destroy (&image_surface->base); - - return status; + acquired = TRUE; } - image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride); - if (unlikely (!image_data)) - { - if (acquired) - _cairo_surface_release_source_image (source, image_surface, image_extra); - else - cairo_surface_destroy (&image_surface->base); - - return _cairo_error (CAIRO_STATUS_NO_MEMORY); + *image_out = NULL; + if (image_surface->width > 0 && image_surface->height > 0) { + *image_out = _cairo_quartz_surface_snapshot_get_image (&image_surface->base); + status = CAIRO_STATUS_SUCCESS; } - // 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, image_surface->data, - (image_surface->height - 1) * image_surface->stride + - cairo_format_stride_for_width (image_surface->format, - image_surface->width)); - *image_out = CairoQuartzCreateCGImage (image_surface->format, - image_surface->width, - image_surface->height, - image_surface->stride, - image_data, - TRUE, - NULL, - DataProviderReleaseCallback, - image_data); + if (acquired) { + _cairo_surface_release_source_image (source, image_surface->imageSurface, image_extra); + image_surface->imageSurface = NULL; + } + cairo_surface_destroy (&image_surface->base); /* TODO: differentiate memory error and unsupported surface type */ if (unlikely (*image_out == NULL)) status = CAIRO_INT_STATUS_UNSUPPORTED; - if (acquired) - _cairo_surface_release_source_image (source, image_surface, image_extra); - else - cairo_surface_destroy (&image_surface->base); - return status; } @@ -993,6 +959,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state, CGColorSpaceRef patternSpace; CGPatternRef cgpat = NULL; cairo_int_status_t status; + CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (state->cgDrawContext)); _cairo_surface_get_extents (&surface->base, &extents); @@ -1048,7 +1015,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state, -state->clipRect.origin.y); } - CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); + CGContextSetFillColorWithColor (state->cgDrawContext, black); state->rect = CGRectMake (0, 0, pattern_extents.width, pattern_extents.height); state->action = DO_IMAGE; @@ -1087,6 +1054,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state, CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0)); CGPatternRelease (cgpat); + CGColorRelease (black); state->action = DO_DIRECT; return CAIRO_STATUS_SUCCESS; @@ -1126,7 +1094,7 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state, if (unlikely (gradFunc == NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; - rgb = CGColorSpaceCreateDeviceRGB (); + rgb = _cairo_quartz_create_color_space (NULL); if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { state->shading = CGShadingCreateAxial (rgb, @@ -1197,9 +1165,11 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state, state->filter = _cairo_quartz_filter_to_quartz (source->filter); if (op == CAIRO_OPERATOR_CLEAR) { - CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1); + CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (surface->cgContext)); + CGContextSetFillColorWithColor (state->cgDrawContext, black); state->action = DO_DIRECT; + CGColorRelease (black); return CAIRO_STATUS_SUCCESS; } @@ -1236,18 +1206,17 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state, if (source->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; + CGColorRef color = _cairo_quartz_create_cgcolor (_cairo_quartz_create_color_space (state->cgDrawContext), + solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + - CGContextSetRGBStrokeColor (state->cgDrawContext, - solid->color.red, - solid->color.green, - solid->color.blue, - solid->color.alpha); - CGContextSetRGBFillColor (state->cgDrawContext, - solid->color.red, - solid->color.green, - solid->color.blue, - solid->color.alpha); + CGContextSetStrokeColorWithColor (state->cgDrawContext, color); + CGContextSetFillColorWithColor (state->cgDrawContext, color); + CGColorRelease (color); state->action = DO_DIRECT; return CAIRO_STATUS_SUCCESS; } @@ -1301,6 +1270,9 @@ static inline void _cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state, cairo_operator_t op) { + CGColorSpaceRef cs = _cairo_quartz_create_color_space (state->cgDrawContext); + CGColorRef transparent = _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 0.0); //releases cs + if (! (op == CAIRO_OPERATOR_SOURCE && state->cgDrawContext == state->cgMaskContext)) return; @@ -1315,8 +1287,9 @@ _cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state, CGContextAddRect (state->cgDrawContext, state->clipRect); - CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 0); + CGContextSetFillColorWithColor (state->cgDrawContext, transparent); CGContextEOFillPath (state->cgDrawContext); + CGColorRelease (transparent); } @@ -1367,7 +1340,7 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface, unsigned char *imageData; cairo_format_t format; - if (IS_EMPTY (surface)) + if (_cairo_quartz_is_zero_surface (&surface->base)) return (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); if (! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) @@ -1377,8 +1350,9 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface, bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext); // let's hope they don't add YUV under us - colorspace = CGBitmapContextGetColorSpace (surface->cgContext); + colorspace = _cairo_quartz_create_color_space (surface->cgContext); color_comps = CGColorSpaceGetNumberOfComponents (colorspace); + CGColorSpaceRelease (colorspace); /* XXX TODO: We can handle many more data formats by * converting to pixman_format_t */ @@ -1439,7 +1413,7 @@ _cairo_quartz_surface_finish (void *abstract_surface) ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext)); - if (IS_EMPTY (surface)) + if (_cairo_quartz_is_zero_surface (&surface->base)) return CAIRO_STATUS_SUCCESS; /* Restore our saved gstate that we use to reset clipping */ @@ -2086,7 +2060,7 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); - if (IS_EMPTY (surface)) + if (_cairo_quartz_is_zero_surface (&surface->base)) return CAIRO_STATUS_SUCCESS; if (path == NULL) { @@ -2184,7 +2158,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext, surface->extents.height = height; surface->virtual_extents = surface->extents; - if (IS_EMPTY (surface)) { + if (_cairo_quartz_is_zero_surface (&surface->base)) { surface->cgContext = NULL; surface->cgContextBaseCTM = CGAffineTransformIdentity; surface->base.is_clear = TRUE; @@ -2234,10 +2208,9 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, unsigned int width, unsigned int height) { - cairo_quartz_surface_t *surf; - - surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA, - width, height); + cairo_quartz_surface_t *surf = + _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA, + width, height); if (likely (!surf->base.status)) CGContextRetain (cgContext); @@ -2250,8 +2223,14 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, * @width: width of the surface, in pixels * @height: height of the surface, in pixels * - * Creates a Quartz surface backed by a CGBitmap. The surface is - * created using the Device RGB (or Device Gray, for A8) color space. + * Creates a Quartz surface backed by a CGBitmapContext using the main + * display's colorspace to avoid an expensive colorspace transform + * done serially on the CPU. This may produce slightly different + * colors from what's intended. Programs for which color management is + * important should create their own CGBitmapContext with a + * device-independent color space; most will expect Cairo to draw in + * sRGB and would use CGColorSpaceCreateWithName(kCGColorSpaceSRGB). + * * All Cairo operations, including those that require software * rendering, will succeed on this surface. * @@ -2283,7 +2262,7 @@ cairo_quartz_surface_create (cairo_format_t format, if (format == CAIRO_FORMAT_ARGB32 || format == CAIRO_FORMAT_RGB24) { - cgColorspace = CGColorSpaceCreateDeviceRGB (); + cgColorspace = _cairo_quartz_create_color_space (NULL); bitinfo = kCGBitmapByteOrder32Host; if (format == CAIRO_FORMAT_ARGB32) bitinfo |= kCGImageAlphaPremultipliedFirst; @@ -2372,8 +2351,14 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) if (surface && _cairo_surface_is_quartz (surface)) { cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface; return quartz->cgContext; - } else - return NULL; + } + + if (surface && _cairo_surface_is_quartz_image (surface)) { + cairo_quartz_image_surface_t *quartz = (cairo_quartz_image_surface_t *) surface; + return quartz->cgContext; + } + + return NULL; } /** @@ -2391,12 +2376,15 @@ _cairo_surface_is_quartz (const cairo_surface_t *surface) } cairo_surface_t* -_cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface) +_cairo_quartz_snapshot_create (cairo_surface_t *surface) { cairo_quartz_snapshot_t *snapshot = NULL; + CGContextRef cgContext; + if (!surface || ! _is_quartz_surface (surface) || _cairo_quartz_is_zero_surface (surface)) + return NULL; - if (!surface || !_cairo_surface_is_quartz (&surface->base) || IS_EMPTY (surface) || - ! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) + if (_cairo_surface_is_quartz (surface) && + ! _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)surface)->cgContext)) return NULL; snapshot = _cairo_malloc (sizeof (cairo_quartz_snapshot_t)); @@ -2405,10 +2393,13 @@ _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); memset (snapshot, 0, sizeof (cairo_quartz_snapshot_t)); + cgContext = cairo_quartz_surface_get_cg_context (surface); _cairo_surface_init (&snapshot->base, &cairo_quartz_snapshot_backend, NULL, CAIRO_CONTENT_COLOR_ALPHA, FALSE); - snapshot->image = CGBitmapContextCreateImage (surface->cgContext); + snapshot->image = CGBitmapContextCreateImage (cgContext); + _cairo_surface_attach_snapshot (surface, &snapshot->base, NULL); + cairo_surface_destroy (&snapshot->base); // The surface has reffed the snapshot so we must unref it here. return &snapshot->base; } @@ -2423,43 +2414,34 @@ _cairo_quartz_snapshot_finish (void *surface) } CGImageRef -_cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface) +_cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface) { - cairo_surface_t *snapshot = - _cairo_surface_has_snapshot (&surface->base, &cairo_quartz_snapshot_backend); + cairo_surface_t *snapshot; + assert (_is_quartz_surface (surface)); + snapshot = + _cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend); if (unlikely (!snapshot)) { snapshot = _cairo_quartz_snapshot_create (surface); if (unlikely (!snapshot || cairo_surface_status (snapshot))) return NULL; - _cairo_surface_attach_snapshot (&surface->base, snapshot, NULL); - cairo_surface_destroy (snapshot); } return CGImageRetain (((cairo_quartz_snapshot_t*)snapshot)->image); } -/* Debug stuff */ - -#ifdef QUARTZ_DEBUG - void -quartz_image_to_png (CGImageRef image, const char *dest) +_cairo_quartz_image_to_png (CGImageRef image, const char *dest) { - static int sctr = 0; - const char* image_name = "quartz-image"; - char pathbuf[100]; - CFStringRef png_utti = CFSTR("public.png"); CFStringRef path; CFURLRef url; CGImageDestinationRef image_dest; - memset (pathbuf, 0, sizeof (pathbuf)); - dest = dest ? dest : image_name; - snprintf (pathbuf, sizeof (pathbuf), "%s/Desktop/%s%d.png",getenv ("HOME"), dest, sctr++); - path = CFStringCreateWithCString (NULL, pathbuf, kCFStringEncodingUTF8); + if (!dest) + return; + path = CFStringCreateWithCString (NULL, dest, kCFStringEncodingUTF8); url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE); image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL); @@ -2470,20 +2452,20 @@ quartz_image_to_png (CGImageRef image, const char *dest) CFRelease (path); } -void -quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest) +cairo_status_t +_cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest) { CGImageRef image; - - if (nq->base.type != CAIRO_SURFACE_TYPE_QUARTZ) { - fprintf (stderr, "** quartz_surface_to_png: surface %p isn't quartz!\n", nq); - return; + cairo_quartz_surface_t *surface; + if (!(_cairo_surface_is_quartz (abstract_surface) && + _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)abstract_surface)->cgContext))) { + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; } - image = CGBitmapContextCreateImage (nq->cgContext); - quartz_image_to_png (image, dest); + surface = (cairo_quartz_surface_t*)abstract_surface; + image = CGBitmapContextCreateImage (surface->cgContext); + _cairo_quartz_image_to_png (image, dest); CGImageRelease (image); + return CAIRO_STATUS_SUCCESS; } - -#endif /* QUARTZ_DEBUG */ diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c index 158ea16ba..2912f5ede 100644 --- a/src/cairo-recording-surface.c +++ b/src/cairo-recording-surface.c @@ -364,7 +364,10 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface) return CAIRO_STATUS_SUCCESS; cleanup: - bbtree_del (&surface->bbtree); + if (surface->bbtree.left) + bbtree_del (surface->bbtree.left); + if (surface->bbtree.right) + bbtree_del (surface->bbtree.right); return status; } diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 415b45f78..75640f723 100755 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -2660,6 +2660,8 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph, * @recording_surface: The recording surface * @foreground_color: The foreground color that was used to record the * glyph, or NULL if foreground color not required. + * + * Sets the surface that was used to record the glyph. */ void _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, @@ -2691,6 +2693,8 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, * @foreground_marker_color: The foreground color that was used to * substitute the foreground_marker, or NULL if foreground_marker not * used when rendering the surface color. + * + * Sets the color surface of the glyph. */ void _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c index 3117267cc..0f4918603 100644 --- a/src/cairo-shape-mask-compositor.c +++ b/src/cairo-shape-mask-compositor.c @@ -116,7 +116,7 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor, &_cairo_pattern_white.base, &pattern.base, clip); - if ((status == CAIRO_INT_STATUS_SUCCESS)) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_ADD, &extents->source_pattern.base, @@ -210,7 +210,7 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor, &_cairo_pattern_white.base, &pattern.base, clip); - if ((status == CAIRO_INT_STATUS_SUCCESS)) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_ADD, &extents->source_pattern.base, @@ -303,7 +303,7 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor, &_cairo_pattern_white.base, &pattern.base, clip); - if ((status == CAIRO_INT_STATUS_SUCCESS)) { + if (status == CAIRO_INT_STATUS_SUCCESS) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_ADD, &extents->source_pattern.base, diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c index 9c4432e24..bf29d4219 100644 --- a/src/cairo-surface-observer.c +++ b/src/cairo-surface-observer.c @@ -54,6 +54,15 @@ #include "cairo-script-private.h" #endif +/** + * SECTION:cairo-surface-observer + * @Title: Surface Observer + * @Short_Description: Observing other surfaces + * @See_Also: #cairo_surface_t + * + * A surface that exists solely to watch another is doing. + */ + static const cairo_surface_backend_t _cairo_surface_observer_backend; /* observation/stats */ diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 609eb9ccf..f1292e0bb 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -49,7 +49,6 @@ #include "cairo-recording-surface-private.h" #include "cairo-region-private.h" #include "cairo-surface-inline.h" -#include "cairo-tee-surface-private.h" /** * SECTION:cairo-surface diff --git a/src/cairo-svg.h b/src/cairo-svg.h index 5328cb583..7745eec90 100644 --- a/src/cairo-svg.h +++ b/src/cairo-svg.h @@ -73,9 +73,9 @@ typedef enum _cairo_svg_version { * lengths in the SVG specification. * * See also: - * https://www.w3.org/TR/SVG/coords.html#Units - * https://www.w3.org/TR/SVG/types.html#DataTypeLength - * https://www.w3.org/TR/css-values-3/#lengths + * - [SVG Units](https://www.w3.org/TR/SVG/coords.html#Units) + * - [SVG Types](https://www.w3.org/TR/SVG/types.html#DataTypeLength) + * - [CSS Length](https://www.w3.org/TR/css-values-3/#lengths) * * Since: 1.16 **/ diff --git a/src/cairo-tee-surface-private.h b/src/cairo-tee-surface-private.h deleted file mode 100644 index a83cfc959..000000000 --- a/src/cairo-tee-surface-private.h +++ /dev/null @@ -1,47 +0,0 @@ -/* cairo - a vector graphics library with display and print output - * - * Copyright © 2009 Chris Wilson - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - * The Original Code is the cairo graphics library. - * - * The Initial Developer of the Original Code is University of Southern - * California. - * - * Contributor(s): - * Chris Wilson <chris@chris-wilson.co.uk> - */ - -#ifndef CAIRO_TEE_SURFACE_PRIVATE_H -#define CAIRO_TEE_SURFACE_PRIVATE_H - -#include "cairoint.h" - -cairo_private cairo_surface_t * -_cairo_tee_surface_find_match (void *abstract_surface, - const cairo_surface_backend_t *backend, - cairo_content_t content); - -#endif /* CAIRO_TEE_SURFACE_PRIVATE_H */ diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c index 4994a5a60..1d075a29c 100644 --- a/src/cairo-tee-surface.c +++ b/src/cairo-tee-surface.c @@ -44,7 +44,6 @@ #include "cairo-default-context-private.h" #include "cairo-error-private.h" -#include "cairo-tee-surface-private.h" #include "cairo-recording-surface-inline.h" #include "cairo-surface-wrapper-private.h" #include "cairo-array-private.h" @@ -565,43 +564,3 @@ cairo_tee_surface_index (cairo_surface_t *abstract_surface, return slave->target; } } - -cairo_surface_t * -_cairo_tee_surface_find_match (void *abstract_surface, - const cairo_surface_backend_t *backend, - cairo_content_t content) -{ - cairo_tee_surface_t *surface = abstract_surface; - cairo_surface_wrapper_t *slaves; - int num_slaves, n; - - /* exact match first */ - if (surface->master.target->backend == backend && - surface->master.target->content == content) - { - return surface->master.target; - } - - num_slaves = _cairo_array_num_elements (&surface->slaves); - slaves = _cairo_array_index (&surface->slaves, 0); - for (n = 0; n < num_slaves; n++) { - if (slaves[n].target->backend == backend && - slaves[n].target->content == content) - { - return slaves[n].target; - } - } - - /* matching backend? */ - if (surface->master.target->backend == backend) - return surface->master.target; - - num_slaves = _cairo_array_num_elements (&surface->slaves); - slaves = _cairo_array_index (&surface->slaves, 0); - for (n = 0; n < num_slaves; n++) { - if (slaves[n].target->backend == backend) - return slaves[n].target; - } - - return NULL; -} diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c index 91ee0e90b..78c7dd5ec 100644 --- a/src/cairo-truetype-subset.c +++ b/src/cairo-truetype-subset.c @@ -1471,10 +1471,14 @@ find_name (tt_name_t *name, unsigned long size, int name_id, int platform, int e if (offset + len > size) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - str = _cairo_strndup (((char*)name) + offset, len); + str = _cairo_malloc (len + 1); if (str == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memcpy (str, + ((char*)name) + offset, + len); + str[len] = 0; break; } } diff --git a/src/cairo.c b/src/cairo.c index 55e7103ea..3d4fea601 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -1166,9 +1166,8 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) * cairo_set_line_width() and ignore this note. * * As with the other stroke parameters, the current line width is - * examined by cairo_stroke(), cairo_stroke_extents(), and - * cairo_stroke_to_path(), but does not have any effect during path - * construction. + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. * * The default line width value is 2.0. * @@ -1242,9 +1241,8 @@ slim_hidden_def (cairo_set_hairline); * styles are drawn. * * As with the other stroke parameters, the current line cap style is - * examined by cairo_stroke(), cairo_stroke_extents(), and - * cairo_stroke_to_path(), but does not have any effect during path - * construction. + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. * * The default line cap style is %CAIRO_LINE_CAP_BUTT. * @@ -1274,9 +1272,8 @@ slim_hidden_def (cairo_set_line_cap); * styles are drawn. * * As with the other stroke parameters, the current line join style is - * examined by cairo_stroke(), cairo_stroke_extents(), and - * cairo_stroke_to_path(), but does not have any effect during path - * construction. + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. * * The default line join style is %CAIRO_LINE_JOIN_MITER. * @@ -1411,9 +1408,8 @@ cairo_get_dash (cairo_t *cr, * converted to a bevel. * * As with the other stroke parameters, the current line miter limit is - * examined by cairo_stroke(), cairo_stroke_extents(), and - * cairo_stroke_to_path(), but does not have any effect during path - * construction. + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. * * The default miter limit value is 10.0, which will convert joins * with interior angles less than 11 degrees to bevels instead of @@ -2941,7 +2937,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr) * CAIRO_TAG_DEST: * * Create a destination for a hyperlink. Destination tag attributes - * are detailed at [Destinations][dests]. + * are detailed at [Destinations][dest]. * * Since: 1.16 **/ @@ -2950,7 +2946,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr) * CAIRO_TAG_LINK: * * Create hyperlink. Link tag attributes are detailed at - * [Links][links]. + * [Links][link]. * * Since: 1.16 **/ @@ -3360,7 +3356,7 @@ cairo_set_scaled_font (cairo_t *cr, if (unlikely (cr->status)) return; - if ((scaled_font == NULL)) { + if (scaled_font == NULL) { _cairo_set_error (cr, _cairo_error (CAIRO_STATUS_NULL_POINTER)); return; } @@ -4044,7 +4040,7 @@ slim_hidden_def (cairo_has_current_point); * cairo_move_to(), cairo_line_to(), cairo_curve_to(), * cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(), * cairo_arc(), cairo_arc_negative(), cairo_rectangle(), - * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path(). + * cairo_text_path(), cairo_glyph_path(). * * Some functions use and alter the current point but do not * otherwise change current path: diff --git a/src/cairo.h b/src/cairo.h index 78a958476..eef4c442b 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -295,6 +295,7 @@ typedef struct _cairo_user_data_key { * @CAIRO_STATUS_WIN32_GDI_ERROR: error occurred in the Windows Graphics Device Interface (Since 1.16) * @CAIRO_STATUS_TAG_ERROR: invalid tag name, attributes, or nesting (Since 1.16) * @CAIRO_STATUS_DWRITE_ERROR: error occurred in the Windows Direct Write API (Since 1.18) + * @CAIRO_STATUS_SVG_FONT_ERROR: error occurred in OpenType-SVG font rendering (Since 1.18) * @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of * status values defined in this enumeration. When using this value, note * that the version of cairo at run-time may have additional status values @@ -2448,26 +2449,37 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_PS: The surface is of type ps, since 1.2 * @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib, since 1.2 * @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb, since 1.2 - * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2 + * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2, deprecated 1.18 + * (glitz support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz, since 1.2 * @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32, since 1.2 - * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2 - * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2 + * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2, deprecated 1.18 + * (beos support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2, deprecated 1.18 + * (directfb support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg, since 1.2 - * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4 + * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4, deprecated 1.18 + * (os2 support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface, since 1.6 * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image, since 1.6 * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10 - * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10 + * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10, deprecated 1.18 + * (Ot support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_RECORDING: The surface is of type recording, since 1.10 - * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10 - * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10 - * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10 + * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10, deprecated 1.18 + * (OpenVG support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10, deprecated 1.18 + * (OpenGL support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10, deprecated 1.18 + * (DRM support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10 * @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10 + * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10, deprecated 1.18 + * (Skia support have been removed, this surface type will never be set by cairo) * @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with * cairo_surface_create_for_rectangle(), since 1.10 - * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12 + * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12, deprecated 1.18 + * (Cogl support have been removed, this surface type will never be set by cairo) * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface diff --git a/src/cairoint.h b/src/cairoint.h index 4b948cc40..e5c281842 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -896,6 +896,10 @@ cairo_private void _cairo_font_options_init_copy (cairo_font_options_t *options, const cairo_font_options_t *other); +cairo_private cairo_bool_t +_cairo_font_options_compare (const cairo_font_options_t *a, + const cairo_font_options_t *b); + cairo_private void _cairo_font_options_fini (cairo_font_options_t *options); diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp index 1d84fc047..cf516d41c 100644 --- a/src/win32/cairo-dwrite-font.cpp +++ b/src/win32/cairo-dwrite-font.cpp @@ -212,6 +212,9 @@ private: RefPtr<IDWriteFactory> DWriteFactory::mFactoryInstance; +RefPtr<IDWriteFactory1> DWriteFactory::mFactoryInstance1; +RefPtr<IDWriteFactory2> DWriteFactory::mFactoryInstance2; +RefPtr<IDWriteFactory3> DWriteFactory::mFactoryInstance3; RefPtr<IDWriteFactory4> DWriteFactory::mFactoryInstance4; RefPtr<IWICImagingFactory> WICImagingFactory::mFactoryInstance; @@ -221,6 +224,107 @@ RefPtr<IDWriteRenderingParams> DWriteFactory::mDefaultRenderingParams; RefPtr<ID2D1Factory> D2DFactory::mFactoryInstance; RefPtr<ID2D1DCRenderTarget> D2DFactory::mRenderTarget; +static int +_quality_from_antialias_mode(cairo_antialias_t antialias) +{ + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + return NONANTIALIASED_QUALITY; + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GRAY: + return ANTIALIASED_QUALITY; + default: + break; + } + return CLEARTYPE_QUALITY; +} + +static RefPtr<IDWriteRenderingParams> +_create_rendering_params(IDWriteRenderingParams *params, + const cairo_font_options_t *options, + cairo_antialias_t antialias) +{ + if (!params) + params = DWriteFactory::DefaultRenderingParams(); + FLOAT gamma = params->GetGamma(); + FLOAT enhanced_contrast = params->GetEnhancedContrast(); + FLOAT clear_type_level = params->GetClearTypeLevel(); + DWRITE_PIXEL_GEOMETRY pixel_geometry = params->GetPixelGeometry(); + DWRITE_RENDERING_MODE rendering_mode = params->GetRenderingMode(); + + cairo_bool_t modified = FALSE; + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + if (rendering_mode != DWRITE_RENDERING_MODE_ALIASED) { + rendering_mode = DWRITE_RENDERING_MODE_ALIASED; + modified = TRUE; + } + break; + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GRAY: + if (clear_type_level) { + clear_type_level = 0; + modified = TRUE; + } + break; + default: + break; + } + auto subpixel_order = cairo_font_options_get_subpixel_order (options); + switch (subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_RGB: + if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_RGB) { + pixel_geometry = DWRITE_PIXEL_GEOMETRY_RGB; + modified = TRUE; + } + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_BGR) { + pixel_geometry = DWRITE_PIXEL_GEOMETRY_BGR; + modified = TRUE; + } + break; + default: + break; + } + if (!modified) + return params; + + HRESULT hr; + RefPtr<IDWriteRenderingParams1> params1; + hr = params->QueryInterface(¶ms1); + if (FAILED(hr)) { + RefPtr<IDWriteRenderingParams> ret; + DWriteFactory::Instance()->CreateCustomRenderingParams(gamma, enhanced_contrast, clear_type_level, pixel_geometry, rendering_mode, &ret); + return ret; + } + + FLOAT grayscaleEnhancedContrast = params1->GetGrayscaleEnhancedContrast(); + RefPtr<IDWriteRenderingParams2> params2; + hr = params->QueryInterface(¶ms2); + if (FAILED(hr)) { + RefPtr<IDWriteRenderingParams1> ret; + DWriteFactory::Instance1()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, &ret); + return ret; + } + + DWRITE_GRID_FIT_MODE gridFitMode = params2->GetGridFitMode(); + RefPtr<IDWriteRenderingParams3> params3; + hr = params->QueryInterface(¶ms3); + if (FAILED(hr)) { + RefPtr<IDWriteRenderingParams2> ret; + DWriteFactory::Instance2()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, gridFitMode, &ret); + return ret; + } + + DWRITE_RENDERING_MODE1 rendering_mode1 = params3->GetRenderingMode1(); + if (antialias == CAIRO_ANTIALIAS_NONE) + rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED; + RefPtr<IDWriteRenderingParams3> ret; + DWriteFactory::Instance3()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode1, gridFitMode, &ret); + return ret; +} + /* Functions #cairo_font_face_backend_t */ static cairo_status_t _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, @@ -557,13 +661,6 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face, dwrite_font->mat_inverse = dwrite_font->mat; cairo_matrix_invert (&dwrite_font->mat_inverse); - dwrite_font->rendering_params = NULL; - if (font_face->rendering_params) { - dwrite_font->rendering_params = font_face->rendering_params; - dwrite_font->rendering_params->AddRef(); - } - dwrite_font->measuring_mode = font_face->measuring_mode; - cairo_font_extents_t extents; DWRITE_FONT_METRICS metrics; @@ -612,6 +709,9 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face, dwrite_font->antialias_mode = options->antialias; } + dwrite_font->rendering_params = _create_rendering_params(font_face->rendering_params, options, dwrite_font->antialias_mode).forget().drop(); + dwrite_font->measuring_mode = font_face->measuring_mode; + return _cairo_scaled_font_set_metrics (*font, &extents); } @@ -716,10 +816,15 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_ // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics // for the glyph outline, without accounting for hinting/gridfitting/antialiasing, // and therefore it does not always cover all pixels that will actually be touched. - if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE && - extents.width > 0 && extents.height > 0) { - extents.width += scaled_font->mat_inverse.xx * 2; - extents.x_bearing -= scaled_font->mat_inverse.xx; + if (extents.width > 0 && extents.height > 0) { + double x = 1, y = 1; + cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y); + x = fabs(x); + y = fabs(y); + extents.width += x * 2; + extents.x_bearing -= x; + extents.height += y * 2; + extents.y_bearing -= y; } _cairo_scaled_glyph_set_metrics (scaled_glyph, @@ -736,8 +841,9 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_ class GeometryRecorder : public IDWriteGeometrySink { public: - GeometryRecorder(cairo_path_fixed_t *aCairoPath) - : mCairoPath(aCairoPath) {} + GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix) + : mCairoPath(aCairoPath) + , mMatrix(matrix) {} // IUnknown interface IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) @@ -779,10 +885,14 @@ public: D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) { - mStartPoint = startPoint; + double x = startPoint.x; + double y = startPoint.y; + cairo_matrix_transform_point(&mMatrix, &x, &y); + mStartPointX = _cairo_fixed_from_double(x); + mStartPointY = _cairo_fixed_from_double(y); cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath, - _cairo_fixed_from_double(startPoint.x), - _cairo_fixed_from_double(startPoint.y)); + mStartPointX, + mStartPointY); (void)status; /* squelch warning */ } @@ -791,8 +901,8 @@ public: { if (figureEnd == D2D1_FIGURE_END_CLOSED) { cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath, - _cairo_fixed_from_double(mStartPoint.x), - _cairo_fixed_from_double(mStartPoint.y)); + mStartPointX, + mStartPointY); (void)status; /* squelch warning */ } } @@ -802,13 +912,22 @@ public: UINT beziersCount) { for (unsigned int i = 0; i < beziersCount; i++) { + double x1 = beziers[i].point1.x; + double y1 = beziers[i].point1.y; + double x2 = beziers[i].point2.x; + double y2 = beziers[i].point2.y; + double x3 = beziers[i].point3.x; + double y3 = beziers[i].point3.y; + cairo_matrix_transform_point(&mMatrix, &x1, &y1); + cairo_matrix_transform_point(&mMatrix, &x2, &y2); + cairo_matrix_transform_point(&mMatrix, &x3, &y3); cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath, - _cairo_fixed_from_double(beziers[i].point1.x), - _cairo_fixed_from_double(beziers[i].point1.y), - _cairo_fixed_from_double(beziers[i].point2.x), - _cairo_fixed_from_double(beziers[i].point2.y), - _cairo_fixed_from_double(beziers[i].point3.x), - _cairo_fixed_from_double(beziers[i].point3.y)); + _cairo_fixed_from_double(x1), + _cairo_fixed_from_double(y1), + _cairo_fixed_from_double(x2), + _cairo_fixed_from_double(y2), + _cairo_fixed_from_double(x3), + _cairo_fixed_from_double(y3)); (void)status; /* squelch warning */ } } @@ -818,16 +937,21 @@ public: UINT pointsCount) { for (unsigned int i = 0; i < pointsCount; i++) { + double x = points[i].x; + double y = points[i].y; + cairo_matrix_transform_point(&mMatrix, &x, &y); cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath, - _cairo_fixed_from_double(points[i].x), - _cairo_fixed_from_double(points[i].y)); + _cairo_fixed_from_double(x), + _cairo_fixed_from_double(y)); (void)status; /* squelch warning */ } } private: cairo_path_fixed_t *mCairoPath; - D2D1_POINT_2F mStartPoint; + const cairo_matrix_t &mMatrix; + cairo_fixed_t mStartPointX; + cairo_fixed_t mStartPointY; }; static cairo_int_status_t @@ -837,7 +961,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon cairo_int_status_t status; cairo_path_fixed_t *path; path = _cairo_path_fixed_create(); - GeometryRecorder recorder(path); + GeometryRecorder recorder(path, scaled_font->base.scale); DWRITE_GLYPH_OFFSET offset; offset.advanceOffset = 0; @@ -846,12 +970,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon FLOAT advance = 0.0; cairo_dwrite_font_face_t *dwriteff = (cairo_dwrite_font_face_t*)scaled_font->base.font_face; - /* GetGlyphRunOutline seems to ignore hinting so just use the em size to get the outline - * to avoid rounding errors when converting to cairo_path_fixed_t. - */ - DWRITE_FONT_METRICS metrics; - dwriteff->dwriteface->GetMetrics(&metrics); - HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(metrics.designUnitsPerEm, + HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(1, &glyphId, &advance, &offset, @@ -864,12 +983,6 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon status = (cairo_int_status_t)_cairo_path_fixed_close_path(path); - /* Now scale the em size down to 1.0 and apply the font matrix and font ctm. */ - cairo_matrix_t mat = scaled_font->base.ctm; - cairo_matrix_multiply(&mat, &scaled_font->base.font_matrix, &mat); - cairo_matrix_scale (&mat, 1.0/metrics.designUnitsPerEm, 1.0/metrics.designUnitsPerEm); - _cairo_path_fixed_transform(path, &mat); - _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, path); @@ -883,7 +996,6 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s { int width, height; double x1, y1, x2, y2; - cairo_glyph_t glyph; cairo_bool_t uses_foreground_color = FALSE; cairo_dwrite_font_face_t *dwrite_font_face = (cairo_dwrite_font_face_t *)scaled_font->base.font_face; @@ -900,22 +1012,18 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s width = (int)(x2 - x1); height = (int)(y2 - y1); - glyph.index = _cairo_scaled_glyph_index (scaled_glyph); - glyph.x = x1; - glyph.y = y1; - DWRITE_GLYPH_RUN run; FLOAT advance = 0; - UINT16 index = (UINT16)glyph.index; + UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); DWRITE_GLYPH_OFFSET offset; - double x = -glyph.x; - double y = -glyph.y; + double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph); DWRITE_MATRIX matrix; D2D1_POINT_2F origin = {0, 0}; RefPtr<IDWriteColorGlyphRunEnumerator1> run_enumerator; HRESULT hr; - /** + /* * We transform by the inverse transformation here. This will put our glyph * locations in the space in which we draw. Which is later transformed by * the transformation matrix that we use. This will transform the @@ -924,7 +1032,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s */ cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); offset.advanceOffset = (FLOAT)x; - /** Y-axis is inverted */ + /* Y-axis is inverted */ offset.ascenderOffset = -(FLOAT)y; run.fontFace = dwrite_font_face->dwriteface; @@ -1036,8 +1144,8 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s if (FAILED(hr) || !have_run) break; - DWRITE_COLOR_GLYPH_RUN1 const* color_run; - hr = run_enumerator->GetCurrentRun(&color_run); + DWRITE_COLOR_GLYPH_RUN1_WORKAROUND const* color_run; + hr = run_enumerator->GetCurrentRun(reinterpret_cast<const DWRITE_COLOR_GLYPH_RUN1**>(&color_run)); if (FAILED(hr)) return _cairo_dwrite_error (hr, "GetCurrentRun failed"); @@ -1118,48 +1226,11 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s return CAIRO_INT_STATUS_SUCCESS; } -/* Helper function adapted from _compute_mask in cairo-win32-font.c */ - -/* Compute an alpha-mask from a monochrome RGB24 image - */ -static cairo_surface_t * -_compute_a8_mask (cairo_surface_t *surface) -{ - cairo_image_surface_t *glyph; - cairo_image_surface_t *mask; - int i, j; - - glyph = (cairo_image_surface_t *)cairo_surface_map_to_image (surface, NULL); - if (unlikely (glyph->base.status)) - return &glyph->base; - - /* No quality param, just use the non-ClearType path */ - - /* Compute an alpha-mask by using the green channel of a (presumed monochrome) - * RGB24 image. - */ - mask = (cairo_image_surface_t *) - cairo_image_surface_create (CAIRO_FORMAT_A8, glyph->width, glyph->height); - if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) { - for (i = 0; i < glyph->height; i++) { - uint32_t *p = (uint32_t *) (glyph->data + i * glyph->stride); - uint8_t *q = (uint8_t *) (mask->data + i * mask->stride); - - for (j = 0; j < glyph->width; j++) - *q++ = 255 - ((*p++ & 0x0000ff00) >> 8); - } - } - - cairo_surface_unmap_image (surface, &glyph->base); - return &mask->base; -} - static cairo_int_status_t _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status; - cairo_glyph_t glyph; cairo_win32_surface_t *surface; cairo_t *cr; cairo_surface_t *image; @@ -1173,16 +1244,12 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_ width = (int)(x2 - x1); height = (int)(y2 - y1); - glyph.index = _cairo_scaled_glyph_index (scaled_glyph); - glyph.x = -x1; - glyph.y = -y1; - DWRITE_GLYPH_RUN run; FLOAT advance = 0; - UINT16 index = (UINT16)glyph.index; + UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); DWRITE_GLYPH_OFFSET offset; - double x = glyph.x; - double y = glyph.y; + double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph); RECT area; DWRITE_MATRIX matrix; @@ -1197,7 +1264,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_ if (status) goto FAIL; - /** + /* * We transform by the inverse transformation here. This will put our glyph * locations in the space in which we draw. Which is later transformed by * the transformation matrix that we use. This will transform the @@ -1206,7 +1273,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_ */ cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); offset.advanceOffset = (FLOAT)x; - /** Y-axis is inverted */ + /* Y-axis is inverted */ offset.ascenderOffset = -(FLOAT)y; area.top = 0; @@ -1232,7 +1299,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_ GdiFlush(); - image = _compute_a8_mask (&surface->base); + image = _cairo_compute_glyph_mask (&surface->base, _quality_from_antialias_mode(scaled_font->antialias_mode)); status = (cairo_int_status_t)image->status; if (status) goto FAIL; @@ -1486,6 +1553,9 @@ cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face) * @params: The #IDWriteRenderingParams object * * Sets the #IDWriteRenderingParams object to @font_face. + * This #IDWriteRenderingParams is used to render glyphs if default values of font options are used. + * If non-defalut values of font options are specified when creating a #cairo_scaled_font_t, + * cairo creates a new #IDWriteRenderingParams object for the #cairo_scaled_font_t object by overwriting the corresponding parameters. * * Since: 1.18 **/ @@ -1559,13 +1629,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface, } } - IDWriteRenderingParams *params; - if (scaled_font->rendering_params) - params = scaled_font->rendering_params; - else - params = DWriteFactory::DefaultRenderingParams(); - - /** + /* * We set the number of pixels per DIP to 1.0. This is because we always want * to draw in device pixels, and not device independent pixels. On high DPI * systems this value will be higher than 1.0 and automatically upscale @@ -1573,8 +1637,15 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface, */ rt->SetPixelsPerDip(1.0); + float x = 0, y = 0; if (transform) { - rt->SetCurrentTransform(transform); + DWRITE_MATRIX matrix = *transform; + matrix.dx -= area.left; + matrix.dy -= area.top; + rt->SetCurrentTransform(&matrix); + } else { + x = (float) -area.left; + y = (float) -area.top; } BitBlt(rt->GetMemoryDC(), 0, 0, @@ -1582,7 +1653,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface, surface->dc, area.left, area.top, SRCCOPY | NOMIRRORBITMAP); - rt->DrawGlyphRun(0, 0, scaled_font->measuring_mode, run, params, color); + rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, scaled_font->rendering_params, color); BitBlt(surface->dc, area.left, area.top, area.right - area.left, area.bottom - area.top, @@ -1618,6 +1689,7 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface, if (FAILED(hr)) return CAIRO_INT_STATUS_UNSUPPORTED; + float x = 0, y = 0; if (transform) { rt->SetTransform(D2D1::Matrix3x2F(transform->m11, transform->m12, @@ -1666,15 +1738,6 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface, if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) return CAIRO_INT_STATUS_UNSUPPORTED; - /* If we have a fallback mask clip set on the dst, we have - * to go through the fallback path */ - if (!_cairo_surface_is_win32_printing (&dst->base)) { - if (clip != NULL) - _cairo_win32_display_surface_set_clip (to_win32_display_surface (dst), clip); - else - _cairo_win32_display_surface_unset_clip (to_win32_display_surface (dst)); - } - /* It is vital that dx values for dxy_buf are calculated from the delta of * _logical_ x coordinates (not user x coordinates) or else the sum of all * previous dx values may start to diverge from the current glyph's x @@ -1689,96 +1752,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface, DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets); BOOL transform = FALSE; - /* Needed to calculate bounding box for efficient blitting */ - INT32 smallestX = INT_MAX; - INT32 largestX = 0; - INT32 smallestY = INT_MAX; - INT32 largestY = 0; - for (int i = 0; i < num_glyphs; i++) { - if (glyphs[i].x < smallestX) { - smallestX = (INT32)glyphs[i].x; - } - if (glyphs[i].x > largestX) { - largestX = (INT32)glyphs[i].x; - } - if (glyphs[i].y < smallestY) { - smallestY = (INT32)glyphs[i].y; - } - if (glyphs[i].y > largestY) { - largestY = (INT32)glyphs[i].y; - } - } - /** - * Here we try to get a rough estimate of the area that this glyph run will - * cover on the surface. Since we use GDI interop to draw we will be copying - * data around the size of the area of the surface that we map. We will want - * to map an area as small as possible to prevent large surfaces to be - * copied around. We take the X/Y-size of the font as margin on the left/top - * twice the X/Y-size of the font as margin on the right/bottom. - * This should always cover the entire area where the glyphs are. - */ - RECT fontArea; - fontArea.left = (INT32)(smallestX - scaled_font->font_matrix.xx); - fontArea.right = (INT32)(largestX + scaled_font->font_matrix.xx * 2); - fontArea.top = (INT32)(smallestY - scaled_font->font_matrix.yy); - fontArea.bottom = (INT32)(largestY + scaled_font->font_matrix.yy * 2); - if (fontArea.left < 0) - fontArea.left = 0; - if (fontArea.top < 0) - fontArea.top = 0; - if (fontArea.bottom > dst->extents.height) { - fontArea.bottom = dst->extents.height; - } - if (fontArea.right > dst->extents.width) { - fontArea.right = dst->extents.width; - } - if (fontArea.right <= fontArea.left || - fontArea.bottom <= fontArea.top) { - return CAIRO_INT_STATUS_SUCCESS; - } - if (fontArea.right > dst->extents.width) { - fontArea.right = dst->extents.width; - } - if (fontArea.bottom > dst->extents.height) { - fontArea.bottom = dst->extents.height; - } - - run.bidiLevel = 0; - run.fontFace = dwriteff->dwriteface; - run.isSideways = FALSE; - if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 && - dwritesf->mat.xx == scaled_font->font_matrix.xx && - dwritesf->mat.yy == scaled_font->font_matrix.yy) { - - for (int i = 0; i < num_glyphs; i++) { - indices[i] = (WORD) glyphs[i].index; - // Since we will multiply by our ctm matrix later for rotation effects - // and such, adjust positions by the inverse matrix now. - offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y); - offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left); - advances[i] = 0.0; - } - run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy; - } else { - transform = TRUE; - // See comment about EPSILON in _cairo_dwrite_glyph_run_from_glyphs - const double EPSILON = 0.0001; - for (int i = 0; i < num_glyphs; i++) { - indices[i] = (WORD) glyphs[i].index; - double x = glyphs[i].x - fontArea.left + EPSILON; - double y = glyphs[i].y - fontArea.top; - cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y); - /** - * Since we will multiply by our ctm matrix later for rotation effects - * and such, adjust positions by the inverse matrix now. The Y-axis - * is inverted so the offset becomes negative. - */ - offsets[i].ascenderOffset = -(FLOAT)y; - offsets[i].advanceOffset = (FLOAT)x; - advances[i] = 0.0; - } - run.fontEmSize = 1.0f; - } + _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform); cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source; COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8, @@ -1794,18 +1768,31 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface, mat = NULL; } - RECT area; - area.left = dst->extents.x; - area.top = dst->extents.y; - area.right = area.left + dst->extents.width; - area.bottom = area.top + dst->extents.height; + RefPtr<IDWriteGlyphRunAnalysis> runAnalysis; + HRESULT hr = DWriteFactory::Instance()-> + CreateGlyphRunAnalysis(&run, 1, mat, + DWRITE_RENDERING_MODE_ALIASED, + dwritesf->measuring_mode, + 0, // baselineOriginX, + 0, // baselineOriginY, + &runAnalysis); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + RECT fontArea; + hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + InflateRect(&fontArea, 1, 1); + /* Needed to calculate bounding box for efficient blitting */ + RECT copyArea, dstArea = { 0, 0, dst->extents.width, dst->extents.height }; + IntersectRect(©Area, &fontArea, &dstArea); #ifdef CAIRO_TRY_D2D_TO_GDI status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst, mat, &run, color, - fontArea); + copyArea); if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) { #endif @@ -1814,7 +1801,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface, &run, color, dwritesf, - fontArea); + copyArea); #ifdef CAIRO_TRY_D2D_TO_GDI } diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp index 4857739ea..c7a24822a 100644 --- a/src/win32/cairo-dwrite-private.hpp +++ b/src/win32/cairo-dwrite-private.hpp @@ -36,27 +36,25 @@ #include "cairoint.h" #include "cairo-win32-refptr.hpp" -#include <dwrite.h> -#include <dwrite_2.h> +#include <dwrite_3.h> #include <d2d1.h> -/* If either of the dwrite_3.h or d2d1_3.h headers required for color fonts - * are not available, include our own version containing just the functions we need. - */ - -#if HAVE_DWRITE_3_H -#include <dwrite_3.h> -#else +#ifdef __MINGW32__ #include "dw-extra.h" +#else +typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; #endif +/* If d2d1_3.h header required for color fonts is not available, + * include our own version containing just the functions we need. + */ + #if HAVE_D2D1_3_H #include <d2d1_3.h> #else #include "d2d1-extra.h" #endif - // DirectWrite is not available on all platforms. typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( DWRITE_FACTORY_TYPE factoryType, @@ -101,6 +99,36 @@ public: return mFactoryInstance; } + static RefPtr<IDWriteFactory1> Instance1() + { + if (!mFactoryInstance1) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance1); + } + } + return mFactoryInstance1; + } + + static RefPtr<IDWriteFactory2> Instance2() + { + if (!mFactoryInstance2) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance2); + } + } + return mFactoryInstance2; + } + + static RefPtr<IDWriteFactory3> Instance3() + { + if (!mFactoryInstance3) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance3); + } + } + return mFactoryInstance3; + } + static RefPtr<IDWriteFactory4> Instance4() { if (!mFactoryInstance4) { @@ -151,6 +179,9 @@ public: private: static RefPtr<IDWriteFactory> mFactoryInstance; + static RefPtr<IDWriteFactory1> mFactoryInstance1; + static RefPtr<IDWriteFactory2> mFactoryInstance2; + static RefPtr<IDWriteFactory3> mFactoryInstance3; static RefPtr<IDWriteFactory4> mFactoryInstance4; static RefPtr<IDWriteFontCollection> mSystemCollection; static RefPtr<IDWriteRenderingParams> mDefaultRenderingParams; diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c index 6bc8bef94..fd9461363 100644 --- a/src/win32/cairo-win32-font.c +++ b/src/win32/cairo-win32-font.c @@ -1335,9 +1335,9 @@ _cairo_win32_scaled_font_load_type1_data (void *abstract_font, length); } -static cairo_surface_t * -_compute_mask (cairo_surface_t *surface, - int quality) +cairo_surface_t * +_cairo_compute_glyph_mask (cairo_surface_t *surface, + int quality) { cairo_image_surface_t *glyph; cairo_image_surface_t *mask; @@ -1421,7 +1421,7 @@ _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_f if (status) goto FAIL; - image = _compute_mask (surface, scaled_font->quality); + image = _cairo_compute_glyph_mask (surface, scaled_font->quality); status = image->status; if (status) goto FAIL; diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h index 486b12811..6af09c0e1 100644 --- a/src/win32/cairo-win32-private.h +++ b/src/win32/cairo-win32-private.h @@ -214,6 +214,10 @@ cairo_bool_t _cairo_win32_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *rectangle); +cairo_surface_t * +_cairo_compute_glyph_mask (cairo_surface_t *surface, + int quality); + uint32_t _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format); diff --git a/src/win32/dw-extra.h b/src/win32/dw-extra.h index 4203f3427..c79e6389c 100644 --- a/src/win32/dw-extra.h +++ b/src/win32/dw-extra.h @@ -1,165 +1,30 @@ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Mingw-w64 dwrite_3.h is broken +/* MinGW workarounds * - * We only need the definitions of the following functions and their dependencies. - * IDWriteFactory4::TranslateColorGlyphRun() - * IDWriteFontResource::GetDefaultFontAxisValues() - * IDWriteFontResource::GetFontAxisCount() - * IDWriteFontResource::HasVariations() - * IDWriteFontFace5::GetFontAxisValueCount() - * IDWriteFontFace5::GetFontAxisValues() - * IDWriteFontFace5::HasVariations() - * IDWriteFontFace5::GetFontResource() - * - * But we need to include all the prior functions in the same struct, - * and parent structs, so that the functions are in the correct position - * in the vtable. The parameters of the unused functions are not - * required as we only need a function in the struct to create a - * function pointer in the vtable. + * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS. + * The DWRITE_COLOR_GLYPH_RUN struct isn't valid. + * <https://sourceforge.net/p/mingw-w64/bugs/913/> */ #ifndef DWRITE_EXTRA_H #define DWRITE_EXTRA_H -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" - -#include <dwrite_2.h> +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10 -interface IDWriteFactory3; -interface IDWriteFactory4; -interface IDWriteColorGlyphRunEnumerator1; - -DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS); - -struct DWRITE_COLOR_GLYPH_RUN1 : DWRITE_COLOR_GLYPH_RUN +typedef struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN { DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat; DWRITE_MEASURING_MODE measuringMode; }; +#else +typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +#error -DEFINE_GUID(IID_IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35); -MIDL_INTERFACE("7c5f86da-c7a1-4f05-b8e1-55a179fe5a35") -IDWriteColorGlyphRunEnumerator1 : public IDWriteColorGlyphRunEnumerator -{ - virtual HRESULT STDMETHODCALLTYPE GetCurrentRun( - const DWRITE_COLOR_GLYPH_RUN1 **run) = 0; - -}; -__CRT_UUID_DECL(IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35) - -DEFINE_GUID(IID_IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65); -MIDL_INTERFACE("9a1b41c3-d3bb-466a-87fc-fe67556a3b65") -IDWriteFactory3 : public IDWriteFactory2 -{ - virtual void STDMETHODCALLTYPE CreateGlyphRunAnalysis() = 0; - virtual void STDMETHODCALLTYPE CreateCustomRenderingParams() = 0; - virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0; - virtual void STDMETHODCALLTYPE CreateFontFaceReference2() = 0; - virtual void STDMETHODCALLTYPE GetSystemFontSet() = 0; - virtual void STDMETHODCALLTYPE CreateFontSetBuilder() = 0; - virtual void STDMETHODCALLTYPE CreateFontCollectionFromFontSet() = 0; - virtual void STDMETHODCALLTYPE GetSystemFontCollection() = 0; - virtual void STDMETHODCALLTYPE GetFontDownloadQueue() = 0; -}; -__CRT_UUID_DECL(IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65) - -DEFINE_GUID(IID_IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56); -MIDL_INTERFACE("4b0b5bd3-0797-4549-8ac5-fe915cc53856") -IDWriteFactory4 : public IDWriteFactory3 -{ - virtual HRESULT STDMETHODCALLTYPE TranslateColorGlyphRun( - D2D1_POINT_2F baselineOrigin, - DWRITE_GLYPH_RUN const *glyphRun, - DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription, - DWRITE_GLYPH_IMAGE_FORMATS desiredGlyphImageFormats, - DWRITE_MEASURING_MODE measuringMode, - DWRITE_MATRIX const *worldAndDpiTransform, - UINT32 colorPaletteIndex, - IDWriteColorGlyphRunEnumerator1 **colorLayers) = 0; -}; -__CRT_UUID_DECL(IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56) - -typedef enum DWRITE_FONT_AXIS_TAG { - DWRITE_FONT_AXIS_TAG_WEIGHT = 0x74686777, - DWRITE_FONT_AXIS_TAG_WIDTH = 0x68746477, - DWRITE_FONT_AXIS_TAG_SLANT = 0x746e6c73, - DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE = 0x7a73706f, - DWRITE_FONT_AXIS_TAG_ITALIC = 0x6c617469 -} DWRITE_FONT_AXIS_TAG; - -typedef struct DWRITE_FONT_AXIS_VALUE { - DWRITE_FONT_AXIS_TAG axisTag; - FLOAT value; -} DWRITE_FONT_AXIS_VALUE; - -DEFINE_GUID(IID_IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2); -MIDL_INTERFACE("1f803a76-6871-48e8-987f-b975551c50f2") -IDWriteFontResource : public IUnknown -{ - virtual void STDMETHODCALLTYPE GetFontFile() = 0; - virtual void STDMETHODCALLTYPE GetFontFaceIndex() = 0; - virtual UINT32 STDMETHODCALLTYPE GetFontAxisCount() = 0; - virtual HRESULT STDMETHODCALLTYPE GetDefaultFontAxisValues( - const DWRITE_FONT_AXIS_VALUE *values, - UINT32 num_values) = 0; - virtual void STDMETHODCALLTYPE GetFontAxisRanges() = 0; - virtual void STDMETHODCALLTYPE GetFontAxisAttributes() = 0; - virtual void STDMETHODCALLTYPE GetAxisNames() = 0; - virtual void STDMETHODCALLTYPE GetAxisValueNameCount() = 0; - virtual void STDMETHODCALLTYPE GetAxisValueNames() = 0; - virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0; - virtual void STDMETHODCALLTYPE CreateFontFace() = 0; - virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0; -}; -__CRT_UUID_DECL(IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2) - -DEFINE_GUID(IID_IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2); -MIDL_INTERFACE("d37d7598-09be-4222-a236-2081341cc1f2") -IDWriteFontFace3 : public IDWriteFontFace2 -{ - virtual void STDMETHODCALLTYPE GetFontFaceReference() = 0; - virtual void STDMETHODCALLTYPE GetPanose() = 0; - virtual void STDMETHODCALLTYPE GetWeight() = 0; - virtual void STDMETHODCALLTYPE GetStretch() = 0; - virtual void STDMETHODCALLTYPE GetStyle() = 0; - virtual void STDMETHODCALLTYPE GetFamilyNames() = 0; - virtual void STDMETHODCALLTYPE GetFaceNames() = 0; - virtual void STDMETHODCALLTYPE GetInformationalStrings() = 0; - virtual void STDMETHODCALLTYPE HasCharacter() = 0; - virtual void STDMETHODCALLTYPE GetRecommendedRenderingMode() = 0; - virtual void STDMETHODCALLTYPE IsCharacterLocal() = 0; - virtual void STDMETHODCALLTYPE IsGlyphLocal() = 0; - virtual void STDMETHODCALLTYPE AreCharactersLocal() = 0; - virtual void STDMETHODCALLTYPE AreGlyphsLocal() = 0; -}; -__CRT_UUID_DECL(IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2) - -DEFINE_GUID(IID_IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f); -MIDL_INTERFACE("27f2a904-4eb8-441d-9678-0563f53e3e2f") -IDWriteFontFace4 : public IDWriteFontFace3 -{ - virtual void STDMETHODCALLTYPE GetGlyphImageFormats_() = 0; - virtual void STDMETHODCALLTYPE GetGlyphImageFormats() = 0; - virtual void STDMETHODCALLTYPE GetGlyphImageData() = 0; - virtual void STDMETHODCALLTYPE ReleaseGlyphImageData() = 0; -}; -__CRT_UUID_DECL(IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f) +#endif -DEFINE_GUID(IID_IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29); -MIDL_INTERFACE("98eff3a5-b667-479a-b145-e2fa5b9fdc29") -IDWriteFontFace5 : public IDWriteFontFace4 -{ - virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount() = 0; - virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues( - DWRITE_FONT_AXIS_VALUE *values, - UINT32 value_count) = 0; - virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0; - virtual HRESULT STDMETHODCALLTYPE GetFontResource( - IDWriteFontResource **resource) = 0; - virtual void STDMETHODCALLTYPE Equals() = 0; -}; -__CRT_UUID_DECL(IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29) +DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS); #endif /* DWRITE_EXTRA_H */ |