[cairo-commit] 2 commits - src/cairo.h src/cairo-pattern.c src/cairo-pattern-private.h src/cairo-recording-surface.c src/cairo-recording-surface-private.h src/cairo-scaled-font-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h src/cairo-user-font.c test/reference test/user-font-color.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Sep 20 09:02:00 UTC 2021


 src/cairo-pattern-private.h                     |    1 
 src/cairo-pattern.c                             |    6 
 src/cairo-recording-surface-private.h           |    5 
 src/cairo-recording-surface.c                   |  149 ++++++++++++++++--------
 src/cairo-scaled-font-private.h                 |    5 
 src/cairo-surface-wrapper-private.h             |    5 
 src/cairo-surface-wrapper.c                     |   33 +++++
 src/cairo-user-font.c                           |   23 ++-
 src/cairo.h                                     |   16 ++
 test/reference/user-font-color.image16.ref.png  |binary
 test/reference/user-font-color.pdf.ref.png      |binary
 test/reference/user-font-color.quartz.ref.png   |binary
 test/reference/user-font-color.ref.png          |binary
 test/reference/user-font-color.script.xfail.png |binary
 test/reference/user-font-color.svg.ref.png      |binary
 test/user-font-color.c                          |    8 -
 16 files changed, 195 insertions(+), 56 deletions(-)

New commits:
commit d87fe096b90005ced23c76f3b44c1a3ad03d9b55
Merge: 4f761bd5a 8ea4ae541
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Sep 20 09:01:58 2021 +0000

    Merge branch 'user-font-foreground-color' into 'master'
    
    Support user fonts that use the foreground color
    
    See merge request cairo/cairo!249

commit 8ea4ae5413bd8ae1497e11a473d173cfc2475ae6
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Mon Aug 30 20:41:18 2021 +0930

    Allow user fonts to use the foreground color

diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index f03dedd9e..f6138fb70 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -72,6 +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_matrix_t		matrix;
     double			opacity;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e7af5ff5e..6bd3edfd8 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -76,6 +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 */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
       1.0                               /* opacity */
     }
@@ -92,6 +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 */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
       1.0                               /* opacity */
     }
@@ -108,6 +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 */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
       1.0                               /* opacity */
     },
@@ -125,6 +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 */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
       1.0                               /* opacity */
     },
@@ -142,6 +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 */
       { 1., 0., 0., 1., 0., 0., },	/* matrix */
       1.0                               /* opacity */
     },
@@ -233,6 +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;
 
     cairo_matrix_init_identity (&pattern->matrix);
 
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index e8d98e8fa..63b7a1de6 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -172,6 +172,11 @@ cairo_private cairo_status_t
 _cairo_recording_surface_replay (cairo_surface_t *surface,
 				 cairo_surface_t *target);
 
+cairo_private cairo_status_t
+_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
+                                                       cairo_surface_t *target,
+                                                       const cairo_color_t *color);
+
 cairo_private cairo_status_t
 _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
 					   const cairo_matrix_t *surface_transform,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 86caf9029..065e62c46 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -96,6 +96,17 @@ typedef enum {
     CAIRO_RECORDING_CREATE_REGIONS
 } cairo_recording_replay_type_t;
 
