[cairo-commit] 2 commits - src/cairo-analysis-surface.c src/cairo-cache.c src/cairoint.h src/cairo-paginated-surface.c src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-ps-surface.c src/cairo-recording-surface.c src/cairo-scaled-font-subsets.c src/cairo-scaled-font-subsets-private.h src/cairo-surface-backend-private.h src/cairo-surface.c src/cairo-svg-surface.c src/cairo-type3-glyph-surface.c src/cairo-user-font.c test/reference

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Feb 2 10:58:54 UTC 2023


 dev/null                                        |binary
 src/cairo-analysis-surface.c                    |   11 
 src/cairo-cache.c                               |    7 
 src/cairo-paginated-surface.c                   |    9 
 src/cairo-pdf-surface-private.h                 |   10 
 src/cairo-pdf-surface.c                         |  407 ++++++++++++++++++++++--
 src/cairo-ps-surface.c                          |   13 
 src/cairo-recording-surface.c                   |    9 
 src/cairo-scaled-font-subsets-private.h         |   35 --
 src/cairo-scaled-font-subsets.c                 |   92 ++---
 src/cairo-surface-backend-private.h             |   14 
 src/cairo-surface.c                             |   32 +
 src/cairo-svg-surface.c                         |    8 
 src/cairo-type3-glyph-surface.c                 |   14 
 src/cairo-user-font.c                           |    4 
 src/cairoint.h                                  |    9 
 test/reference/ft-color-font.pdf.xfail.png      |binary
 test/reference/user-font-color.image16.ref.png  |binary
 test/reference/user-font-color.pdf.ref.png      |binary
 test/reference/user-font-color.ps.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.xcb.ref.png      |binary
 test/reference/user-font-color.xlib.ref.png     |binary
 test/reference/user-font.pdf.xfail.png          |binary
 test/reference/user-font.svg.argb32.ref.png     |binary
 test/reference/user-font.svg.rgb24.ref.png      |binary
 28 files changed, 531 insertions(+), 143 deletions(-)

New commits:
commit 00453e9a7dbfcd5a86ccb48a27ee0d74616b88a2
Merge: 9be6429cb 79501baaa
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu Feb 2 10:58:52 2023 +0000

    Merge branch 'pdf-color-fonts' into 'master'
    
    PDF Type 3 color fonts
    
    See merge request cairo/cairo!434

commit 79501baaa19f90954af0dda5910396375d21845e
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Jan 22 15:55:06 2023 +1030

    PDF Type 3 color fonts
    
    This implements Type 3 color fonts for PDF for any font with a
    CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE. This includes user-fonts,
    SVG fonts, and COLR fonts.
    
    Glyphs with foreground colors are not yet implemented as Type 3 glyphs
    and will be rendered as images by cairo-surface.

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 86e10d5b0..0e7ba8a38 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -831,6 +831,14 @@ _cairo_analysis_surface_tag (void	                *abstract_surface,
     return backend_status;
 }
 
+static cairo_bool_t
+_cairo_analysis_surface_supports_color_glyph (void                 *abstract_surface,
+                                              cairo_scaled_font_t  *scaled_font,
+                                              unsigned long         glyph_index)
+{
+    return TRUE;
+}
+
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
 
@@ -865,7 +873,8 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     _cairo_analysis_surface_has_show_text_glyphs,
     _cairo_analysis_surface_show_text_glyphs,
     NULL, /* get_supported_mime_types */
-    _cairo_analysis_surface_tag
+    _cairo_analysis_surface_tag,
+    _cairo_analysis_surface_supports_color_glyph
 };
 
 cairo_surface_t *
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index 96809b585..be1285a20 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -336,3 +336,10 @@ _cairo_hash_bytes (uintptr_t hash,
 	hash = ((hash << 5) + hash) + *bytes++;
     return hash;
 }
+
+uintptr_t
+_cairo_hash_uintptr (uintptr_t hash,
+                     uintptr_t u)
+{
+    return _cairo_hash_bytes (hash, &u, sizeof(u));
+}
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 278c1a641..e079a9a28 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -756,6 +756,14 @@ _cairo_paginated_surface_tag (void			 *abstract_surface,
 			       begin, tag_name, attributes);
 }
 
+static cairo_bool_t
+_cairo_paginated_surface_supports_color_glyph (void                 *abstract_surface,
+                                               cairo_scaled_font_t  *scaled_font,
+                                               unsigned long         glyph_index)
+{
+    return TRUE;
+}
+
 static cairo_surface_t *
 _cairo_paginated_surface_snapshot (void *abstract_other)
 {
@@ -811,4 +819,5 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
     _cairo_paginated_surface_show_text_glyphs,
     _cairo_paginated_surface_get_supported_mime_types,
     _cairo_paginated_surface_tag,
+    _cairo_paginated_surface_supports_color_glyph,
 };
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 0781d9c53..c97affe6b 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -258,6 +258,13 @@ typedef struct _cairo_pdf_interchange {
 
 } cairo_pdf_interchange_t;
 
+typedef struct _cairo_pdf_color_glyph {
+    cairo_hash_entry_t   base;
+    cairo_scaled_font_t *scaled_font;
+    unsigned long        glyph_index;
+    cairo_bool_t         supported;
+} cairo_pdf_color_glyph_t;
+
 /* pdf surface data */
 
 typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
