Merge branch 'svg-color-glyphs' into 'master'
Draft: Add support for color glyphs to SVG backend See merge request cairo/cairo!562
|
|
@ -49,4 +49,3 @@ text-rotate
|
|||
text-unhinted-metrics
|
||||
tighten-bounds
|
||||
unbounded-operator
|
||||
user-font-color
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ filter-bilinear-extents
|
|||
filter-nearest-offset
|
||||
filter-nearest-transformed
|
||||
finer-grained-fallbacks
|
||||
ft-color-font
|
||||
ft-show-glyphs-positioning
|
||||
ft-text-vertical-layout-type1
|
||||
ft-text-vertical-layout-type3
|
||||
|
|
@ -106,4 +105,3 @@ tighten-bounds
|
|||
unbounded-operator
|
||||
xcb-surface-source
|
||||
xlib-surface-source
|
||||
user-font-color
|
||||
|
|
|
|||
|
|
@ -45,6 +45,13 @@
|
|||
|
||||
#include "cairo-surface-private.h"
|
||||
|
||||
typedef struct _cairo_svg_color_glyph {
|
||||
cairo_hash_entry_t base;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
unsigned long glyph_index;
|
||||
cairo_bool_t supported;
|
||||
} cairo_svg_color_glyph_t;
|
||||
|
||||
struct _cairo_svg_surface_start {
|
||||
cairo_surface_t base;
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,25 @@ _cairo_svg_source_surface_equal (const void *key_a, const void *key_b)
|
|||
return a->id == b->id;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_svg_color_glyph_equal (const void *key_a, const void *key_b)
|
||||
{
|
||||
const cairo_svg_color_glyph_t *a = key_a;
|
||||
const cairo_svg_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_svg_color_glyph_init_key (cairo_svg_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 void
|
||||
_cairo_svg_source_surface_pluck (void *entry, void *closure)
|
||||
{
|
||||
|
|
@ -128,6 +147,18 @@ _cairo_svg_source_surface_pluck (void *entry, void *closure)
|
|||
free (source_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_svg_color_glyph_pluck (void *entry, void *closure)
|
||||
{
|
||||
cairo_svg_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 void
|
||||
_cairo_svg_paint_init_key (cairo_svg_paint_t *paint)
|
||||
{
|
||||
|
|
@ -526,6 +557,8 @@ typedef struct _cairo_svg_surface {
|
|||
|
||||
cairo_svg_document_t *document;
|
||||
|
||||
cairo_hash_table_t *color_glyphs;
|
||||
|
||||
cairo_svg_stream_t xml_node;
|
||||
cairo_array_t page_set;
|
||||
|
||||
|
|
@ -1080,13 +1113,19 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
|
|||
|
||||
surface->document = _cairo_svg_document_reference (document);
|
||||
|
||||
surface->color_glyphs = _cairo_hash_table_create (_cairo_svg_color_glyph_equal);
|
||||
if (unlikely (surface->color_glyphs == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto CLEANUP1;
|
||||
}
|
||||
|
||||
surface->xml_node = _cairo_svg_stream_create ();
|
||||
_cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
|
||||
|
||||
surface->source_surfaces = _cairo_hash_table_create (_cairo_svg_source_surface_equal);
|
||||
if (unlikely (surface->source_surfaces == NULL)) {
|
||||
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
goto CLEANUP;
|
||||
goto CLEANUP2;
|
||||
}
|
||||
|
||||
_cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path);
|
||||
|
|
@ -1110,7 +1149,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
|
|||
}
|
||||
|
||||
/* ignore status as we are on the error path */
|
||||
CLEANUP:
|
||||
CLEANUP2:
|
||||
(void) _cairo_hash_table_destroy (surface->color_glyphs);
|
||||
CLEANUP1:
|
||||
(void) _cairo_svg_stream_destroy (&surface->xml_node);
|
||||
(void) _cairo_svg_document_destroy (document);
|
||||
|
||||
|
|
@ -1346,6 +1387,59 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
|
|||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_svg_document_emit_color_glyph_data (cairo_svg_document_t *document,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph_index)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
cairo_scaled_glyph_t *scaled_glyph;
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
|
||||
NULL, /* foreground color */
|
||||
&scaled_glyph);
|
||||
if (unlikely (status)) {
|
||||
return status;
|
||||
}
|
||||
// User fonts always have a recording surface, but they may not be color glyphs.
|
||||
if (scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph) {
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
0,
|
||||
0,
|
||||
FALSE);
|
||||
cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
|
||||
status = paginated_surface->status;
|
||||
if (unlikely (status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cairo_surface_set_fallback_resolution (paginated_surface,
|
||||
document->owner->x_fallback_resolution,
|
||||
document->owner->y_fallback_resolution);
|
||||
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (scaled_glyph->recording_surface);
|
||||
_cairo_svg_surface_emit_composite_pattern (&document->xml_node_glyphs,
|
||||
svg_surface,
|
||||
(cairo_surface_pattern_t *) pattern,
|
||||
invalid_pattern_id,
|
||||
NULL);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cleanup:
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
status = cairo_surface_status (paginated_surface);
|
||||
}
|
||||
cairo_surface_destroy (paginated_surface);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
|
|
@ -1483,7 +1577,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
cleanup:
|
||||
if (status == CAIRO_STATUS_SUCCESS) {
|
||||
status = cairo_surface_status (paginated_surface);
|
||||
}
|
||||
|
|
@ -1510,13 +1604,19 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
|
|||
font_id,
|
||||
subset_glyph_index);
|
||||
|
||||
status = _cairo_svg_document_emit_outline_glyph_data (document,
|
||||
scaled_font,
|
||||
scaled_font_glyph_index);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
status = _cairo_svg_document_emit_bitmap_glyph_data (document,
|
||||
scaled_font,
|
||||
scaled_font_glyph_index);
|
||||
status = _cairo_svg_document_emit_color_glyph_data (document,
|
||||
scaled_font,
|
||||
scaled_font_glyph_index);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
status = _cairo_svg_document_emit_outline_glyph_data (document,
|
||||
scaled_font,
|
||||
scaled_font_glyph_index);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
status = _cairo_svg_document_emit_bitmap_glyph_data (document,
|
||||
scaled_font,
|
||||
scaled_font_glyph_index);
|
||||
}
|
||||
}
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
|
|
@ -1660,6 +1760,11 @@ _cairo_svg_surface_finish (void *abstract_surface)
|
|||
_cairo_hash_table_foreach (surface->source_surfaces, _cairo_svg_source_surface_pluck, surface->source_surfaces);
|
||||
_cairo_hash_table_destroy (surface->source_surfaces);
|
||||
|
||||
_cairo_hash_table_foreach (surface->color_glyphs,
|
||||
_cairo_svg_color_glyph_pluck,
|
||||
surface->color_glyphs);
|
||||
_cairo_hash_table_destroy (surface->color_glyphs);
|
||||
|
||||
status = _cairo_svg_document_destroy (surface->document);
|
||||
if (final_status == CAIRO_STATUS_SUCCESS) {
|
||||
final_status = status;
|
||||
|
|
@ -2430,6 +2535,28 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_svg_stream_t *output,
|
|||
return status;
|
||||
}
|
||||
|
||||
// FIXME error handling order
|
||||
cairo_svg_paint_t *paint_entry = _cairo_calloc (sizeof (cairo_svg_paint_t));
|
||||
if (paint_entry == NULL) {
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
cairo_rectangle_int_t extents;
|
||||
cairo_bool_t is_bounded;
|
||||
// how to get extents ???
|
||||
is_bounded =_cairo_surface_get_extents (pattern->surface, &extents);
|
||||
//assert (is_bounded); ???
|
||||
paint_entry->source_id = surface->source_id;
|
||||
paint_entry->box.p1.x = extents.x;
|
||||
paint_entry->box.p1.y = extents.y;
|
||||
paint_entry->box.p2.x = extents.x + extents.width;
|
||||
paint_entry->box.p2.y = extents.y + extents.height;
|
||||
_cairo_svg_paint_box_add_padding (&paint_entry->box);
|
||||
|
||||
_cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
|
||||
_cairo_svg_paint_init_key (paint_entry);
|
||||
status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
|
||||
|
||||
surface->transitive_paint_used = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -4082,14 +4209,25 @@ _cairo_svg_surface_show_glyphs_impl (cairo_svg_stream_t *output,
|
|||
return status;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_svg_surface_has_show_text_glyphs (void *abstract_surface)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_svg_surface_show_glyphs (void *abstract_surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
const cairo_clip_t *clip)
|
||||
_cairo_svg_surface_show_text_glyphs (void *abstract_surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_pattern_t *source,
|
||||
const char *utf8,
|
||||
int utf8_len,
|
||||
cairo_glyph_t *glyphs,
|
||||
int num_glyphs,
|
||||
const cairo_text_cluster_t *clusters,
|
||||
int num_clusters,
|
||||
cairo_text_cluster_flags_t cluster_flags,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
const cairo_clip_t *clip)
|
||||
{
|
||||
cairo_svg_surface_t *surface = abstract_surface;
|
||||
cairo_int_status_t status;
|
||||
|
|
@ -4126,6 +4264,63 @@ _cairo_svg_surface_get_supported_mime_types (void *abstract_surface)
|
|||
return _cairo_svg_supported_mime_types;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_svg_surface_supports_color_glyph (void *abstract_surface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long glyph_index)
|
||||
{
|
||||
cairo_svg_surface_t *surface = abstract_surface;
|
||||
cairo_svg_color_glyph_t glyph_key;
|
||||
cairo_svg_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_svg_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_svg_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_svg_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_RECORDING_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 const cairo_surface_backend_t cairo_svg_surface_backend = {
|
||||
CAIRO_SURFACE_TYPE_SVG,
|
||||
_cairo_svg_surface_finish,
|
||||
|
|
@ -4156,10 +4351,14 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
|
|||
_cairo_svg_surface_stroke,
|
||||
_cairo_svg_surface_fill,
|
||||
_cairo_svg_surface_fill_stroke,
|
||||
_cairo_svg_surface_show_glyphs,
|
||||
NULL, /* has_show_text_glyphs */
|
||||
NULL, /* show_text_glyphs */
|
||||
NULL, /* show_glyphs */
|
||||
_cairo_svg_surface_has_show_text_glyphs,
|
||||
_cairo_svg_surface_show_text_glyphs,
|
||||
_cairo_svg_surface_get_supported_mime_types,
|
||||
NULL, /* tag */
|
||||
_cairo_svg_surface_supports_color_glyph,
|
||||
NULL, /* analyze_recording_surface */
|
||||
NULL, /* command_id */
|
||||
};
|
||||
|
||||
static cairo_status_t
|
||||
|
|
|
|||
BIN
test/reference/ft-color-font.svg11.argb32.ref.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
test/reference/ft-color-font.svg11.rgb24.ref.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
test/reference/ft-svg-render-color.svg.ref.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
BIN
test/reference/ft-svg-render-doc.svg.ref.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
test/reference/ft-svg-render-fill.svg.ref.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
BIN
test/reference/user-font-color.svg11.ref.png
Normal file
|
After Width: | Height: | Size: 10 KiB |