+typedef struct _cairo_recording_surface_replay_params {
+    const cairo_rectangle_int_t *surface_extents;
+    const cairo_matrix_t *surface_transform;
+    cairo_surface_t	     *target;
+    const cairo_clip_t *target_clip;
+    cairo_bool_t surface_is_unbounded;
+    cairo_recording_replay_type_t type;
+    cairo_recording_region_type_t region;
+    const cairo_color_t *foreground_color;
+} cairo_recording_surface_replay_params_t;
+
 static const cairo_surface_backend_t cairo_recording_surface_backend;
 
 /**
@@ -1782,18 +1793,12 @@ _cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t  *su
 
 static cairo_status_t
 _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
-					  const cairo_rectangle_int_t *surface_extents,
-					  const cairo_matrix_t *surface_transform,
-					  cairo_surface_t	     *target,
-					  const cairo_clip_t *target_clip,
-					  cairo_bool_t surface_is_unbounded,
-					  cairo_recording_replay_type_t type,
-					  cairo_recording_region_type_t region)
+					  cairo_recording_surface_replay_params_t *params)
 {
     cairo_surface_wrapper_t wrapper;
     cairo_command_t **elements;
     cairo_bool_t replay_all =
-	type == CAIRO_RECORDING_CREATE_REGIONS || region == CAIRO_RECORDING_REGION_ALL;
+	params->type == CAIRO_RECORDING_CREATE_REGIONS || params->region == CAIRO_RECORDING_REGION_ALL;
     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
     cairo_rectangle_int_t extents;
     cairo_bool_t use_indices = FALSE;
@@ -1803,8 +1808,8 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
     if (unlikely (surface->base.status))
 	return surface->base.status;
 
-    if (unlikely (target->status))
-	return target->status;
+    if (unlikely (params->target->status))
+	return params->target->status;
 
     if (unlikely (surface->base.finished))
 	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
@@ -1814,19 +1819,20 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 
     assert (_cairo_surface_is_recording (&surface->base));
 
-    _cairo_surface_wrapper_init (&wrapper, target);
-    if (surface_extents)
-	_cairo_surface_wrapper_intersect_extents (&wrapper, surface_extents);
+    _cairo_surface_wrapper_init (&wrapper, params->target);
+    if (params->surface_extents)
+	_cairo_surface_wrapper_intersect_extents (&wrapper, params->surface_extents);
     r = &_cairo_unbounded_rectangle;
-    if (! surface->unbounded && !surface_is_unbounded) {
+    if (! surface->unbounded && !params->surface_is_unbounded) {
 	_cairo_surface_wrapper_intersect_extents (&wrapper, &surface->extents);
 	r = &surface->extents;
     }
-    _cairo_surface_wrapper_set_inverse_transform (&wrapper, surface_transform);
-    _cairo_surface_wrapper_set_clip (&wrapper, target_clip);
+    _cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform);
+    _cairo_surface_wrapper_set_clip (&wrapper, params->target_clip);
+    _cairo_surface_wrapper_set_foreground_color (&wrapper, params->foreground_color);
 
     /* Compute the extents of the target clip in recorded device space */
-    if (! _cairo_surface_wrapper_get_target_extents (&wrapper, surface_is_unbounded, &extents))
+    if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents))
 	goto done;
 
     surface->has_bilevel_alpha = TRUE;
@@ -1843,7 +1849,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
     for (i = 0; i < num_elements; i++) {
 	cairo_command_t *command = elements[use_indices ? surface->indices[i] : i];
 
-	if (! replay_all && command->header.region != region)
+	if (! replay_all && command->header.region != params->region)
 	    continue;
 
 	if (! _cairo_rectangle_intersects (&extents, &command->header.extents)) {
@@ -1857,7 +1863,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						   command->header.op,
 						   &command->paint.source.base,
 						   command->header.clip);
-	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+	    if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 		_cairo_recording_surface_merge_source_attributes (surface,
 								  command->header.op,
 								  &command->paint.source.base);
@@ -1870,7 +1876,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						  &command->mask.source.base,
 						  &command->mask.mask.base,
 						  command->header.clip);
-	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+	    if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 		_cairo_recording_surface_merge_source_attributes (surface,
 								  command->header.op,
 								  &command->mask.source.base);
@@ -1891,7 +1897,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						    command->stroke.tolerance,
 						    command->stroke.antialias,
 						    command->header.clip);
-	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+	    if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 		_cairo_recording_surface_merge_source_attributes (surface,
 								  command->header.op,
 								  &command->stroke.source.base);
@@ -1904,14 +1910,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 		cairo_command_t *stroke_command;
 
 		stroke_command = NULL;
-		if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
+		if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
 		    stroke_command = elements[i + 1];
 
 		if (stroke_command != NULL &&
-		    type == CAIRO_RECORDING_REPLAY &&
-		    region != CAIRO_RECORDING_REGION_ALL)
+		    params->type == CAIRO_RECORDING_REPLAY &&
+		    params->region != CAIRO_RECORDING_REGION_ALL)
 		{
-		    if (stroke_command->header.region != region)
+		    if (stroke_command->header.region != params->region)
 			stroke_command = NULL;
 		}
 
