diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2023-01-28 04:54:26 +0000 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2023-01-28 04:54:26 +0000 |
commit | b67afda591f90a40ba7eafcf42dbf36ed7a746e6 (patch) | |
tree | fabd55a3e7d5f38dc67327afca3247cfcc297c1c /src | |
parent | ffabca7924ac57cb808a6a05fa1b00e038f068b5 (diff) | |
parent | bdf97dd2a16886f53f840f1d76922a28e4f36e63 (diff) | |
download | cairo-b67afda591f90a40ba7eafcf42dbf36ed7a746e6.tar.gz |
Merge branch 'fix-ft-foreground' into 'master'
Fix foreground colors in FT/SVG/COLRv1
See merge request cairo/cairo!430
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-colr-glyph-render.c | 86 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 141 | ||||
-rw-r--r-- | src/cairo-ft-private.h | 9 | ||||
-rw-r--r-- | src/cairo-gstate.c | 2 | ||||
-rw-r--r-- | src/cairo-pattern-private.h | 5 | ||||
-rw-r--r-- | src/cairo-pattern.c | 20 | ||||
-rw-r--r-- | src/cairo-recording-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-scaled-font-private.h | 6 | ||||
-rwxr-xr-x | src/cairo-scaled-font.c | 26 | ||||
-rw-r--r-- | src/cairo-surface.c | 14 | ||||
-rw-r--r-- | src/cairo-svg-glyph-render.c | 77 | ||||
-rw-r--r-- | src/cairo-user-font.c | 17 |
12 files changed, 234 insertions, 171 deletions
diff --git a/src/cairo-colr-glyph-render.c b/src/cairo-colr-glyph-render.c index 104942b78..28254fd51 100644 --- a/src/cairo-colr-glyph-render.c +++ b/src/cairo-colr-glyph-render.c @@ -36,6 +36,7 @@ #include "cairo-array-private.h" #include "cairo-ft-private.h" #include "cairo-path-private.h" +#include "cairo-pattern-private.h" #include <assert.h> #include <math.h> @@ -55,9 +56,11 @@ typedef struct _cairo_colr_glyph_render { FT_Face face; - cairo_pattern_t *foreground_color; FT_Color *palette; unsigned int num_palette_entries; + cairo_pattern_t *foreground_marker; + cairo_pattern_t *foreground_source; + cairo_bool_t foreground_source_used; int level; } cairo_colr_glyph_render_t; @@ -225,29 +228,29 @@ draw_paint_colr_layers (cairo_colr_glyph_render_t *render, static void get_palette_color (cairo_colr_glyph_render_t *render, - FT_ColorIndex *ci, - cairo_color_t *color, - cairo_bool_t *is_foreground_color) + FT_ColorIndex *ci, + cairo_color_t *color, + double *colr_alpha, + cairo_bool_t *is_foreground_color) { cairo_bool_t foreground = FALSE; if (ci->palette_index == 0xffff || ci->palette_index >= render->num_palette_entries) { - color->red = 0; - color->green = 0; - color->blue = 0; + color->red = 0; + color->green = 0; + color->blue = 0; color->alpha = 1; - foreground = TRUE; + foreground = TRUE; } else { - FT_Color c = render->palette[ci->palette_index]; - color->red = c.red / 255.0; - color->green = c.green / 255.0; - color->blue = c.blue / 255.0; + FT_Color c = render->palette[ci->palette_index]; + color->red = c.red / 255.0; + color->green = c.green / 255.0; + color->blue = c.blue / 255.0; color->alpha = c.alpha / 255.0; } - color->alpha *= double_from_2_14 (ci->alpha); - if (is_foreground_color) - *is_foreground_color = foreground; + *colr_alpha = double_from_2_14 (ci->alpha); + *is_foreground_color = foreground; } static cairo_status_t @@ -256,21 +259,19 @@ draw_paint_solid (cairo_colr_glyph_render_t *render, cairo_t *cr) { cairo_color_t color; + double colr_alpha; cairo_bool_t is_foreground_color; #if DEBUG_COLR printf ("%*sDraw PaintSolid\n", 2 * render->level, ""); #endif - get_palette_color (render, &solid->color, &color, &is_foreground_color); - if (is_foreground_color) - { - cairo_set_source (cr, render->foreground_color); - cairo_paint_with_alpha (cr, color.alpha); - } - else - { - cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha); + get_palette_color (render, &solid->color, &color, &colr_alpha, &is_foreground_color); + if (is_foreground_color) { + cairo_set_source (cr, render->foreground_marker); + cairo_paint_with_alpha (cr, colr_alpha); + } else { + cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * colr_alpha); cairo_paint (cr); } @@ -315,6 +316,8 @@ read_colorline (cairo_colr_glyph_render_t *render, cairo_colr_color_line_t *cl; FT_ColorStop stop; int i; + double colr_alpha; + cairo_bool_t is_foreground_color; cl = calloc (1, sizeof (cairo_colr_color_line_t)); if (unlikely (cl == NULL)) @@ -330,7 +333,28 @@ read_colorline (cairo_colr_glyph_render_t *render, i = 0; while (FT_Get_Colorline_Stops (render->face, &stop, &colorline->color_stop_iterator)) { cl->stops[i].position = double_from_16_16 (stop.stop_offset); - get_palette_color (render, &stop.color, &cl->stops[i].color, NULL); + get_palette_color (render, &stop.color, &cl->stops[i].color, &colr_alpha, &is_foreground_color); + if (is_foreground_color) { + double red, green, blue, alpha; + if (cairo_pattern_get_rgba (render->foreground_source, + &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS) + { + cl->stops[i].color.red = red; + cl->stops[i].color.green = green; + cl->stops[i].color.blue = blue; + cl->stops[i].color.alpha = alpha * colr_alpha; + render->foreground_source_used = TRUE; + } + else + { + cl->stops[i].color.red = 0; + cl->stops[i].color.green = 0; + cl->stops[i].color.blue = 0; + cl->stops[i].color.alpha = colr_alpha; + } + } else { + cl->stops[i].color.alpha *= colr_alpha; + } i++; } @@ -1190,7 +1214,9 @@ _cairo_render_colr_v1_glyph (FT_Face face, unsigned long glyph, FT_Color *palette, int num_palette_entries, - cairo_t *cr) + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_colr_glyph_render_t colr_render; @@ -1202,7 +1228,9 @@ _cairo_render_colr_v1_glyph (FT_Face face, colr_render.face = face; colr_render.palette = palette; colr_render.num_palette_entries = num_palette_entries; - colr_render.foreground_color = cairo_pattern_reference (cairo_get_source (cr)); + colr_render.foreground_marker = _cairo_pattern_create_foreground_marker (); + colr_render.foreground_source = cairo_pattern_reference (foreground_source);; + colr_render.foreground_source_used = FALSE; colr_render.level = 0; status = draw_colr_glyph (&colr_render, @@ -1210,7 +1238,9 @@ _cairo_render_colr_v1_glyph (FT_Face face, FT_COLOR_INCLUDE_ROOT_TRANSFORM, cr); - cairo_pattern_destroy (colr_render.foreground_color); + cairo_pattern_destroy (colr_render.foreground_marker); + cairo_pattern_destroy (colr_render.foreground_source); + *foreground_source_used = colr_render.foreground_source_used; return status; } diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index e6a8d20e3..75d6f8c16 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -2707,7 +2707,6 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font, return status; } -#ifdef HAVE_FT_PALETTE_SELECT static cairo_int_status_t _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph, @@ -2715,6 +2714,7 @@ _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled cairo_bool_t vertical_layout, int load_flags) { +#ifdef HAVE_FT_PALETTE_SELECT cairo_surface_t *recording_surface; cairo_t *cr; cairo_status_t status; @@ -2755,8 +2755,7 @@ _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled { cairo_pattern_t *pattern; if (layer_color_index == 0xFFFF) { - pattern = cairo_pattern_create_rgb (0, 0, 0); - pattern->is_userfont_foreground = TRUE; + pattern = _cairo_pattern_create_foreground_marker (); } else { double r = 0, g = 0, b = 0, a = 1; if (layer_color_index < num_palette_entries) { @@ -2800,22 +2799,25 @@ _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled recording_surface, NULL); return status; -} +#else + return CAIRO_INT_STATUS_UNSUPPORTED; #endif +} -#if HAVE_FT_COLR_V1 static cairo_int_status_t _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph, FT_Face face, + const cairo_color_t *foreground_color, cairo_text_extents_t *extents) { +#if HAVE_FT_COLR_V1 cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_surface_t *recording_surface; cairo_t *cr; - cairo_pattern_t *pattern; FT_Color *palette; unsigned int num_palette_entries; + cairo_bool_t foreground_source_used = FALSE; recording_surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); @@ -2827,11 +2829,6 @@ _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled cairo_set_font_size (cr, 1.0); cairo_set_font_options (cr, &scaled_font->base.options); - pattern = cairo_pattern_create_rgb (0, 0, 0); - pattern->is_userfont_foreground = TRUE; - cairo_set_source (cr, pattern); - cairo_pattern_destroy (pattern); - extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin); extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin); extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing; @@ -2840,14 +2837,15 @@ _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette); if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color); status = _cairo_render_colr_v1_glyph (face, _cairo_scaled_glyph_index (scaled_glyph), palette, num_palette_entries, - cr); - if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) - status = CAIRO_INT_STATUS_UNSUPPORTED; - + cr, + foreground_pattern, + &foreground_source_used); + cairo_pattern_destroy (foreground_pattern); if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); } @@ -2864,7 +2862,7 @@ _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled _cairo_scaled_glyph_set_recording_surface (scaled_glyph, &scaled_font->base, recording_surface, - NULL); + foreground_source_used ? foreground_color : NULL); scaled_glyph->color_glyph = TRUE; scaled_glyph->color_glyph_set = TRUE; @@ -2937,24 +2935,27 @@ _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled } return status; -} +#else + return CAIRO_INT_STATUS_UNSUPPORTED; #endif +} -#if HAVE_FT_SVG_DOCUMENT static cairo_int_status_t _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph, FT_Face face, + const cairo_color_t *foreground_color, cairo_text_extents_t *extents) { +#if HAVE_FT_SVG_DOCUMENT cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_surface_t *recording_surface; cairo_t *cr; - cairo_pattern_t *pattern; FT_SVG_Document svg_doc = face->glyph->other; char *svg_document; FT_Color *palette; unsigned int num_palette_entries; + cairo_bool_t foreground_source_used = FALSE; /* Create NULL terminated SVG document */ svg_document = _cairo_strndup ((const char*)svg_doc->svg_document, svg_doc->svg_document_length); @@ -2974,11 +2975,6 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon cairo_set_font_size (cr, 1.0); cairo_set_font_options (cr, &scaled_font->base.options); - pattern = cairo_pattern_create_rgb (0, 0, 0); - pattern->is_userfont_foreground = TRUE; - cairo_set_source (cr, pattern); - cairo_pattern_destroy (pattern); - extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin); extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin); extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing; @@ -2987,6 +2983,7 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette); if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color); status = _cairo_render_svg_glyph (svg_document, svg_doc->start_glyph_id, svg_doc->end_glyph_id, @@ -2994,7 +2991,10 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon svg_doc->units_per_EM, palette, num_palette_entries, - cr); + cr, + foreground_pattern, + &foreground_source_used); + cairo_pattern_destroy (foreground_pattern); if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); } @@ -3012,7 +3012,7 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon _cairo_scaled_glyph_set_recording_surface (scaled_glyph, &scaled_font->base, recording_surface, - NULL); + foreground_source_used ? foreground_color : NULL); scaled_glyph->color_glyph = TRUE; scaled_glyph->color_glyph_set = TRUE; @@ -3085,8 +3085,10 @@ _cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_fon } return status; -} +#else + return CAIRO_INT_STATUS_UNSUPPORTED; #endif +} static cairo_int_status_t _cairo_ft_scaled_glyph_init_surface_for_recording_surface (cairo_ft_scaled_font_t *scaled_font, @@ -3278,11 +3280,12 @@ _cairo_ft_scaled_glyph_is_colr_v1 (cairo_ft_scaled_font_t *scaled_font, static const int ft_glyph_private_key; static cairo_int_status_t -_cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font, - cairo_scaled_glyph_t *scaled_glyph, - FT_Face face, - cairo_bool_t vertical_layout, - int load_flags) +_cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + cairo_bool_t vertical_layout, + int load_flags, + const cairo_color_t *foreground_color) { cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cairo_text_extents_t fs_metrics; @@ -3348,25 +3351,23 @@ _cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font, &fs_metrics); -/* SVG and COLR v1 glyphs require the bounding box to be obtained from - * the ink extents of the rendering. We need to render glyph to a - * recording surface to obtain these extents. But we also need the - * advance from _cairo_ft_scaled_glyph_get_metrics() before calling - * this function. - */ + /* SVG and COLRv1 glyphs require the bounding box to be obtained + * from the ink extents of the rendering. We need to render glyph + * to a recording surface to obtain these extents. But we also + * need the advance from _cairo_ft_scaled_glyph_get_metrics() + * before calling this function. + */ -#if HAVE_FT_SVG_DOCUMENT if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) { status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font, scaled_glyph, face, + foreground_color, &fs_metrics); if (unlikely (status)) return status; } -#endif -#if HAVE_FT_COLR_V1 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) { if (!hint_metrics) { status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, @@ -3382,11 +3383,11 @@ _cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font, status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font, scaled_glyph, face, + foreground_color, &fs_metrics); if (unlikely (status)) return status; } -#endif _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, @@ -3409,6 +3410,11 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, 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; + +#ifdef FT_LOAD_COLOR + color_flag = FT_LOAD_COLOR; +#endif face = _cairo_ft_unscaled_font_lock_face (unscaled); if (!face) @@ -3432,12 +3438,14 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, vertical_layout = TRUE; } + /* Metrics will always be requested when a scaled glyph is created */ if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) { status = _cairo_ft_scaled_glyph_init_metrics (scaled_font, scaled_glyph, face, vertical_layout, - load_flags); + load_flags, + foreground_color); if (unlikely (status)) goto FAIL; } @@ -3447,26 +3455,39 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, assert (glyph_priv != NULL); if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) { - switch (glyph_priv->format) { - case CAIRO_FT_GLYPH_TYPE_BITMAP: - case CAIRO_FT_GLYPH_TYPE_OUTLINE: - break; - case CAIRO_FT_GLYPH_TYPE_SVG: - case CAIRO_FT_GLYPH_TYPE_COLR_V1: - /* The SVG and COLR v1 recording surfaces are - * initialized in _cairo_ft_scaled_glyph_init_metrics() - */ - status = CAIRO_STATUS_SUCCESS; - break; - case CAIRO_FT_GLYPH_TYPE_COLR_V0: -#ifdef HAVE_FT_PALETTE_SELECT + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG || + glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0 || + glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) + { + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags | color_flag, + FALSE, + vertical_layout); + if (unlikely (status)) + goto FAIL; + + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) { + status = _cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &scaled_glyph->fs_metrics); + } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) { + status = _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &scaled_glyph->fs_metrics); + } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0) { status = _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (scaled_font, scaled_glyph, face, vertical_layout, load_flags); -#endif - break; + } } if (status) goto FAIL; @@ -3477,8 +3498,8 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) { status = _cairo_ft_scaled_glyph_init_surface_for_recording_surface (scaled_font, - scaled_glyph, - foreground_color); + scaled_glyph, + foreground_color); } else { status = _cairo_ft_scaled_glyph_init_surface (scaled_font, scaled_glyph, diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h index 312f65454..836f7e523 100644 --- a/src/cairo-ft-private.h +++ b/src/cairo-ft-private.h @@ -1,3 +1,4 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ /* cairo - a vector graphics library with display and print output * * Copyright © 2005 Red Hat, Inc @@ -74,7 +75,9 @@ _cairo_render_svg_glyph (const char *svg_document, double units_per_em, FT_Color *palette, int num_palette_entries, - cairo_t *cr); + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used); #endif #if HAVE_FT_COLR_V1 @@ -83,7 +86,9 @@ _cairo_render_colr_v1_glyph (FT_Face face, unsigned long glyph, FT_Color *palette, int num_palette_entries, - cairo_t *cr); + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used); #endif CAIRO_END_DECLS diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 0d52491c9..0f4fd541a 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -1145,7 +1145,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, } _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); - if (source->type == CAIRO_PATTERN_TYPE_SOLID && + if (source->type == CAIRO_PATTERN_TYPE_SOLID && !source->is_foreground_marker && mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && _cairo_operator_bounded_by_source (op)) { diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h index 0a5e41e8b..d061b39c4 100644 --- a/src/cairo-pattern-private.h +++ b/src/cairo-pattern-private.h @@ -72,7 +72,7 @@ struct _cairo_pattern { cairo_filter_t filter; cairo_extend_t extend; cairo_bool_t has_component_alpha; - cairo_bool_t is_userfont_foreground; + cairo_bool_t is_foreground_marker; cairo_matrix_t matrix; double opacity; @@ -240,6 +240,9 @@ _cairo_pattern_fini (cairo_pattern_t *pattern); cairo_private cairo_pattern_t * _cairo_pattern_create_solid (const cairo_color_t *color); +cairo_private cairo_pattern_t * +_cairo_pattern_create_foreground_marker (void); + cairo_private void _cairo_pattern_transform (cairo_pattern_t *pattern, const cairo_matrix_t *ctm_inverse); diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 070309ac6..d16ed2836 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -76,7 +76,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil = { CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ FALSE, /* has component alpha */ - FALSE, /* is_userfont_foreground */ + FALSE, /* is_foreground_marker */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ } @@ -93,7 +93,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ FALSE, /* has component alpha */ - FALSE, /* is_userfont_foreground */ + FALSE, /* is_foreground_marker */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ } @@ -110,7 +110,7 @@ const cairo_solid_pattern_t _cairo_pattern_black = { CAIRO_FILTER_NEAREST, /* filter */ CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ - FALSE, /* is_userfont_foreground */ + FALSE, /* is_foreground_marker */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -128,7 +128,7 @@ const cairo_solid_pattern_t _cairo_pattern_clear = { CAIRO_FILTER_NEAREST, /* filter */ CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ - FALSE, /* is_userfont_foreground */ + FALSE, /* is_foreground_marker */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -146,7 +146,7 @@ const cairo_solid_pattern_t _cairo_pattern_white = { CAIRO_FILTER_NEAREST, /* filter */ CAIRO_EXTEND_REPEAT, /* extend */ FALSE, /* has component alpha */ - FALSE, /* is_userfont_foreground */ + FALSE, /* is_foreground_marker */ { 1., 0., 0., 1., 0., 0., }, /* matrix */ 1.0 /* opacity */ }, @@ -238,7 +238,7 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) pattern->opacity = 1.0; pattern->has_component_alpha = FALSE; - pattern->is_userfont_foreground = FALSE; + pattern->is_foreground_marker = FALSE; cairo_matrix_init_identity (&pattern->matrix); @@ -625,6 +625,14 @@ _cairo_pattern_create_solid (const cairo_color_t *color) } cairo_pattern_t * +_cairo_pattern_create_foreground_marker (void) +{ + cairo_pattern_t *pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + pattern->is_foreground_marker = TRUE; + return pattern; +} + +cairo_pattern_t * _cairo_pattern_create_in_error (cairo_status_t status) { cairo_pattern_t *pattern; diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c index a7de8df5b..e87320523 100644 --- a/src/cairo-recording-surface.c +++ b/src/cairo-recording-surface.c @@ -2706,7 +2706,7 @@ print_pattern (FILE *file, switch (pattern->type) { case CAIRO_PATTERN_TYPE_SOLID: { cairo_solid_pattern_t *p = (cairo_solid_pattern_t *) pattern; - if (pattern->is_userfont_foreground) { + if (pattern->is_foreground_marker) { fprintf (file, "solid foreground\n"); } else { fprintf (file, "solid rgba: %f %f %f %f\n", diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index 8c10b60c7..64abbe0f5 100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h @@ -150,11 +150,11 @@ struct _cairo_scaled_glyph { cairo_color_t foreground_color; /* only used for color glyphs */ - /* TRUE if the recording_surface required the foreground_color to render. */ + /* TRUE if the recording_surface used the foreground_source to render. */ unsigned recording_uses_foreground_color : 1; - /* TRUE if the color_surface required the foreground_color to render. */ - unsigned image_uses_foreground_color : 1; + /* TRUE if the recording surface uses the foreground marker. */ + unsigned recording_uses_foreground_marker : 1; /* TRUE if color_glyph specifies if glyph is color or non color, FALSE if glyph color type unknown. */ unsigned color_glyph_set : 1; diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index d7e3f1e4b..415b45f78 100755 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -2688,14 +2688,15 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, * @scaled_glyph: a #cairo_scaled_glyph_t * @scaled_font: a #cairo_scaled_font_t * @surface: The image surface - * @foreground_color: The foreground color that was used to render the - * glyph, or NULL if foreground color not required. + * @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. */ void _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font, cairo_image_surface_t *surface, - const cairo_color_t *foreground_color) + const cairo_color_t *foreground_marker_color) { if (scaled_glyph->color_surface != NULL) cairo_surface_destroy (&scaled_glyph->color_surface->base); @@ -2703,9 +2704,9 @@ _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, /* sanity check the backend glyph contents */ _cairo_debug_check_image_surface_is_defined (&surface->base); scaled_glyph->color_surface = surface; - scaled_glyph->image_uses_foreground_color = foreground_color != NULL; - if (foreground_color) - scaled_glyph->foreground_color = *foreground_color; + scaled_glyph->recording_uses_foreground_marker = foreground_marker_color != NULL; + if (foreground_marker_color) + scaled_glyph->foreground_color = *foreground_marker_color; if (surface != NULL) scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; @@ -2935,19 +2936,20 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, return CAIRO_INT_STATUS_UNSUPPORTED; /* If requesting a color surface or recording for a glyph that has - * used the foreground color to render the color_surface, and the - * foreground color has changed, request a new image and/or - * recording. */ - - if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE && + * used the foreground color to render the recording, and the + * foreground color has changed, request a new recording. */ + if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) && scaled_glyph->recording_uses_foreground_color && !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color)) { need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; } + /* If requesting a color surface for a glyph that has + * used the foreground color to render the color_surface, and the + * foreground color has changed, request a new image. */ if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE && - scaled_glyph->image_uses_foreground_color && + (scaled_glyph->recording_uses_foreground_marker || scaled_glyph->recording_uses_foreground_color) && !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color)) { need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 503a9a1c1..e9e6233a6 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -2204,7 +2204,7 @@ _cairo_surface_paint (cairo_surface_t *surface, if (unlikely (status)) return status; - if (source->is_userfont_foreground && surface->foreground_source) { + if (source->is_foreground_marker && surface->foreground_source) { source = surface->foreground_source; surface->foreground_used = TRUE; } @@ -2259,7 +2259,7 @@ _cairo_surface_mask (cairo_surface_t *surface, if (unlikely (status)) return status; - if (source->is_userfont_foreground && surface->foreground_source) { + if (source->is_foreground_marker && surface->foreground_source) { source = surface->foreground_source; surface->foreground_used = TRUE; } @@ -2320,12 +2320,12 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, if (unlikely (status)) return status; - if (fill_source->is_userfont_foreground && surface->foreground_source) { + if (fill_source->is_foreground_marker && surface->foreground_source) { fill_source = surface->foreground_source; surface->foreground_used = TRUE; } - if (stroke_source->is_userfont_foreground && surface->foreground_source) { + if (stroke_source->is_foreground_marker && surface->foreground_source) { stroke_source = surface->foreground_source; surface->foreground_used = TRUE; } @@ -2404,7 +2404,7 @@ _cairo_surface_stroke (cairo_surface_t *surface, if (unlikely (status)) return status; - if (source->is_userfont_foreground && surface->foreground_source) { + if (source->is_foreground_marker && surface->foreground_source) { source = surface->foreground_source; surface->foreground_used = TRUE; } @@ -2454,7 +2454,7 @@ _cairo_surface_fill (cairo_surface_t *surface, if (unlikely (status)) return status; - if (source->is_userfont_foreground && surface->foreground_source) { + if (source->is_foreground_marker && surface->foreground_source) { source = surface->foreground_source; surface->foreground_used = TRUE; } @@ -2944,7 +2944,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (unlikely (status)) return status; - if (source->is_userfont_foreground && surface->foreground_source) + if (source->is_foreground_marker && surface->foreground_source) source = surface->foreground_source; if (_cairo_scaled_font_has_color_glyphs (scaled_font) && diff --git a/src/cairo-svg-glyph-render.c b/src/cairo-svg-glyph-render.c index 9b953687d..3c14f8c59 100644 --- a/src/cairo-svg-glyph-render.c +++ b/src/cairo-svg-glyph-render.c @@ -35,8 +35,9 @@ */ #include "cairoint.h" -#include "cairo-ft-private.h" #include "cairo-array-private.h" +#include "cairo-ft-private.h" +#include "cairo-pattern-private.h" #include "cairo-scaled-font-subsets-private.h" #include <stdarg.h> @@ -239,7 +240,7 @@ typedef struct _cairo_svg_element { } cairo_svg_element_t; typedef struct _cairo_svg_color { - enum { RGB, CURRENT_COLOR } type; + enum { RGB, FOREGROUND } type; double red; double green; double blue; @@ -291,7 +292,6 @@ typedef struct _cairo_svg_glyph_render { cairo_hash_table_t *ids; cairo_svg_graphics_state_t *graphics_state; cairo_t *cr; - cairo_pattern_t *foreground_color; double units_per_em; struct { cairo_svg_element_t *paint_server; @@ -307,6 +307,10 @@ typedef struct _cairo_svg_glyph_render { double height; cairo_bool_t view_port_set; + cairo_pattern_t *foreground_marker; + cairo_pattern_t *foreground_source; + cairo_bool_t foreground_source_used; + int debug; /* 0 = quiet, 1 = errors, 2 = warnings, 3 = info */ } cairo_svg_glyph_render_t; @@ -745,13 +749,13 @@ get_color (cairo_svg_glyph_render_t *svg_render, len = strlen(s); - if (string_equal (s, "inherit") || - string_equal (s, "currentColor") || - string_equal (s, "context-fill") || - string_equal (s, "context-stroke")) + if (string_equal (s, "inherit")) { + return FALSE; + } else if (string_equal (s, "currentColor") || + string_equal (s, "context-fill") || + string_equal (s, "context-stroke")) { - color->type = CURRENT_COLOR; - color->red = color->green = color->blue = 0; + *color = svg_render->graphics_state->color; return TRUE; } else if (len > 0 && s[0] == '#') { if (len == 4) { @@ -810,7 +814,7 @@ get_color (cairo_svg_glyph_render_t *svg_render, end = strpbrk(s, WHITE_SPACE_CHARS ")"); if (!end || end == s) - return FALSE; + return FALSE; char *fallback = _cairo_strndup (s, end - s); cairo_bool_t success = get_color (svg_render, fallback, color); @@ -1710,6 +1714,15 @@ render_element_stop (cairo_svg_glyph_render_t *svg_render, color.green, color.blue, opacity); + } else { /* color.type == FOREGROUND */ + double red, green, blue, alpha; + if (cairo_pattern_get_rgba (svg_render->foreground_source, &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS) { + svg_render->foreground_source_used = TRUE; + } else { + red = green = blue = 0; + alpha = 1; + } + cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, alpha); } return TRUE; } @@ -1906,12 +1919,10 @@ draw_path (cairo_svg_glyph_render_t *svg_render) gs->fill.color.green, gs->fill.color.blue, gs->fill_opacity); - } else if (gs->fill.color.type == CURRENT_COLOR) { - cairo_set_source_rgba (svg_render->cr, - gs->color.red, - gs->color.green, - gs->color.blue, - gs->fill_opacity); + } else if (gs->fill.color.type == FOREGROUND) { + cairo_set_source (svg_render->cr, svg_render->foreground_marker); + if (gs->fill_opacity < 1.0) + group = TRUE; } } else if (gs->fill.type == PAINT_SERVER) { pattern = create_pattern (svg_render, gs->fill.paint_server); @@ -1942,12 +1953,10 @@ draw_path (cairo_svg_glyph_render_t *svg_render) gs->stroke.color.green, gs->stroke.color.blue, gs->stroke_opacity); - } else if (gs->stroke.color.type == CURRENT_COLOR) { - cairo_set_source_rgba (svg_render->cr, - gs->color.red, - gs->color.green, - gs->color.blue, - gs->stroke_opacity); + } else if (gs->fill.color.type == FOREGROUND) { + cairo_set_source (svg_render->cr, svg_render->foreground_marker); + if (gs->fill_opacity < 1.0) + group = TRUE; } } else if (gs->stroke.type == PAINT_SERVER) { pattern = create_pattern (svg_render, gs->stroke.paint_server); @@ -2579,20 +2588,11 @@ static void init_graphics_state (cairo_svg_glyph_render_t *svg_render) { cairo_svg_graphics_state_t *gs; - double alpha; gs = _cairo_malloc (sizeof (cairo_svg_graphics_state_t)); get_paint (svg_render, "black", &gs->fill); get_paint (svg_render, "none", &gs->stroke); - gs->color.type = RGB; - if (cairo_pattern_get_rgba (svg_render->foreground_color, - &gs->color.red, - &gs->color.green, - &gs->color.blue, - &alpha) != CAIRO_STATUS_SUCCESS) - { - get_color (svg_render, "black", &gs->color); - } + gs->color.type = FOREGROUND; gs->fill_opacity = 1.0; gs->stroke_opacity = 1.0; gs->opacity = 1.0; @@ -3096,7 +3096,9 @@ _cairo_render_svg_glyph (const char *svg_document, double units_per_em, FT_Color *palette, int num_palette_entries, - cairo_t *cr) + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used) { cairo_status_t status = CAIRO_STATUS_SUCCESS; @@ -3122,7 +3124,6 @@ _cairo_render_svg_glyph (const char *svg_document, svg_render->cr = cr; svg_render->units_per_em = units_per_em; - svg_render->foreground_color = cairo_pattern_reference (cairo_get_source (cr)); svg_render->build_pattern.paint_server = NULL; svg_render->build_pattern.pattern = NULL; svg_render->build_pattern.type = BUILD_PATTERN_NONE; @@ -3131,6 +3132,10 @@ _cairo_render_svg_glyph (const char *svg_document, svg_render->num_palette_entries = num_palette_entries; svg_render->palette = palette; + svg_render->foreground_marker = _cairo_pattern_create_foreground_marker (); + svg_render->foreground_source = cairo_pattern_reference (foreground_source);; + svg_render->foreground_source_used = FALSE; + init_graphics_state (svg_render); print_info (svg_render, "Glyph ID: %ld", glyph); @@ -3175,7 +3180,9 @@ _cairo_render_svg_glyph (const char *svg_document, while (svg_render->graphics_state) restore_graphics_state (svg_render); - cairo_pattern_destroy (svg_render->foreground_color); + cairo_pattern_destroy (svg_render->foreground_marker); + cairo_pattern_destroy (svg_render->foreground_source); + *foreground_source_used = svg_render->foreground_source_used; /* The hash entry for each element with an id is removed by * free_elements() */ diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c index 913395fd9..e7a1d0211 100644 --- a/src/cairo-user-font.c +++ b/src/cairo-user-font.c @@ -381,20 +381,8 @@ _cairo_user_scaled_glyph_init (void *abstract_font, { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_user_scaled_font_t *scaled_font = abstract_font; - cairo_bool_t need_recording = FALSE; - if (!scaled_glyph->recording_surface) { - need_recording = TRUE; - } else { - if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE|CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) && - scaled_glyph->recording_uses_foreground_color && - !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color)) - { - need_recording = TRUE; - } - } - - if (need_recording) { + if (!scaled_glyph->recording_surface || (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE)) { status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph, foreground_color); if (status) return status; @@ -598,8 +586,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_ } user_scaled_font->foreground_pattern = NULL; - user_scaled_font->foreground_marker = cairo_pattern_create_rgb (0, 0, 0); - user_scaled_font->foreground_marker->is_userfont_foreground = TRUE; + user_scaled_font->foreground_marker = _cairo_pattern_create_foreground_marker (); /* XXX metrics hinting? */ |