@@ -288,6 +295,7 @@ struct _cairo_pdf_surface {
     cairo_array_t knockout_group;
     cairo_array_t jbig2_global;
     cairo_array_t page_heights;
+    cairo_hash_table_t *color_glyphs;
 
     cairo_scaled_font_subsets_t *font_subsets;
     cairo_array_t fonts;
@@ -335,11 +343,13 @@ struct _cairo_pdf_surface {
 
     cairo_pdf_operators_t pdf_operators;
     cairo_paginated_mode_t paginated_mode;
+    cairo_bool_t type3_replay;
     cairo_bool_t select_pattern_gstate_saved;
 
     cairo_bool_t force_fallbacks;
 
     cairo_operator_t current_operator;
+    cairo_bool_t reset_gs_required;
     cairo_bool_t current_pattern_is_solid_color;
     cairo_bool_t current_color_is_stroke;
     double current_color_red;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 28e01ea5b..772828eb8 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -280,7 +280,8 @@ typedef struct _cairo_pdf_alpha_linear_function {
 } cairo_pdf_alpha_linear_function_t;
 
 static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+			  cairo_bool_t         clear_doc_surfaces);
 
 static void
 _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
@@ -338,6 +339,9 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
 static cairo_bool_t
 _cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
 
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b);
+
 static const cairo_surface_backend_t cairo_pdf_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
 
@@ -485,12 +489,18 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 	goto BAIL0;
     }
 
+    surface->color_glyphs = _cairo_hash_table_create (_cairo_pdf_color_glyph_equal);
+    if (unlikely (surface->color_glyphs == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto BAIL1;
+    }
+
     _cairo_pdf_group_resources_init (&surface->resources);
 
     surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
     if (! surface->font_subsets) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto BAIL1;
+	goto BAIL2;
     }
 
     _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
@@ -499,7 +509,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     surface->pages_resource = _cairo_pdf_surface_new_object (surface);
     if (surface->pages_resource.id == 0) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-        goto BAIL2;
+        goto BAIL3;
     }
 
     surface->struct_tree_root.id = 0;
@@ -515,11 +525,13 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
     _cairo_array_init (&surface->object_stream.objects, sizeof (cairo_xref_stream_object_t));
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+    surface->type3_replay = FALSE;
 
     surface->force_fallbacks = FALSE;
     surface->select_pattern_gstate_saved = FALSE;
     surface->current_pattern_is_solid_color = FALSE;
     surface->current_operator = CAIRO_OPERATOR_OVER;
+    surface->reset_gs_required = FALSE;
     surface->header_emitted = FALSE;
 
     _cairo_surface_clipper_init (&surface->clipper,
@@ -537,7 +549,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 
     status = _cairo_pdf_interchange_init (surface);
     if (unlikely (status))
-	goto BAIL2;
+	goto BAIL3;
 
     surface->page_parent_tree = -1;
     _cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t));
@@ -568,8 +580,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t	*output,
 	return surface->paginated_surface;
     }
 
-BAIL2:
+BAIL3:
     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
+BAIL2:
+    _cairo_hash_table_destroy (surface->color_glyphs);
 BAIL1:
     _cairo_hash_table_destroy (surface->all_surfaces);
 BAIL0:
@@ -998,12 +1012,14 @@ cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface,
 }
 
 static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+			  cairo_bool_t         clear_doc_surfaces)
 {
     int i, size;
     cairo_pdf_pattern_t *pattern;
     cairo_pdf_source_surface_t *src_surface;
     cairo_pdf_smask_group_t *group;
+    cairo_pdf_source_surface_t doc_surface;
 
     size = _cairo_array_num_elements (&surface->page_patterns);
     for (i = 0; i < size; i++) {
@@ -1037,6 +1053,21 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
     if (surface->thumbnail_image)
 	cairo_surface_destroy (&surface->thumbnail_image->base);
     surface->thumbnail_image = NULL;
+
+    if (clear_doc_surfaces) {
+	size = _cairo_array_num_elements (&surface->doc_surfaces);
+	for (i = 0; i < size; i++) {
+	    _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
+	    if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+		cairo_pattern_destroy (doc_surface.raster_pattern);
+	    } else {
+		if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0)
+		    _cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id);
+		cairo_surface_destroy (doc_surface.surface);
+	    }
+	}
+	_cairo_array_truncate (&surface->doc_surfaces, 0);
+    }
 }
 
 static void
@@ -1443,6 +1474,25 @@ _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
     }
 }
 
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b)
+{
+    const cairo_pdf_color_glyph_t *a = key_a;
+    const cairo_pdf_color_glyph_t *b = key_b;
+
+    if (a->scaled_font != b->scaled_font)
+	return FALSE;
+
+    return (a->glyph_index == b->glyph_index);
+}
+
+static void
+_cairo_pdf_color_glyph_init_key (cairo_pdf_color_glyph_t *key)
+{
+    key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->scaled_font);
+    key->base.hash = _cairo_hash_uintptr (key->base.hash, key->glyph_index);
+}
+
 static cairo_int_status_t
 _cairo_pdf_surface_acquire_source_image_from_pattern (cairo_pdf_surface_t          *surface,
 						      const cairo_pattern_t        *pattern,
@@ -2131,7 +2181,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t         *surface,
     surface->group_stream.bbox = *bbox;
 
     /* Reset gstate */
-    _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+    surface->reset_gs_required = TRUE;
     surface->current_pattern_is_solid_color = FALSE;
     surface->current_operator = CAIRO_OPERATOR_OVER;
     _cairo_pdf_operators_reset (&surface->pdf_operators);
@@ -2488,6 +2538,18 @@ _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
     free (surface_entry);
 }
 