@@ -1937,7 +1943,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 								 stroke_command->stroke.tolerance,
 								 stroke_command->stroke.antialias,
 								 command->header.clip);
-		    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		    if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 			_cairo_recording_surface_merge_source_attributes (surface,
 									  command->header.op,
 									  &command->fill.source.base);
@@ -1957,7 +1963,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 						      command->fill.tolerance,
 						      command->fill.antialias,
 						      command->header.clip);
-		if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+		if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 		    _cairo_recording_surface_merge_source_attributes (surface,
 								      command->header.op,
 								      &command->fill.source.base);
@@ -1975,7 +1981,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 							      command->show_text_glyphs.cluster_flags,
 							      command->show_text_glyphs.scaled_font,
 							      command->header.clip);
-	    if (type == CAIRO_RECORDING_CREATE_REGIONS) {
+	    if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
 		_cairo_recording_surface_merge_source_attributes (surface,
 								  command->header.op,
 								  &command->show_text_glyphs.source.base);
@@ -1997,7 +2003,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 	if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
 	    status = CAIRO_INT_STATUS_SUCCESS;
 
-	if (type == CAIRO_RECORDING_CREATE_REGIONS && command->header.region != CAIRO_RECORDING_REGION_NATIVE) {
+	if (params->type == CAIRO_RECORDING_CREATE_REGIONS && command->header.region != CAIRO_RECORDING_REGION_NATIVE) {
 	    if (status == CAIRO_INT_STATUS_SUCCESS) {
 		command->header.region = CAIRO_RECORDING_REGION_NATIVE;
 	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
@@ -2130,10 +2136,37 @@ cairo_status_t
 _cairo_recording_surface_replay (cairo_surface_t *surface,
 				 cairo_surface_t *target)
 {
-    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, NULL,
-						     target, NULL, FALSE,
-						     CAIRO_RECORDING_REPLAY,
-						     CAIRO_RECORDING_REGION_ALL);
+    cairo_recording_surface_replay_params_t params;
+
+    params.surface_extents = NULL;
+    params.surface_transform = NULL;
+    params.target = target;
+    params.target_clip = NULL;
+    params.surface_is_unbounded = FALSE;
+    params.type = CAIRO_RECORDING_REPLAY;
+    params.region = CAIRO_RECORDING_REGION_ALL;
+    params.foreground_color = NULL;
+
+    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
+}
+
+cairo_status_t
+_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
+                                                       cairo_surface_t *target,
+                                                       const cairo_color_t *color)
+{
+    cairo_recording_surface_replay_params_t params;
+
+    params.surface_extents = NULL;
+    params.surface_transform = NULL;
+    params.target = target;
+    params.target_clip = NULL;
+    params.surface_is_unbounded = FALSE;
+    params.type = CAIRO_RECORDING_REPLAY;
+    params.region = CAIRO_RECORDING_REGION_ALL;
+    params.foreground_color = color;
+
+    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
 }
 
 cairo_status_t
@@ -2142,10 +2175,18 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
 					   cairo_surface_t *target,
 					   const cairo_clip_t *target_clip)
 {
-    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, surface_transform,
-						     target, target_clip, FALSE,
-						     CAIRO_RECORDING_REPLAY,
-						     CAIRO_RECORDING_REGION_ALL);
+    cairo_recording_surface_replay_params_t params;
+
+    params.surface_extents = NULL;
+    params.surface_transform = surface_transform;
+    params.target = target;
+    params.target_clip = target_clip;
+    params.surface_is_unbounded = FALSE;
+    params.type = CAIRO_RECORDING_REPLAY;
+    params.region = CAIRO_RECORDING_REGION_ALL;
+    params.foreground_color = NULL;
+
+    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
 }
 
 /* Replay recording to surface. When the return status of each operation is
@@ -2160,11 +2201,18 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
 						    cairo_surface_t *target,
 						    cairo_bool_t surface_is_unbounded)
 {
-    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, surface_transform,
-						     target, NULL,
-						     surface_is_unbounded,
-						     CAIRO_RECORDING_CREATE_REGIONS,
-						     CAIRO_RECORDING_REGION_ALL);
+    cairo_recording_surface_replay_params_t params;
+
+    params.surface_extents = NULL;
+    params.surface_transform = surface_transform;
+    params.target = target;
+    params.target_clip = NULL;
+    params.surface_is_unbounded = surface_is_unbounded;
+    params.type = CAIRO_RECORDING_CREATE_REGIONS;
+    params.region = CAIRO_RECORDING_REGION_ALL;
+    params.foreground_color = NULL;
+
+    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
 }
 
 cairo_status_t
@@ -2173,11 +2221,18 @@ _cairo_recording_surface_replay_region (cairo_surface_t          *surface,
 					cairo_surface_t          *target,
 					cairo_recording_region_type_t  region)
 {
-    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface,
-						     surface_extents, NULL,
-						     target, NULL, FALSE,
-						     CAIRO_RECORDING_REPLAY,
-						     region);
+    cairo_recording_surface_replay_params_t params;
+
+    params.surface_extents = surface_extents;
+    params.surface_transform = NULL;
+    params.target = target;
+    params.target_clip = NULL;
+    params.surface_is_unbounded = FALSE;
+    params.type = CAIRO_RECORDING_REPLAY;
+    params.region = region;
+    params.foreground_color = NULL;
+
+    return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
 }
 
 static cairo_status_t
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 42e9b0913..3b2fe586d 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -148,13 +148,14 @@ struct _cairo_scaled_glyph {
     cairo_list_t            dev_privates;
 
     cairo_color_t           foreground_color;   /* only used for color glyphs */