+static void
+_cairo_pdf_color_glyph_pluck (void *entry, void *closure)
+{
+    cairo_pdf_color_glyph_t *glyph_entry = entry;
+    cairo_hash_table_t *patterns = closure;
+
+    _cairo_hash_table_remove (patterns, &glyph_entry->base);
+    cairo_scaled_font_destroy (glyph_entry->scaled_font);
+
+    free (glyph_entry);
+}
+
 static cairo_status_t
 _cairo_pdf_surface_finish (void *abstract_surface)
 {
@@ -2496,7 +2558,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     cairo_pdf_resource_t catalog;
     cairo_status_t status, status2;
     int size, i;
-    cairo_pdf_source_surface_t doc_surface;
     cairo_pdf_jbig2_global_t *global;
     char *label;
     cairo_pdf_resource_t xref_res;
@@ -2505,7 +2566,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     if (surface->base.status != CAIRO_STATUS_SUCCESS)
 	goto CLEANUP;
 
-    _cairo_pdf_surface_clear (surface);
+    _cairo_pdf_surface_clear (surface, FALSE);
 
     status = _cairo_pdf_surface_open_object_stream (surface);
     if (unlikely (status))
@@ -2514,10 +2575,17 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     /* Emit unbounded surfaces */
     _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
 
+    _cairo_pdf_surface_clear (surface, TRUE);
+
     status = surface->base.status;
     if (status == CAIRO_STATUS_SUCCESS)
 	status = _cairo_pdf_surface_emit_font_subsets (surface);
 
+    /* Emit any new patterns or surfaces created by the Type 3 font subset. */
+    _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
+
+    _cairo_pdf_surface_clear (surface, TRUE);
+
     status = _cairo_pdf_surface_write_pages (surface);
     if (unlikely (status))
 	return status;
@@ -2608,17 +2676,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     _cairo_array_fini (&surface->page_surfaces);
     _cairo_array_fini (&surface->object_stream.objects);
 
-    size = _cairo_array_num_elements (&surface->doc_surfaces);
-    for (i = 0; i < size; i++) {
-	_cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
-	if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
-	    cairo_pattern_destroy (doc_surface.raster_pattern);
-	} else {
-	    if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0)
-		_cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id);
-	    cairo_surface_destroy (doc_surface.surface);
-	}
-    }
     _cairo_array_fini (&surface->doc_surfaces);
     _cairo_hash_table_foreach (surface->all_surfaces,
 			       _cairo_pdf_source_surface_entry_pluck,
@@ -2630,6 +2687,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
     _cairo_array_fini (&surface->page_annots);
     _cairo_array_fini (&surface->forward_links);
 
+     _cairo_hash_table_foreach (surface->color_glyphs,
+				_cairo_pdf_color_glyph_pluck,
+				surface->color_glyphs);
+     _cairo_hash_table_destroy (surface->color_glyphs);
+
     if (surface->font_subsets) {
 	_cairo_scaled_font_subsets_destroy (surface->font_subsets);
 	surface->font_subsets = NULL;
@@ -3727,7 +3789,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t        *surface,
 	goto err;
 
     /* Reset gstate */
-    _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+    surface->reset_gs_required = TRUE;
 
     if (source->content == CAIRO_CONTENT_COLOR) {
 	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
@@ -5080,6 +5142,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t          *surface,
 							alpha != 1.0, /* need_transp_group */
 							extents,
 							smask_res,
+
 							&pdf_source,
 							&x_offset,
 							&y_offset,
@@ -5267,6 +5330,11 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
 {
     cairo_int_status_t status;
 
+    if (surface->reset_gs_required) {
+	_cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+	surface->reset_gs_required = FALSE;
+    }
+
     if (op == surface->current_operator)
 	return CAIRO_STATUS_SUCCESS;
 
@@ -5430,7 +5498,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
     if (unlikely (status))
 	return status;
 
-    _cairo_pdf_surface_clear (surface);
+    _cairo_pdf_surface_clear (surface, FALSE);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -6479,6 +6547,208 @@ _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
     return _cairo_output_stream_get_status (stream);
 }
 
+static cairo_int_status_t
+cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface,
+				    cairo_scaled_font_t *scaled_font,
+				    unsigned long	 glyph_index,
+				    cairo_box_t         *bbox,
+				    double              *width)
+{
+    cairo_rectangle_int_t extents;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_matrix_t mat;
+    cairo_int_status_t status;
+    double x_advance, y_advance;
+    cairo_matrix_t font_matrix_inverse;
+    cairo_surface_t *analysis;
+    cairo_rectangle_int_t old_surface_extents;
+    cairo_bool_t old_surface_bounded;
+    cairo_paginated_mode_t old_paginated_mode;
+    cairo_surface_t *glyph_surface = NULL;
+    unsigned int regions_id = 0;
+    cairo_surface_pattern_t surface_pattern;
+
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+					 NULL, /* foreground color */
+					 &scaled_glyph);
+    if (status == CAIRO_INT_STATUS_SUCCESS)
+	glyph_surface = cairo_surface_reference (scaled_glyph->recording_surface);
+
+    _cairo_scaled_font_thaw_cache (scaled_font);
+    if (unlikely (status))
+	return status;
+
+    analysis = _cairo_analysis_surface_create (&surface->base, TRUE);
+    if (unlikely (analysis->status)) {
+	status = _cairo_surface_set_error (&surface->base, analysis->status);
+	goto cleanup;
+    }
+
+    extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+    extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+    extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+    extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
+
+    old_surface_extents = surface->surface_extents;
+    old_surface_bounded = surface->surface_bounded;
+    old_paginated_mode = surface->paginated_mode;
+    surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+    surface->type3_replay = TRUE;
+    surface->surface_extents = extents;
+    surface->surface_bounded = TRUE;
+
+    status = _cairo_recording_surface_region_array_attach (glyph_surface, &regions_id);
+    if (status)
+	goto cleanup;
+
+    status = _cairo_recording_surface_replay_and_create_regions (glyph_surface, regions_id,
+                                                                 NULL, analysis, TRUE);
+    if (status)
+	goto cleanup;
+
+    surface->surface_extents = old_surface_extents;
+    surface->surface_bounded = old_surface_bounded;
+    surface->paginated_mode = old_paginated_mode;
+    surface->type3_replay = FALSE;
+
+    if (status ==  CAIRO_INT_STATUS_SUCCESS &&
+	_cairo_analysis_surface_has_unsupported (analysis))
+    {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    cairo_surface_destroy (analysis);
+    if (status)
+	goto cleanup;
+
+    _cairo_pattern_init_for_surface (&surface_pattern, glyph_surface);
+    surface_pattern.region_array_id = regions_id;
+
+    cairo_matrix_init_identity (&mat);
+    cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+
+    /* transform glyph extents to operation space */
+    cairo_box_t box;
+    _cairo_box_from_rectangle (&box, &extents);
+    _cairo_matrix_transform_bounding_box_fixed (&mat, &box, NULL);
+    _cairo_box_round_to_rectangle (&box, &extents);
+
+    status = cairo_matrix_invert (&mat);
+    if (status) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto cleanup;
+    }
+
+    cairo_pattern_set_matrix (&surface_pattern.base, &mat);
+
+    x_advance = scaled_glyph->metrics.x_advance;
+    y_advance = scaled_glyph->metrics.y_advance;
+    font_matrix_inverse = scaled_font->font_matrix;
+    status = cairo_matrix_invert (&font_matrix_inverse);
+    if (status) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto cleanup;
+    }
+
+    cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+    *width = x_advance;
+
+    *bbox = scaled_glyph->bbox;
+    _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+						bbox, NULL);
+
+    _cairo_output_stream_printf (surface->output,
+				 "%f 0 d0\n",
+				 x_advance);
+
+    _cairo_pdf_surface_paint_surface_pattern (surface,
+					      CAIRO_OPERATOR_OVER,
+					      &surface_pattern.base,
+					      &extents,
+					      1.0, /* alpha */
+					      NULL, /* smask_res */
+					      FALSE); /* mask */
+
+  cleanup:
+    cairo_surface_destroy (glyph_surface);
+
+    return status;
+}
+
+static cairo_int_status_t
+cairo_pdf_surface_emit_color_glyph_image (cairo_pdf_surface_t *surface,
+					  cairo_scaled_font_t *scaled_font,
+					  unsigned long	       glyph_index,
+					  cairo_box_t         *bbox,
+					  double              *width)
+{
+    cairo_rectangle_int_t extents;
+    cairo_pattern_t *image_pattern;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_matrix_t mat;
+    cairo_int_status_t status, status2;
+    double x_advance, y_advance;
+    cairo_matrix_t font_matrix_inverse;
+
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+					 NULL, /* foreground color */
+					 &scaled_glyph);
+    if (unlikely (status))
+	goto FAIL;
+
+    extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+    extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+    extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+    extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
+
+    image_pattern = cairo_pattern_create_for_surface (&scaled_glyph->color_surface->base);
+
+    cairo_matrix_init_translate (&mat, extents.x, extents.y);
+    cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+    status2 = cairo_matrix_invert (&mat);
+    cairo_pattern_set_matrix (image_pattern, &mat);
+
+    x_advance = scaled_glyph->metrics.x_advance;
+    y_advance = scaled_glyph->metrics.y_advance;
+    font_matrix_inverse = scaled_font->font_matrix;
+    status2 = cairo_matrix_invert (&font_matrix_inverse);
+
+    /* The invertability of font_matrix is tested in
+     * pdf_operators_show_glyphs before any glyphs are mapped to the
+     * subset. */
+    assert (status2 == CAIRO_INT_STATUS_SUCCESS);
+
+    cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+    *width = x_advance;
+
+    *bbox = scaled_glyph->bbox;
+    _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+						bbox, NULL);
+
+    _cairo_output_stream_printf (surface->output,
+				 "%f 0 d0\n",
+				 x_advance);
+
+    _cairo_pdf_surface_paint_surface_pattern (surface,
+					      CAIRO_OPERATOR_OVER,
+					      image_pattern,
+					      &extents,
+					      1.0, /* alpha */
+					      NULL, /* smask_res */
+					      FALSE); /* mask */
+    cairo_pattern_destroy (image_pattern);
+  FAIL:
+    _cairo_scaled_font_thaw_cache (scaled_font);
+
+    return status;
+}
+
 static cairo_int_status_t
 _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t		*surface,
 					   cairo_scaled_font_subset_t	*font_subset)
@@ -6541,6 +6811,20 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t		*surface,
 							font_subset->glyphs[i],
 							&bbox,
 							&widths[i]);
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    status = cairo_pdf_surface_emit_color_glyph (surface,
+							 font_subset->scaled_font,
+							 font_subset->glyphs[i],
+							 &bbox,
+							 &widths[i]);
+	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+		status = cairo_pdf_surface_emit_color_glyph_image (surface,
+								   font_subset->scaled_font,
+								   font_subset->glyphs[i],
+								   &bbox,
+								   &widths[i]);
+	    }
+	}
 	if (unlikely (status))
 	    break;
 
@@ -6725,12 +7009,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
     status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
                                                         _cairo_pdf_surface_emit_scaled_font_subset,
                                                         surface);
-    if (unlikely (status))
-	goto BAIL;
-
-    status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
-						      _cairo_pdf_surface_emit_scaled_font_subset,
-						      surface);
 
 BAIL:
     _cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -7627,6 +7905,9 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
     /* The SOURCE operator is supported if the pattern is opaque or if
      * there is nothing painted underneath. */
     if (op == CAIRO_OPERATOR_SOURCE) {
+	if (surface->type3_replay)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
@@ -8762,6 +9043,13 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
 	return status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	/* Enabling text in Type 3 fonts currently crashes cairo. Most
+	 * PDF viewers don't seem to suport text in Type 3 so we let
+	 * this go to image fallback.
+	 */
+	if (surface->type3_replay)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 	status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
 	goto cleanup;
     }