-    /* TRUE if the color_surface used the foreground_color to render. */
+    /* TRUE if the color_surface required the foreground_color to render. */
     unsigned                uses_foreground_color : 1;
 
     /* TRUE if this is not a color glyph, FALSE if is a color glyph or unknown.  */
     unsigned                not_color_glyph : 1;
 
-    unsigned                has_color : 1;
+    /* TRUE if recording_surface is a color glyph */
+    unsigned                recording_is_color : 1;
 };
 
 struct _cairo_scaled_glyph_private {
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index 380ba099d..7c3bc56ba 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -53,6 +53,7 @@ struct _cairo_surface_wrapper {
     cairo_bool_t has_extents;
     cairo_rectangle_int_t extents;
     const cairo_clip_t *clip;
+    cairo_pattern_t *foreground_source;
 
     cairo_bool_t needs_transform;
 };
@@ -73,6 +74,10 @@ cairo_private void
 _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
 				 const cairo_clip_t *clip);
 
+cairo_private void
+_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
+                                             const cairo_color_t *color);
+
 cairo_private void
 _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
 
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 7fb417a20..8ba82bd40 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -144,6 +144,9 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
     if (_cairo_clip_is_all_clipped (dev_clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (source->is_userfont_foreground && wrapper->foreground_source)
+        source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
@@ -182,6 +185,9 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
     if (_cairo_clip_is_all_clipped (dev_clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (source->is_userfont_foreground && wrapper->foreground_source)
+        source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
@@ -229,6 +235,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
     if (_cairo_clip_is_all_clipped (dev_clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (source->is_userfont_foreground && wrapper->foreground_source)
+        source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
@@ -297,6 +306,12 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
     if (_cairo_clip_is_all_clipped (dev_clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (fill_source->is_userfont_foreground && wrapper->foreground_source)
+        fill_source = wrapper->foreground_source;
+
+    if (stroke_source->is_userfont_foreground && wrapper->foreground_source)
+        stroke_source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
@@ -362,6 +377,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
     if (_cairo_clip_is_all_clipped (dev_clip))
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
 
+    if (source->is_userfont_foreground && wrapper->foreground_source)
+        source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
@@ -425,6 +443,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
     cairo_surface_get_font_options (wrapper->target, &options);
     cairo_font_options_merge (&options, &scaled_font->options);
 
+    if (source->is_userfont_foreground && wrapper->foreground_source)
+        source = wrapper->foreground_source;
+
     if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 	int i;
@@ -591,6 +612,14 @@ _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
     wrapper->clip = clip;
 }
 
+void
+_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
+                                             const cairo_color_t *color)
+{
+    if (color)
+        wrapper->foreground_source = _cairo_pattern_create_solid (color);
+}
+
 void
 _cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t    *wrapper,
 					 cairo_font_options_t	    *options)
@@ -622,6 +651,7 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
     wrapper->has_extents = FALSE;
     wrapper->extents.x = wrapper->extents.y = 0;
     wrapper->clip = NULL;
+    wrapper->foreground_source = NULL;
 
     wrapper->needs_transform = FALSE;
     if (target) {
@@ -633,6 +663,9 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
 void
 _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
 {
+    if (wrapper->foreground_source)
+        cairo_pattern_destroy (wrapper->foreground_source);
+
     cairo_surface_destroy (wrapper->target);
 }
 
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 47b9f0422..d6427f060 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -171,15 +171,21 @@ _cairo_user_scaled_glyph_init (void			 *abstract_font,
 	    status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
 
 	    if (face->scaled_font_methods.render_color_glyph) {
+		cairo_pattern_t *pattern;
+
 		recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE);
 
 		cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE);
+		pattern = cairo_pattern_create_rgb (0, 0, 0);
+		pattern->is_userfont_foreground = TRUE;
+		cairo_set_source (cr, pattern);
+		cairo_pattern_destroy (pattern);
 		status = face->scaled_font_methods.render_color_glyph ((cairo_scaled_font_t *)scaled_font,
 								       _cairo_scaled_glyph_index(scaled_glyph),
 								       cr, &extents);
 		if (status == CAIRO_INT_STATUS_SUCCESS) {
 		    status = cairo_status (cr);
-		    scaled_glyph->has_color = TRUE;
+		    scaled_glyph->recording_is_color = TRUE;
 		}
 	    }
 
@@ -260,7 +266,7 @@ _cairo_user_scaled_glyph_init (void			 *abstract_font,
 	height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
 	  _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
 
-	if (scaled_glyph->has_color) {
+	if (scaled_glyph->recording_is_color) {
             format = CAIRO_FORMAT_ARGB32;
         } else {
             switch (scaled_font->base.options.antialias) {
@@ -285,20 +291,27 @@ _cairo_user_scaled_glyph_init (void			 *abstract_font,
 	cairo_surface_set_device_offset (surface,
 	                                 - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
 	                                 - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
-	status = _cairo_recording_surface_replay (recording_surface, surface);
+
+	if (scaled_glyph->recording_is_color) {
+	    status = _cairo_recording_surface_replay_with_foreground_color (recording_surface,
+									    surface,
+									    foreground_color);
+	} else {
+	    status = _cairo_recording_surface_replay (recording_surface, surface);
+	}
 
 	if (unlikely (status)) {
 	    cairo_surface_destroy(surface);
 	    return status;
 	}
 
-	if (!scaled_glyph->has_color && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE)) {
+	if (!scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE)) {
             _cairo_scaled_glyph_set_surface (scaled_glyph,
                                              &scaled_font->base,
                                              (cairo_image_surface_t *) surface);
         }
 
-        if (scaled_glyph->has_color && (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) {
+        if (scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) {
             _cairo_scaled_glyph_set_color_surface (scaled_glyph,
                                                    &scaled_font->base,
                                                    (cairo_image_surface_t *)surface,
diff --git a/src/cairo.h b/src/cairo.h
index a3c5bc11f..fb1da4146 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1763,6 +1763,22 @@ typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_
  * cairo_user_font_face_set_render_color_glyph_func(), setting the
  * source is a valid operation.
  *
+ * When this callback is set with
+ * cairo_user_font_face_set_render_color_glyph_func(), the default
+ * source is the current source color of the context that is rendering
+ * the user font. That is, the same color a non-color user font will
+ * be rendered in. In most cases the callback will want to set a
+ * specific color. If the callback wishes to use the current context
+ * color after using another source, it should retain a reference to
+ * the source or use cairo_save()/cairo_restore() prior to changing
+ * the source. Note that the default source contains an internal
+ * marker to indicate that it is to be substituted with the current
+ * context source color when rendered to a surface. Querying the
+ * default source pattern will reveal a solid black color, however
+ * this is not representative of the color that will actually be
+ * used. Similarly, setting a solid black color will render black, not
+ * the current context source when the glyph is painted to a surface.
+ *
  * Other non-default settings on @cr include a font size of 1.0 (given that
  * it is set up to be in font space), and font options corresponding to
  * @scaled_font.
diff --git a/test/reference/user-font-color.image16.ref.png b/test/reference/user-font-color.image16.ref.png
index 8b29f0b38..404fbf948 100644
Binary files a/test/reference/user-font-color.image16.ref.png and b/test/reference/user-font-color.image16.ref.png differ
diff --git a/test/reference/user-font-color.pdf.ref.png b/test/reference/user-font-color.pdf.ref.png
index 849614f0d..674d1a4d6 100644
Binary files a/test/reference/user-font-color.pdf.ref.png and b/test/reference/user-font-color.pdf.ref.png differ
diff --git a/test/reference/user-font-color.quartz.ref.png b/test/reference/user-font-color.quartz.ref.png
index 86ce77e38..fc976e8ea 100644
Binary files a/test/reference/user-font-color.quartz.ref.png and b/test/reference/user-font-color.quartz.ref.png differ
diff --git a/test/reference/user-font-color.ref.png b/test/reference/user-font-color.ref.png
index bce2f000b..c4294c5f7 100644
Binary files a/test/reference/user-font-color.ref.png and b/test/reference/user-font-color.ref.png differ
diff --git a/test/reference/user-font-color.script.xfail.png b/test/reference/user-font-color.script.xfail.png
index 6b1f7ddc6..472a16e16 100644
Binary files a/test/reference/user-font-color.script.xfail.png and b/test/reference/user-font-color.script.xfail.png differ
diff --git a/test/reference/user-font-color.svg.ref.png b/test/reference/user-font-color.svg.ref.png
index 9e9bf7d58..4ce8882f8 100644
Binary files a/test/reference/user-font-color.svg.ref.png and b/test/reference/user-font-color.svg.ref.png differ
diff --git a/test/user-font-color.c b/test/user-font-color.c
index 437e57a27..781d6945d 100644
--- a/test/user-font-color.c
+++ b/test/user-font-color.c
@@ -57,13 +57,15 @@ test_scaled_font_init (cairo_scaled_font_t  *scaled_font,
 static void
 render_glyph_solid (cairo_t *cr, double width, double height, cairo_bool_t color)
 {
+    cairo_pattern_t *pattern = cairo_pattern_reference(cairo_get_source (cr));
+
     if (color)
         cairo_set_source_rgba (cr, 0, 1, 1, 0.5);
     cairo_rectangle (cr, 0, 0, width/2, height/2);
     cairo_fill (cr);
 
     if (color)
-        cairo_set_source_rgba (cr, 1, 0, 1, 0.5);
+        cairo_set_source (cr, pattern);
     cairo_rectangle (cr, width/4, height/4, width/2, height/2);
     cairo_fill (cr);
 
@@ -71,6 +73,8 @@ render_glyph_solid (cairo_t *cr, double width, double height, cairo_bool_t color
         cairo_set_source_rgba (cr, 1, 1, 0, 0.5);
     cairo_rectangle (cr, width/2, height/2, width/2, height/2);
     cairo_fill (cr);
+
+    cairo_pattern_destroy (pattern);
 }
 
 static void
@@ -236,7 +240,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_stroke (cr);
 
     /* text in color */
-    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_set_source_rgb (cr, 0, 0.3, 0);
     cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
     cairo_show_text (cr, text);
 


More information about the cairo-commit mailing list