@@ -8915,6 +9203,68 @@ _cairo_pdf_surface_tag (void			   *abstract_surface,
     return status;
 }
 
+/* The Type 3 font subset support will the embed the
+ * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE image if vector operations
+ * are not supported. The only case we don't currently handle is if a
+ * foreground color is used.
+ */
+static cairo_bool_t
+_cairo_pdf_surface_supports_color_glyph (void                  *abstract_surface,
+					 cairo_scaled_font_t   *scaled_font,
+					 unsigned long          glyph_index)
+{
+    cairo_pdf_surface_t *surface = abstract_surface;
+    cairo_pdf_color_glyph_t glyph_key;
+    cairo_pdf_color_glyph_t *glyph_entry;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_status_t status;
+
+    glyph_key.scaled_font = scaled_font;
+    glyph_key.glyph_index = glyph_index;
+
+    _cairo_pdf_color_glyph_init_key (&glyph_key);
+    glyph_entry = _cairo_hash_table_lookup (surface->color_glyphs, &glyph_key.base);
+    if (glyph_entry)
+	return glyph_entry->supported;
+
+    glyph_entry = _cairo_malloc (sizeof (cairo_pdf_color_glyph_t));
+    if (glyph_entry == NULL) {
+	status = _cairo_surface_set_error (&surface->base,
+					   _cairo_error (CAIRO_STATUS_NO_MEMORY));
+        return FALSE;
+    }
+
+    glyph_entry->scaled_font = cairo_scaled_font_reference (scaled_font);
+    glyph_entry->glyph_index = glyph_index;
+    _cairo_pdf_color_glyph_init_key (glyph_entry);
+
+    glyph_entry->supported = FALSE;
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+					 NULL, /* foreground color */
+					 &scaled_glyph);
+    if (unlikely (status))
+	goto done;
+
+    glyph_entry->supported = !(scaled_glyph->recording_uses_foreground_color ||
+			       scaled_glyph->recording_uses_foreground_marker);
+
+  done:
+    _cairo_scaled_font_thaw_cache (scaled_font);
+
+    status = _cairo_hash_table_insert (surface->color_glyphs,
+				       &glyph_entry->base);
+    if (unlikely(status)) {
+	status = _cairo_surface_set_error (&surface->base,
+					   _cairo_error (CAIRO_STATUS_NO_MEMORY));
+        return FALSE;
+    }
+
+    return glyph_entry->supported;
+}
+
 static cairo_int_status_t
 _cairo_pdf_surface_set_paginated_mode (void			*abstract_surface,
 				       cairo_paginated_mode_t	 paginated_mode)
@@ -8973,6 +9323,7 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     _cairo_pdf_surface_show_text_glyphs,
     _cairo_pdf_surface_get_supported_mime_types,
     _cairo_pdf_surface_tag,
+    _cairo_pdf_surface_supports_color_glyph,
 };
 
 static const cairo_paginated_surface_backend_t
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a37af4c5a..abc9407ee 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -912,18 +912,11 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
     if (unlikely (status))
 	return status;
 
-    status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
-                                                        _cairo_ps_surface_emit_scaled_font_subset,
-                                                        surface);
-    if (unlikely (status))
-	return status;
-
-    return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
-						    _cairo_ps_surface_emit_scaled_font_subset,
-						    surface);
+    return _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
+						      _cairo_ps_surface_emit_scaled_font_subset,
+						      surface);
 }
 
-
 static cairo_int_status_t
 _cairo_ps_surface_emit_forms (cairo_ps_surface_t *surface)
 {
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index e87320523..158ea16ba 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -1231,6 +1231,14 @@ _cairo_recording_surface_tag (void			 *abstract_surface,
     return status;
 }
 
+static cairo_bool_t
+_cairo_recording_surface_supports_color_glyph (void                 *abstract_surface,
+                                               cairo_scaled_font_t  *scaled_font,
+                                               unsigned long         glyph_index)
+{
+    return TRUE;
+}
+
 static void
 _command_init_copy (cairo_recording_surface_t *surface,
 		    cairo_command_header_t *dst,
@@ -1703,6 +1711,7 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
     _cairo_recording_surface_show_text_glyphs,
     NULL, /* get_supported_mime_types */
     _cairo_recording_surface_tag,
+    _cairo_recording_surface_supports_color_glyph,
 };
 
 static unsigned int
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 5b531d298..4ba7cbee5 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -296,41 +296,6 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
                                              cairo_scaled_font_subset_callback_func_t  font_subset_callback,
 				             void				      *closure);
 
-/**
- * _cairo_scaled_font_subsets_foreach_user:
- * @font_subsets: a #cairo_scaled_font_subsets_t
- * @font_subset_callback: a function to be called for each font subset
- * @closure: closure data for the callback function
- *
- * Iterate over each unique scaled font subset as created by calls to
- * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
- * unique pairs of (font_id, subset_id) as returned by
- * _cairo_scaled_font_subsets_map_glyph().
- *
- * For each subset, @font_subset_callback will be called and will be
- * provided with both a #cairo_scaled_font_subset_t object containing
- * all the glyphs in the subset as well as the value of @closure.
- *
- * The #cairo_scaled_font_subset_t object contains the scaled_font,
- * the font_id, and the subset_id corresponding to all glyphs
- * belonging to the subset. In addition, it contains an array providing
- * a mapping between subset glyph indices and the original scaled font
- * glyph indices.
- *
- * The index of the array corresponds to subset_glyph_index values
- * returned by _cairo_scaled_font_subsets_map_glyph() while the
- * values of the array correspond to the scaled_font_glyph_index
- * values passed as input to the same function.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
- * value indicating an error. Possible errors include
- * %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_private cairo_status_t
-_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t		  *font_subsets,
-					 cairo_scaled_font_subset_callback_func_t  font_subset_callback,
-					 void					  *closure);
-
 /**
  * _cairo_scaled_font_subset_create_glyph_names:
  * @font_subsets: a #cairo_scaled_font_subsets_t
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index c5ba12665..2a9e8144c 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -62,7 +62,6 @@ typedef enum {
 typedef enum {
     CAIRO_SUBSETS_FOREACH_UNSCALED,
     CAIRO_SUBSETS_FOREACH_SCALED,
-    CAIRO_SUBSETS_FOREACH_USER
 } cairo_subsets_foreach_type_t;
 
 typedef struct _cairo_sub_font {
@@ -70,7 +69,6 @@ typedef struct _cairo_sub_font {
 
     cairo_bool_t is_scaled;
     cairo_bool_t is_composite;
-    cairo_bool_t is_user;
     cairo_bool_t use_latin_subset;
     cairo_bool_t reserve_notdef;
     cairo_scaled_font_subsets_t *parent;
@@ -284,8 +282,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
 
     sub_font->is_scaled = is_scaled;
     sub_font->is_composite = is_composite;
-    sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
-    sub_font->reserve_notdef = !sub_font->is_user;
+    sub_font->reserve_notdef = !sub_font->is_scaled;
     _cairo_sub_font_init_key (sub_font, scaled_font);
 
     sub_font->parent = parent;
@@ -295,7 +292,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
     sub_font->use_latin_subset = parent->use_latin_subset;
 
     /* latin subsets of Type 3 and CID CFF fonts are not supported */
-    if (sub_font->is_user || sub_font->is_scaled ||
+    if (sub_font->is_scaled ||
 	_cairo_cff_scaled_font_is_cid_cff (scaled_font) )
     {
 	sub_font->use_latin_subset = FALSE;
@@ -620,12 +617,11 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
 	    }
 	}
 
-	/* If glyph is in the winansi encoding and font is not a user
+	/* If glyph is in the winansi encoding and font is not a scaled
 	 * font, put glyph in the latin subset. */
 	is_latin = FALSE;
 	latin_character = -1;
-	if (sub_font->use_latin_subset &&
-	    (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
+	if (sub_font->use_latin_subset && !sub_font->is_scaled)
 	{
 	    latin_character = _cairo_unicode_to_winansi (font_unicode);
 	    if (latin_character > 0)
@@ -839,6 +835,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
     cairo_int_status_t status;
     int max_glyphs;
     cairo_bool_t type1_font;
+    cairo_bool_t has_path;
+    cairo_bool_t has_color;
+    cairo_bool_t is_user;
 
     /* Lookup glyph in unscaled subsets */
     if (subsets->type != CAIRO_SUBSETS_SCALED) {
@@ -872,30 +871,47 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
 
     /* Glyph not found. Determine whether the glyph is outline or
      * bitmap and add to the appropriate subset.
-     *
-     * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
+     */
+    is_user = _cairo_font_face_is_user (scaled_font->font_face);
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    /* Check if glyph is color */
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 scaled_font_glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+					 NULL, /* foreground color */
+					 &scaled_glyph);
+    has_color = (status == CAIRO_INT_STATUS_SUCCESS);
+
+    /* Check if glyph has a path */
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 scaled_font_glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_PATH,
+					 NULL, /* foreground color */
+					 &scaled_glyph);
+    has_path = (status == CAIRO_INT_STATUS_SUCCESS);
+
+    /* glyph_index 0 (the .notdef glyph) is a special case. Some fonts
      * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
      * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
      * empty glyphs in this case so we can put the glyph in a unscaled
-     * subset. */
-    if (scaled_font_glyph_index == 0 ||
-	_cairo_font_face_is_user (scaled_font->font_face)) {
-	status = CAIRO_STATUS_SUCCESS;
-    } else {
-	_cairo_scaled_font_freeze_cache (scaled_font);
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     scaled_font_glyph_index,
-					     CAIRO_SCALED_GLYPH_INFO_PATH,
+     * subset.
+     */
+    if (scaled_font_glyph_index == 0 && !is_user)
+        has_path = TRUE;
+
+    /* If this fails there is nothing we can do with this glyph. */
+    status = _cairo_scaled_glyph_lookup (scaled_font,
+					 scaled_font_glyph_index,
+					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
                                              NULL, /* foreground color */
-					     &scaled_glyph);
-	_cairo_scaled_font_thaw_cache (scaled_font);
-    }
+					 &scaled_glyph);
+    _cairo_scaled_font_thaw_cache (scaled_font);
     if (_cairo_int_status_is_error (status))
         return status;
 
-    if (status == CAIRO_INT_STATUS_SUCCESS &&
-	subsets->type != CAIRO_SUBSETS_SCALED &&
-	! _cairo_font_face_is_user (scaled_font->font_face))
+    /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */
+    if (subsets->type != CAIRO_SUBSETS_SCALED &&
+	has_path && !has_color && !is_user)
     {
         /* Path available. Add to unscaled subset. */
         key.is_scaled = FALSE;
@@ -1007,19 +1023,12 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
 {
     cairo_sub_font_collection_t collection;
     cairo_sub_font_t *sub_font;
-    cairo_bool_t is_scaled, is_user;
+    cairo_bool_t is_scaled;
 
     is_scaled = FALSE;
-    is_user = FALSE;
 
-    if (type == CAIRO_SUBSETS_FOREACH_USER)
-	is_user = TRUE;
-
-    if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
-	type == CAIRO_SUBSETS_FOREACH_USER)
-    {
+    if (type == CAIRO_SUBSETS_FOREACH_SCALED)
 	is_scaled = TRUE;
-    }
 
     if (is_scaled)
         collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
@@ -1055,9 +1064,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
 	sub_font = font_subsets->unscaled_sub_fonts_list;
 
     while (sub_font) {
-	if (sub_font->is_user == is_user)
-	    _cairo_sub_font_collect (sub_font, &collection);
-
+	_cairo_sub_font_collect (sub_font, &collection);
 	sub_font = sub_font->next;
     }
     free (collection.utf8);
@@ -1090,17 +1097,6 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t	    *fo
 							CAIRO_SUBSETS_FOREACH_UNSCALED);
 }
 
-cairo_status_t
-_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t		  *font_subsets,
-					 cairo_scaled_font_subset_callback_func_t  font_subset_callback,
-					 void					  *closure)
-{
-    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
-                                                        font_subset_callback,
-                                                        closure,
-							CAIRO_SUBSETS_FOREACH_USER);
-}
-
 static cairo_bool_t
 _cairo_string_equal (const void *key_a, const void *key_b)
 {
diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h
index d31655be8..15032de20 100644
--- a/src/cairo-surface-backend-private.h
+++ b/src/cairo-surface-backend-private.h
@@ -124,14 +124,14 @@ struct _cairo_surface_backend {
     (*paint)			(void			*surface,
 				 cairo_operator_t	 op,
 				 const cairo_pattern_t	*source,
-				 const cairo_clip_t		*clip);
+				 const cairo_clip_t	*clip);
 
     cairo_warn cairo_int_status_t
     (*mask)			(void			*surface,
 				 cairo_operator_t	 op,
 				 const cairo_pattern_t	*source,
 				 const cairo_pattern_t	*mask,
-				 const cairo_clip_t		*clip);
+				 const cairo_clip_t	*clip);
 
     cairo_warn cairo_int_status_t
     (*stroke)			(void			*surface,
@@ -143,7 +143,7 @@ struct _cairo_surface_backend {
 				 const cairo_matrix_t	*ctm_inverse,
 				 double			 tolerance,
 				 cairo_antialias_t	 antialias,
-				 const cairo_clip_t		*clip);
+				 const cairo_clip_t	*clip);
 
     cairo_warn cairo_int_status_t
     (*fill)			(void			*surface,
@@ -153,7 +153,7 @@ struct _cairo_surface_backend {
 				 cairo_fill_rule_t	 fill_rule,
 				 double			 tolerance,
 				 cairo_antialias_t	 antialias,
-				 const cairo_clip_t           *clip);
+				 const cairo_clip_t     *clip);
 
     cairo_warn cairo_int_status_t
     (*fill_stroke)		(void			*surface,
@@ -196,7 +196,7 @@ struct _cairo_surface_backend {
 				 int			     num_clusters,
 				 cairo_text_cluster_flags_t  cluster_flags,
 				 cairo_scaled_font_t	    *scaled_font,
-				 const cairo_clip_t               *clip);
+				 const cairo_clip_t         *clip);
 
     const char **
     (*get_supported_mime_types)	(void			    *surface);
@@ -207,6 +207,10 @@ struct _cairo_surface_backend {
 				 const char             *tag_name,
 				 const char             *attributes);
 
+    cairo_bool_t
+    (*supports_color_glyph) (void                       *surface,
+                             cairo_scaled_font_t        *scaled_font,
+                             unsigned long               glyph_index);
 };
 
 cairo_private cairo_status_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e9e6233a6..609eb9ccf 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2795,9 +2795,21 @@ composite_color_glyphs (cairo_surface_t             *surface,
                     goto UNLOCK;
 
                 if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) {
-                    skip_cluster = FALSE;
-                    break;
-                }
+		    cairo_bool_t supports_color_glyph = FALSE;
+
+		    if (surface->backend->supports_color_glyph) {
+			_cairo_scaled_font_thaw_cache (scaled_font);
+			supports_color_glyph = _cairo_surface_supports_color_glyph (surface, scaled_font, glyphs[gp].index);
+
+			memset (glyph_cache, 0, sizeof (glyph_cache));
+			_cairo_scaled_font_freeze_cache (scaled_font);
+		    }
+
+		    if (!supports_color_glyph) {
+			skip_cluster = FALSE;
+			break;
+		    }
+		}
             }
 
             if (skip_cluster) {
@@ -2967,9 +2979,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
 
         if (num_glyphs == 0)
             goto DONE;
-    }
-    else
+    } else {
       utf8_copy = NULL;
+    }
 
     /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
      * show_text_glyphs.  Keep in synch. */
@@ -3057,6 +3069,16 @@ _cairo_surface_tag (cairo_surface_t	        *surface,
     return _cairo_surface_set_error (surface, status);
 }
 
+cairo_bool_t
+_cairo_surface_supports_color_glyph (cairo_surface_t       *surface,
+				     cairo_scaled_font_t   *scaled_font,
+				     unsigned long          glyph_index)
+{
+    if (surface->backend->supports_color_glyph != NULL)
+	return surface->backend->supports_color_glyph (surface, scaled_font, glyph_index);
+
+    return FALSE;
+}
 
 /**
  * _cairo_surface_set_resolution:
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index b39a94a37..b7212a547 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1555,14 +1555,6 @@ _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
     status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets,
                                                         _cairo_svg_document_emit_font_subset,
                                                         document);
-    if (unlikely (status))
-	goto FAIL;
-
-    status = _cairo_scaled_font_subsets_foreach_user (document->font_subsets,
-						      _cairo_svg_document_emit_font_subset,
-						      document);
-
-  FAIL:
     _cairo_scaled_font_subsets_destroy (document->font_subsets);
     document->font_subsets = NULL;
 
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index c0971e102..53c029493 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -457,12 +457,22 @@ _cairo_type3_glyph_surface_emit_glyph (void		     *abstract_surface,
     _cairo_type3_glyph_surface_set_stream (surface, stream);
 
     _cairo_scaled_font_freeze_cache (surface->scaled_font);
+
+    /* Check if this is a color glyph and bail out if it is */
     status = _cairo_scaled_glyph_lookup (surface->scaled_font,
 					 glyph_index,
-					 CAIRO_SCALED_GLYPH_INFO_METRICS |
-					 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+					 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
 					 NULL, /* foreground color */
 					 &scaled_glyph);
+    if (status == CAIRO_INT_STATUS_SUCCESS) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto FAIL;
+    } status = _cairo_scaled_glyph_lookup (surface->scaled_font,
+					   glyph_index,
+					   CAIRO_SCALED_GLYPH_INFO_METRICS |
+					   CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+					   NULL, /* foreground color */
+					   &scaled_glyph);
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 	status = _cairo_scaled_glyph_lookup (surface->scaled_font,
 					     glyph_index,
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index e7a1d0211..ee11d864c 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -183,7 +183,9 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
     } else {
 	status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
 
-	if (face->scaled_font_methods.render_color_glyph) {
+	if (face->scaled_font_methods.render_color_glyph &&
+	    scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
+	{
 	    recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE, foreground_color);
 
 	    cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE);
diff --git a/src/cairoint.h b/src/cairoint.h
index 1e8c02fb3..5ce747ee4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -406,6 +406,10 @@ _cairo_hash_bytes (uintptr_t hash,
 		   const void *bytes,
 		   unsigned int length);
 
+cairo_private uintptr_t
+_cairo_hash_uintptr (uintptr_t hash,
+                     uintptr_t u);
+
 /* We use bits 24-27 to store phases for subpixel positions */
 #define _cairo_scaled_glyph_index(g) ((unsigned long)((g)->hash_entry.hash & 0xffffff))
 #define _cairo_scaled_glyph_xphase(g) (int)(((g)->hash_entry.hash >> 24) & 3)
@@ -1483,6 +1487,11 @@ _cairo_surface_tag (cairo_surface_t	        *surface,
 		    const char                  *tag_name,
 		    const char                  *attributes);
 
+cairo_private cairo_bool_t
+_cairo_surface_supports_color_glyph (cairo_surface_t       *surface,
+				     cairo_scaled_font_t   *scaled_font,
+				     unsigned long          glyph_index);
+
 cairo_private cairo_status_t
 _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
 				     cairo_image_surface_t  **image_out,
diff --git a/test/reference/ft-color-font.pdf.ref.png b/test/reference/ft-color-font.pdf.ref.png
deleted file mode 100644
index 3ea9e7850..000000000
Binary files a/test/reference/ft-color-font.pdf.ref.png and /dev/null differ
diff --git a/test/reference/ft-color-font.pdf.xfail.png b/test/reference/ft-color-font.pdf.xfail.png
new file mode 100644
index 000000000..5832a3464
Binary files /dev/null and b/test/reference/ft-color-font.pdf.xfail.png differ
diff --git a/test/reference/user-font-color.image16.ref.png b/test/reference/user-font-color.image16.ref.png
index 25a95ddac..b3721daf5 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 dc0962d70..bc14795ca 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.ps.ref.png b/test/reference/user-font-color.ps.ref.png
index 36c5c84a7..59932e64e 100644
Binary files a/test/reference/user-font-color.ps.ref.png and b/test/reference/user-font-color.ps.ref.png differ
diff --git a/test/reference/user-font-color.quartz.ref.png b/test/reference/user-font-color.quartz.ref.png
index bb76c16ab..b7c484647 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 e210c718d..3986f10a7 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 19b45e714..c74331eaf 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.xfail.png b/test/reference/user-font-color.svg.xfail.png
deleted file mode 100644
index fd10d6653..000000000
Binary files a/test/reference/user-font-color.svg.xfail.png and /dev/null differ
diff --git a/test/reference/user-font-color.xcb.ref.png b/test/reference/user-font-color.xcb.ref.png
index 45b323473..c3ec667b7 100644
Binary files a/test/reference/user-font-color.xcb.ref.png and b/test/reference/user-font-color.xcb.ref.png differ
diff --git a/test/reference/user-font-color.xlib.ref.png b/test/reference/user-font-color.xlib.ref.png
index 45b323473..c3ec667b7 100644
Binary files a/test/reference/user-font-color.xlib.ref.png and b/test/reference/user-font-color.xlib.ref.png differ
diff --git a/test/reference/user-font.pdf.xfail.png b/test/reference/user-font.pdf.xfail.png
new file mode 100644
index 000000000..b5145aed6
Binary files /dev/null and b/test/reference/user-font.pdf.xfail.png differ
diff --git a/test/reference/user-font.svg.argb32.ref.png b/test/reference/user-font.svg.argb32.ref.png
new file mode 100644
index 000000000..e14924e9a
Binary files /dev/null and b/test/reference/user-font.svg.argb32.ref.png differ
diff --git a/test/reference/user-font.svg.rgb24.ref.png b/test/reference/user-font.svg.rgb24.ref.png
new file mode 100644
index 000000000..c534efcfe
Binary files /dev/null and b/test/reference/user-font.svg.rgb24.ref.png differ


More information about the cairo-commit mailing list