From bryce at freedesktop.org Mon Jul 10 16:38:20 2017 From: bryce at freedesktop.org (Bryce Harrington) Date: Mon, 10 Jul 2017 16:38:20 +0000 (UTC) Subject: [cairo-commit] [cairo-www] src/news Message-ID: <20170710163820.B2A63182C2@annarchy.freedesktop.org> src/news/cairo-1.12.4.mdwn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) New commits: commit 3274f6d8bbdc06a83548df7843bcac504831521e Author: Bryce Harrington Date: Mon Jul 10 09:37:59 2017 -0700 news: Fix typos in the old 1.12.4 note diff --git a/src/news/cairo-1.12.4.mdwn b/src/news/cairo-1.12.4.mdwn index 3559e51..e921475 100644 --- a/src/news/cairo-1.12.4.mdwn +++ b/src/news/cairo-1.12.4.mdwn @@ -35,7 +35,7 @@ =================================================================== More bugs, and more importantly, more fixes. On the cairo-gl side, we have refinements to the MSAA compositor which enables hardware - acceleration of comparitively low-quality antialiasing - which is useful + acceleration of comparatively low-quality antialiasing - which is useful in animations and on very high density screens. For cairo-xlib, we have finally enabled SHM transport for image transfers to and from the X server. A long standing required feature, SHM transport offers a notable @@ -90,7 +90,7 @@ and then back again to user coordinates (cairo_copy_path, cairo_append_path) https://bugs.freedesktop.org/show_bug.cgi?id=54732 - =20 + Fix extents computations for a degenerate path consisting only of a move-to https://bugs.freedesktop.org/show_bug.cgi?id=54549 From bryce at kemper.freedesktop.org Sat Jul 29 00:02:56 2017 From: bryce at kemper.freedesktop.org (Bryce Harrington) Date: Sat, 29 Jul 2017 00:02:56 +0000 (UTC) Subject: [cairo-commit] 2 commits - RELEASING Message-ID: <20170729000256.8BF7C761B1@kemper.freedesktop.org> RELEASING | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) New commits: commit f6673e239a7e72a1f66e8faf1e5d5bbe7bdc2fd4 Author: Bryce Harrington Date: Fri Jul 28 17:02:29 2017 -0700 RELEASING: Note adding index to cairo-docs.xml for minor releases diff --git a/RELEASING b/RELEASING index bc40d704..e844627e 100644 --- a/RELEASING +++ b/RELEASING @@ -122,12 +122,21 @@ Here are the steps to follow to create a new cairo release: Otherwise, (i.e. there are only bug fixes), increment cairo_version_micro to the next larger (even) number. -5) Commit the changes to NEWS and cairo-version.h +5) For Minor releases, add an index entry to doc/public/cairo-docs.xml + + Towards the end of the file, add a new section for the stable + release. It'll look something like: + + + Index of new symbols in X.Y + + +6) Commit the changes to NEWS and cairo-version.h It's especially important to mention the new version number in your commit log. -6) Run "make release-publish" which will perform the following steps +7) Run "make release-publish" which will perform the following steps for you: * Generate ChangeLog files out of git repository @@ -164,7 +173,7 @@ Here are the steps to follow to create a new cairo release: previous versions, remove manual-${THIS_RELEASE} and release/cairo-${THIS_RELEASE}. -7) Update trunk (or the stable branch) version number. +8) Update trunk (or the stable branch) version number. For Micro releases (X.Y.Z), increment cairo_version_micro to the next larger (odd) number in cairo-version.h, commit, and push. @@ -173,17 +182,17 @@ Here are the steps to follow to create a new cairo release: next larger (odd) number, and set cairo_version_micro to 1. Then commit and push. -8) Push the new tag out to the central tree with a command like: +9) Push the new tag out to the central tree with a command like: git push origin master ${THIS_RELEASE} -9) Edit the cairo bugzilla product and add the new version numbers. +10) Edit the cairo bugzilla product and add the new version numbers. Note that you need to add two versions. One for the release/snapshot (with an even micro version), another with the post-release version (with an odd micro version). -10) Send out an announcement message. +11) Send out an announcement message. Send a message to cairo-announce at cairographics.org and CC cairo at cairographics.org, gnome-announce-list at gnome.org and @@ -194,5 +203,5 @@ Here are the steps to follow to create a new cairo release: git shortlog ${LAST_RELEASE}... -11) Add the announcement to the NEWS page and the front page. +12) Add the announcement to the NEWS page and the front page. commit 3a8bb3380532dbbede661f6c58a8a9cd443840c2 Author: Bryce Harrington Date: Fri Jul 28 16:31:50 2017 -0700 RELEASING: Note use of branches for stable releases diff --git a/RELEASING b/RELEASING index 424902e9..bc40d704 100644 --- a/RELEASING +++ b/RELEASING @@ -1,5 +1,18 @@ Here are the steps to follow to create a new cairo release: +0) Decide type of release and checkout the appropriate branch. + + The Cairo project makes three types of releases: Development + snapshot releases, stable minor releases, and stable micro (aka + "point") releases. Micro releases should be only bugfixes and + no API additions. If there are API additions consider making a + Minor release. Snapshot releases can be done of the current + development tree between Minor releases, as desired. + + For stable releases (both minor and micro), the work should be + done on the given release branch. E.g. for 1.14.12, check out + the 1.14 branch via "git checkout origin/1.14 -b 1.14". + 1) Ensure that there are no local, uncommitted/unpushed mods. You're probably in a good state if both "git diff @@ -45,12 +58,6 @@ Here are the steps to follow to create a new cairo release: 3) Decide what the new version number for the release will be. - There are three types of releases: Minor, Micro, and - Snapshot. Micro releases should be only bugfixes and no API - additions. If there are API additions consider making a Minor - release. Snapshot releases can be done of the current - development tree between Minor releases, as desired. - Cairo uses even numbers for official releases, and odd numbers for development snapshots. Thus, for a Minor release it would be: @@ -76,8 +83,6 @@ Here are the steps to follow to create a new cairo release: LAST_RELEASE="X.Y.Z" # e.g. 1.15.2 THIS_RELEASE="X.Y.Z+2" # e.g. 1.15.4 - - 4) Fill out an entry in the NEWS file Sift through the logs since the last release. This is most From bryce at kemper.freedesktop.org Sat Jul 29 00:03:05 2017 From: bryce at kemper.freedesktop.org (Bryce Harrington) Date: Sat, 29 Jul 2017 00:03:05 +0000 (UTC) Subject: [cairo-commit] doc/public Message-ID: <20170729000305.A299A761B1@kemper.freedesktop.org> doc/public/cairo-docs.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) New commits: commit 0fadb2c56d855560810205d78975450ddce271df Author: Bryce Harrington Date: Fri Jul 28 17:02:12 2017 -0700 cairo-docs: whitespace cleanup diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml index 73c9813f..9b92bfaf 100644 --- a/doc/public/cairo-docs.xml +++ b/doc/public/cairo-docs.xml @@ -1,9 +1,9 @@ - + ]> - + Cairo: A Vector Graphics Library Cairo: A Vector Graphics Library From behdad at kemper.freedesktop.org Sat Jul 29 15:22:45 2017 From: behdad at kemper.freedesktop.org (Behdad Esfahbod) Date: Sat, 29 Jul 2017 15:22:45 +0000 (UTC) Subject: [cairo-commit] 7 commits - src/cairo-ft-font.c src/cairoint.h src/cairo-scaled-font.c src/cairo-scaled-font-private.h src/cairo-surface.c Message-ID: <20170729152245.4F8777630A@kemper.freedesktop.org> src/cairo-ft-font.c | 87 ++++++++++++---- src/cairo-scaled-font-private.h | 3 src/cairo-scaled-font.c | 30 +++++ src/cairo-surface.c | 209 +++++++++++++++++++++++++++++++++++++++- src/cairoint.h | 11 +- 5 files changed, 317 insertions(+), 23 deletions(-) New commits: commit 7a1e378466971d26a3f6d3c9437744bc5ffef1eb Author: Behdad Esfahbod Date: Sat Jul 29 16:20:21 2017 +0100 Fix color font support infinite-loop with empty glyphs Ouch! But it all works now! Only took five years to merge this feature. Thanks Matthias Clasen for working out a real patch from my initial sketch. diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 3bf5381a..e1070f4c 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -1438,6 +1438,7 @@ _render_glyph_outline (FT_Face face, (*surface) = (cairo_image_surface_t *) cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); + pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE); if ((*surface)->base.status) return (*surface)->base.status; } else { @@ -1662,6 +1663,10 @@ _transform_glyph_bitmap (cairo_matrix_t * shape, old_image = (*surface); (*surface) = (cairo_image_surface_t *)image; + + /* Note: we converted subpixel-rendered RGBA images to grayscale, + * so, no need to copy component alpha to new image. */ + cairo_surface_destroy (&old_image->base); cairo_surface_set_device_offset (&(*surface)->base, @@ -2309,16 +2314,6 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, } #ifdef FT_LOAD_COLOR - /* Color-glyph support: - * - * This flags needs plumbing through fontconfig (does it?), and - * maybe we should cache color and grayscale bitmaps separately - * such that users of the font (ie. the surface) can choose which - * version to use based on target content type. - * - * Moreover, none of our backends and compositors currently support - * color glyphs. As such, this is currently disabled. - */ load_flags |= FT_LOAD_COLOR; #endif @@ -2469,7 +2464,7 @@ LOAD: if (unlikely (status)) goto FAIL; - if ((pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8) && + if (pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8 && !pixman_image_get_component_alpha (surface->pixman_image)) { _cairo_scaled_glyph_set_color_surface (scaled_glyph, &scaled_font->base, commit 5e3350e4d1df6aeb4333cb1e4134feb22280735c Author: Matthias Clasen Date: Fri Jun 30 21:17:43 2017 -0400 Simplify things a bit Do away with the separate check for color glyphs - we can just do the filtering, and if there are no color glyphs, it is a no-op. As long as we only do this for fonts with color glyphs, it should be fine. Reduce repetition in composite_color_glyphs by breaking out some helper functions. diff --git a/src/cairo-surface.c b/src/cairo-surface.c index d0d1cad6..c524fe4b 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -2523,46 +2523,62 @@ slim_hidden_def (cairo_surface_has_show_text_glyphs); #define GLYPH_CACHE_SIZE 64 -static cairo_bool_t -has_color_glyphs (cairo_glyph_t *glyphs, - int num_glyphs, - cairo_scaled_font_t *scaled_font, - cairo_scaled_glyph_t **glyph_cache) +static inline cairo_int_status_t +ensure_scaled_glyph (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t **glyph_cache, + cairo_glyph_t *glyph, + cairo_scaled_glyph_t **scaled_glyph) { - cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; - int i; - cairo_bool_t has_color = FALSE; + int cache_index; + cairo_int_status_t status; - _cairo_scaled_font_freeze_cache (scaled_font); + cache_index = glyph->index % GLYPH_CACHE_SIZE; + *scaled_glyph = glyph_cache[cache_index]; + if (*scaled_glyph == NULL || _cairo_scaled_glyph_index (*scaled_glyph) != glyph->index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph->index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + scaled_glyph); + if (unlikely (status)) + status = _cairo_scaled_font_set_error (scaled_font, status); + + glyph_cache[cache_index] = *scaled_glyph; + } - for (i = 0; i < num_glyphs; i++) { - cairo_scaled_glyph_t *scaled_glyph; - unsigned long glyph_index = glyphs[i].index; - int cache_index = glyph_index % GLYPH_CACHE_SIZE; - - scaled_glyph = glyph_cache[cache_index]; - if (scaled_glyph == NULL || - _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { - status = _cairo_scaled_glyph_lookup (scaled_font, - glyphs[i].index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (unlikely (status)) { - status = _cairo_scaled_font_set_error (scaled_font, status); - break; - } + return status; +} - glyph_cache[cache_index] = scaled_glyph; - } +static inline cairo_int_status_t +composite_one_color_glyph (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + cairo_glyph_t *glyph, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_int_status_t status; + cairo_image_surface_t *glyph_surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; - if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) { - has_color = TRUE; - break; - } + status = CAIRO_STATUS_SUCCESS; + + glyph_surface = scaled_glyph->color_surface; + + if (glyph_surface->width && glyph_surface->height) { + int x, y; + /* round glyph locations to the nearest pixels */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyph->x - glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyph->y - glyph_surface->base.device_transform.y0); + + pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); + cairo_matrix_init_translate (&matrix, - x, - y); + cairo_pattern_set_matrix (pattern, &matrix); + status = surface->backend->paint (surface, op, pattern, clip); } - _cairo_scaled_font_thaw_cache (scaled_font); - return has_color; + return status; } static cairo_int_status_t @@ -2577,22 +2593,20 @@ composite_color_glyphs (cairo_surface_t *surface, int *num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - const cairo_clip_t *clip, - cairo_scaled_glyph_t **glyph_cache) + const cairo_clip_t *clip) { cairo_int_status_t status; int i, j; cairo_scaled_glyph_t *scaled_glyph; - cairo_image_surface_t *glyph_surface; - cairo_pattern_t *pattern; - cairo_matrix_t matrix; - unsigned long glyph_index; - int cache_index; int remaining_clusters = 0; int remaining_glyphs = 0; int remaining_bytes = 0; int glyph_pos = 0; int byte_pos = 0; + int gp; + cairo_scaled_glyph_t *glyph_cache[GLYPH_CACHE_SIZE]; + + memset (glyph_cache, 0, sizeof (glyph_cache)); status = CAIRO_STATUS_SUCCESS; @@ -2607,28 +2621,16 @@ composite_color_glyphs (cairo_surface_t *surface, cairo_bool_t skip_cluster = FALSE; for (j = 0; j < clusters[i].num_glyphs; j++) { - int gp; - if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) gp = glyph_pos - j; else gp = glyph_pos + j; - glyph_index = glyphs[gp].index; - cache_index = glyph_index % GLYPH_CACHE_SIZE; - scaled_glyph = glyph_cache[cache_index]; - if (scaled_glyph == NULL || - _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { - status = _cairo_scaled_glyph_lookup (scaled_font, - glyph_index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (unlikely (status)) { - status = _cairo_scaled_font_set_error (scaled_font, status); - goto UNLOCK; - } - glyph_cache[cache_index] = scaled_glyph; - } + status = ensure_scaled_glyph (scaled_font, glyph_cache, + &glyphs[gp], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) { skip_cluster = TRUE; break; @@ -2650,43 +2652,20 @@ composite_color_glyphs (cairo_surface_t *surface, } for (j = 0; j < clusters[i].num_glyphs; j++) { - int gp; if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) gp = glyph_pos - j; else gp = glyph_pos + j; - glyph_index = glyphs[gp].index; - cache_index = glyph_index % GLYPH_CACHE_SIZE; - scaled_glyph = glyph_cache[cache_index]; - if (scaled_glyph == NULL || - _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { - status = _cairo_scaled_glyph_lookup (scaled_font, - glyph_index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (unlikely (status)) { - status = _cairo_scaled_font_set_error (scaled_font, status); - goto UNLOCK; - } - glyph_cache[cache_index] = scaled_glyph; - } - glyph_surface = scaled_glyph->color_surface; - - if (glyph_surface->width && glyph_surface->height) { - int x, y; - /* round glyph locations to the nearest pixels */ - /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ - x = _cairo_lround (glyphs[gp].x - glyph_surface->base.device_transform.x0); - y = _cairo_lround (glyphs[gp].y - glyph_surface->base.device_transform.y0); - - pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); - cairo_matrix_init_translate (&matrix, - x, - y); - cairo_pattern_set_matrix (pattern, &matrix); - status = surface->backend->paint (surface, op, pattern, clip); - if (unlikely (status)) - goto UNLOCK; - } + status = ensure_scaled_glyph (scaled_font, glyph_cache, + &glyphs[gp], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; + + status = composite_one_color_glyph (surface, op, source, clip, + &glyphs[gp], scaled_glyph); + if (unlikely (status)) + goto UNLOCK; } if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) @@ -2707,43 +2686,20 @@ composite_color_glyphs (cairo_surface_t *surface, } else { for (glyph_pos = 0; glyph_pos < *num_glyphs; glyph_pos++) { - glyph_index = glyphs[glyph_pos].index; - cache_index = glyph_index % GLYPH_CACHE_SIZE; - scaled_glyph = glyph_cache[cache_index]; - if (scaled_glyph == NULL || - _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { - status = _cairo_scaled_glyph_lookup (scaled_font, - glyph_index, - CAIRO_SCALED_GLYPH_INFO_SURFACE, - &scaled_glyph); - if (unlikely (status)) { - status = _cairo_scaled_font_set_error (scaled_font, status); - goto UNLOCK; - } - glyph_cache[cache_index] = scaled_glyph; - } + status = ensure_scaled_glyph (scaled_font, glyph_cache, + &glyphs[glyph_pos], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) { glyphs[remaining_glyphs++] = glyphs[glyph_pos]; continue; } - glyph_surface = scaled_glyph->color_surface; - - if (glyph_surface->width && glyph_surface->height) { - int x, y; - /* round glyph locations to the nearest pixels */ - /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ - x = _cairo_lround (glyphs[glyph_pos].x - glyph_surface->base.device_transform.x0); - y = _cairo_lround (glyphs[glyph_pos].y - glyph_surface->base.device_transform.y0); - - pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); - cairo_matrix_init_translate (&matrix, - x, - y); - cairo_pattern_set_matrix (pattern, &matrix); - status = surface->backend->paint (surface, op, pattern, clip); - if (unlikely (status)) - goto UNLOCK; - } + status = composite_one_color_glyph (surface, op, source, clip, + &glyphs[glyph_pos], scaled_glyph); + if (unlikely (status)) + goto UNLOCK; } *num_glyphs = remaining_glyphs; @@ -2812,24 +2768,19 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_scaled_font_has_color_glyphs (scaled_font)) { - cairo_scaled_glyph_t *glyph_cache[GLYPH_CACHE_SIZE]; - memset (glyph_cache, 0, sizeof (glyph_cache)); - if (has_color_glyphs (glyphs, num_glyphs, scaled_font, glyph_cache)) { - status = composite_color_glyphs (surface, op, - source, - (char *)utf8, &utf8_len, - glyphs, &num_glyphs, - (cairo_text_cluster_t *)clusters, &num_clusters, cluster_flags, - scaled_font, - clip, - glyph_cache); - - if (unlikely (status)) - goto DONE; - - if (num_glyphs == 0) - goto DONE; - } + status = composite_color_glyphs (surface, op, + source, + (char *)utf8, &utf8_len, + glyphs, &num_glyphs, + (cairo_text_cluster_t *)clusters, &num_clusters, cluster_flags, + scaled_font, + clip); + + if (unlikely (status)) + goto DONE; + + if (num_glyphs == 0) + goto DONE; } /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and commit db14d6d70759df221d6aaee9a1dc0354c39f1aa3 Author: Matthias Clasen Date: Thu Jun 29 22:57:02 2017 -0400 Render color glyphs as source, not as mask Use paint instead of show_glyphs for color glyphs. To avoid overhead, we only check for color glyphs if the font is known to contain any. Paint clusters containing only color glyphs and rewrite the inputs to remove the handled clusters and glyphs. diff --git a/src/cairo-surface.c b/src/cairo-surface.c index fc5f876d..d0d1cad6 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -508,7 +508,7 @@ cairo_surface_create_similar (cairo_surface_t *other, if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT); - if (unlikely (other->status)) + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); /* We inherit the device scale, so create a larger surface */ @@ -2521,6 +2521,240 @@ cairo_surface_has_show_text_glyphs (cairo_surface_t *surface) } slim_hidden_def (cairo_surface_has_show_text_glyphs); +#define GLYPH_CACHE_SIZE 64 + +static cairo_bool_t +has_color_glyphs (cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t **glyph_cache) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + int i; + cairo_bool_t has_color = FALSE; + + _cairo_scaled_font_freeze_cache (scaled_font); + + for (i = 0; i < num_glyphs; i++) { + cairo_scaled_glyph_t *scaled_glyph; + unsigned long glyph_index = glyphs[i].index; + int cache_index = glyph_index % GLYPH_CACHE_SIZE; + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + break; + } + + glyph_cache[cache_index] = scaled_glyph; + } + + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) { + has_color = TRUE; + break; + } + } + + _cairo_scaled_font_thaw_cache (scaled_font); + return has_color; +} + +static cairo_int_status_t +composite_color_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + char *utf8, + int *utf8_len, + cairo_glyph_t *glyphs, + int *num_glyphs, + 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_scaled_glyph_t **glyph_cache) +{ + cairo_int_status_t status; + int i, j; + cairo_scaled_glyph_t *scaled_glyph; + cairo_image_surface_t *glyph_surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + unsigned long glyph_index; + int cache_index; + int remaining_clusters = 0; + int remaining_glyphs = 0; + int remaining_bytes = 0; + int glyph_pos = 0; + int byte_pos = 0; + + status = CAIRO_STATUS_SUCCESS; + + _cairo_scaled_font_freeze_cache (scaled_font); + + if (clusters) { + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyph_pos = *num_glyphs - 1; + + for (i = 0; i < *num_clusters; i++) { + cairo_bool_t skip_cluster = FALSE; + + for (j = 0; j < clusters[i].num_glyphs; j++) { + int gp; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + gp = glyph_pos - j; + else + gp = glyph_pos + j; + + glyph_index = glyphs[gp].index; + cache_index = glyph_index % GLYPH_CACHE_SIZE; + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + goto UNLOCK; + } + glyph_cache[cache_index] = scaled_glyph; + } + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) { + skip_cluster = TRUE; + break; + } + } + + if (skip_cluster) { + memmove (utf8 + remaining_bytes, utf8 + byte_pos, clusters[i].num_bytes); + remaining_bytes += clusters[i].num_bytes; + byte_pos += clusters[i].num_bytes; + for (j = 0; j < clusters[i].num_glyphs; j++, remaining_glyphs++) { + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyphs[*num_glyphs - 1 - remaining_glyphs] = glyphs[glyph_pos--]; + else + glyphs[remaining_glyphs] = glyphs[glyph_pos++]; + } + clusters[remaining_clusters++] = clusters[i]; + continue; + } + + for (j = 0; j < clusters[i].num_glyphs; j++) { + int gp; + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + gp = glyph_pos - j; + else + gp = glyph_pos + j; + + glyph_index = glyphs[gp].index; + cache_index = glyph_index % GLYPH_CACHE_SIZE; + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + goto UNLOCK; + } + glyph_cache[cache_index] = scaled_glyph; + } + glyph_surface = scaled_glyph->color_surface; + + if (glyph_surface->width && glyph_surface->height) { + int x, y; + /* round glyph locations to the nearest pixels */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyphs[gp].x - glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyphs[gp].y - glyph_surface->base.device_transform.y0); + + pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); + cairo_matrix_init_translate (&matrix, - x, - y); + cairo_pattern_set_matrix (pattern, &matrix); + status = surface->backend->paint (surface, op, pattern, clip); + if (unlikely (status)) + goto UNLOCK; + } + } + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyph_pos -= clusters[i].num_glyphs; + else + glyph_pos += clusters[i].num_glyphs; + + byte_pos += clusters[i].num_bytes; + } + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + memmove (utf8, utf8 + *utf8_len - remaining_bytes, remaining_bytes); + + *utf8_len = remaining_bytes; + *num_glyphs = remaining_glyphs; + *num_clusters = remaining_clusters; + + } else { + + for (glyph_pos = 0; glyph_pos < *num_glyphs; glyph_pos++) { + glyph_index = glyphs[glyph_pos].index; + cache_index = glyph_index % GLYPH_CACHE_SIZE; + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + &scaled_glyph); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + goto UNLOCK; + } + glyph_cache[cache_index] = scaled_glyph; + } + + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) { + glyphs[remaining_glyphs++] = glyphs[glyph_pos]; + continue; + } + + glyph_surface = scaled_glyph->color_surface; + + if (glyph_surface->width && glyph_surface->height) { + int x, y; + /* round glyph locations to the nearest pixels */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyphs[glyph_pos].x - glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyphs[glyph_pos].y - glyph_surface->base.device_transform.y0); + + pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); + cairo_matrix_init_translate (&matrix, - x, - y); + cairo_pattern_set_matrix (pattern, &matrix); + status = surface->backend->paint (surface, op, pattern, clip); + if (unlikely (status)) + goto UNLOCK; + } + } + + *num_glyphs = remaining_glyphs; + } + +UNLOCK: + _cairo_scaled_font_thaw_cache (scaled_font); + + return status; +} + /* Note: the backends may modify the contents of the glyph array as long as * they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to * avoid copying the array again and again, and edit it in-place. @@ -2577,6 +2811,27 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_scaled_font_has_color_glyphs (scaled_font)) { + cairo_scaled_glyph_t *glyph_cache[GLYPH_CACHE_SIZE]; + memset (glyph_cache, 0, sizeof (glyph_cache)); + if (has_color_glyphs (glyphs, num_glyphs, scaled_font, glyph_cache)) { + status = composite_color_glyphs (surface, op, + source, + (char *)utf8, &utf8_len, + glyphs, &num_glyphs, + (cairo_text_cluster_t *)clusters, &num_clusters, cluster_flags, + scaled_font, + clip, + glyph_cache); + + if (unlikely (status)) + goto DONE; + + if (num_glyphs == 0) + goto DONE; + } + } + /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and * show_text_glyphs. Keep in synch. */ if (clusters) { @@ -2627,6 +2882,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, } } +DONE: if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { surface->is_clear = FALSE; surface->serial++; commit 6a8a25cc4792eca774fa6d0857229659adbe063b Author: Matthias Clasen Date: Fri Apr 8 13:20:56 2016 -0400 Implement has_color_glyphs for freetype This information is available from the FT_Face using the FT_HAS_COLOR macro. We cache the value in the unscaled_font object as soon as we have an FT_Face. diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 4b9af2f8..3bf5381a 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -169,6 +169,9 @@ struct _cairo_ft_unscaled_font { cairo_matrix_t current_shape; FT_Matrix Current_Shape; + unsigned int have_color_set : 1; + unsigned int have_color : 1; /* true if the font contains color glyphs */ + cairo_mutex_t mutex; int lock_count; @@ -426,6 +429,9 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, if (from_face) { unscaled->from_face = TRUE; _cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face); + + unscaled->have_color = FT_HAS_COLOR (face) != 0; + unscaled->have_color_set = TRUE; } else { char *filename_copy; @@ -437,6 +443,8 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL); + + unscaled->have_color_set = FALSE; } unscaled->have_scale = FALSE; @@ -704,6 +712,9 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) unscaled->face = face; + unscaled->have_color = FT_HAS_COLOR (face) != 0; + unscaled->have_color_set = TRUE; + font_map->num_open_faces++; return face; @@ -2826,6 +2837,20 @@ _cairo_ft_load_type1_data (void *abstract_font, return status; } +static cairo_bool_t +_cairo_ft_has_color_glyphs (void *scaled) +{ + cairo_ft_unscaled_font_t *unscaled = ((cairo_ft_scaled_font_t *)scaled)->unscaled; + + if (!unscaled->have_color_set) { + FT_Face face; + face = _cairo_ft_unscaled_font_lock_face (unscaled); + _cairo_ft_unscaled_font_unlock_face (unscaled); + } + + return unscaled->have_color; +} + static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { CAIRO_FONT_TYPE_FT, _cairo_ft_scaled_font_fini, @@ -2836,7 +2861,8 @@ static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { _cairo_ft_index_to_ucs4, _cairo_ft_is_synthetic, _cairo_index_to_glyph_name, - _cairo_ft_load_type1_data + _cairo_ft_load_type1_data, + _cairo_ft_has_color_glyphs }; /* #cairo_ft_font_face_t */ commit 66228456531c8a80f3985160bf1013248e433681 Author: Matthias Clasen Date: Fri Apr 8 13:21:47 2016 -0400 Expose 'has color glyphs' as a scaled font property This information will be used in subsequent commits to quickly decide that we won't try to handle glpyhs as masks. Implementing the new has_color_glyphs vfunc is optional - only backends that support color glyphs need to implement it. diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index 6ce6bb6d..317d2119 100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h @@ -178,6 +178,8 @@ _cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph, void (*destroy) (cairo_scaled_glyph_private_t *, cairo_scaled_glyph_t *, cairo_scaled_font_t *)); +cairo_private cairo_bool_t +_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font); CAIRO_END_DECLS diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 665395b5..b8804903 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -3190,3 +3190,12 @@ cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, _cairo_font_options_init_copy (options, &scaled_font->options); } slim_hidden_def (cairo_scaled_font_get_font_options); + +cairo_bool_t +_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font->backend != NULL && scaled_font->backend->has_color_glyphs != NULL) + return scaled_font->backend->has_color_glyphs (scaled_font); + else + return FALSE; +} diff --git a/src/cairoint.h b/src/cairoint.h index a04a92e9..f6435592 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -608,6 +608,9 @@ struct _cairo_scaled_font_backend { long offset, unsigned char *buffer, unsigned long *length); + + cairo_bool_t + (*has_color_glyphs) (void *scaled_font); }; struct _cairo_font_face_backend { commit 52b17c724260512873ab0731e2e2314bb0a15e4b Author: Matthias Clasen Date: Thu Jun 29 20:19:56 2017 -0400 Support loading color glyphs with freetype Use the FT_LOAD_COLOR flag to instruct freetype to load embedded PNGs without converting them to grayscale. We always load both the color and regular surface when we are loading surfaces. diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 5b367e7b..4b9af2f8 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -2283,8 +2283,10 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && - (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) == 0) + (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) == 0) { load_flags |= FT_LOAD_NO_BITMAP; + } /* * Don't pass FT_LOAD_VERTICAL_LAYOUT to FT_Load_Glyph here as @@ -2306,7 +2308,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, * Moreover, none of our backends and compositors currently support * color glyphs. As such, this is currently disabled. */ - /* load_flags |= FT_LOAD_COLOR; */ + load_flags |= FT_LOAD_COLOR; #endif @@ -2420,7 +2422,8 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, &fs_metrics); } - if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { +LOAD: + if (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) { cairo_image_surface_t *surface; if (!scaled_glyph_loaded) { @@ -2448,18 +2451,39 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, { status = _transform_glyph_bitmap (&unscaled->current_shape, &surface); - if (unlikely (status)) - cairo_surface_destroy (&surface->base); - } + if (unlikely (status)) + cairo_surface_destroy (&surface->base); + } } if (unlikely (status)) goto FAIL; - _cairo_scaled_glyph_set_surface (scaled_glyph, - &scaled_font->base, - surface); + if ((pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8) && + !pixman_image_get_component_alpha (surface->pixman_image)) { + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + surface); + } else { + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + surface); + } } +#ifdef FT_LOAD_COLOR + if (((info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) != 0) && + ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_SURFACE) == 0)) { + /* + * A kludge -- load again, without color. + * No need to load the metrics again, though + */ + scaled_glyph_loaded = FALSE; + info &= ~CAIRO_SCALED_GLYPH_INFO_METRICS; + load_flags &= ~FT_LOAD_COLOR; + goto LOAD; + } +#endif + if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { cairo_path_fixed_t *path = NULL; /* hide compiler warning */ @@ -2467,7 +2491,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font, * A kludge -- the above code will trash the outline, * so reload it. This will probably never occur though */ - if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { + if ((info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) != 0) { scaled_glyph_loaded = FALSE; load_flags |= FT_LOAD_NO_BITMAP; } commit 0d8859c66fb82a00147ab77d1971111306ca2272 Author: Matthias Clasen Date: Thu Apr 7 20:38:09 2016 -0400 Add support for color glyphs to cairo_scaled_glyph_t With this, glyphs can have either a surface that is expected to be used as mask, or a color_surface that should be used as source, or both. This will be used to support colored emoji glyphs that are stored as PNG images in OpenType fonts. diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h index da7b3469..6ce6bb6d 100644 --- a/src/cairo-scaled-font-private.h +++ b/src/cairo-scaled-font-private.h @@ -141,6 +141,7 @@ struct _cairo_scaled_glyph { cairo_image_surface_t *surface; /* device-space image */ cairo_path_fixed_t *path; /* device-space outline */ cairo_surface_t *recording_surface; /* device-space recording-surface */ + cairo_image_surface_t *color_surface; /* device-space color image */ const void *dev_private_key; void *dev_private; diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index dff30538..665395b5 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -224,6 +224,9 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, cairo_surface_finish (scaled_glyph->recording_surface); cairo_surface_destroy (scaled_glyph->recording_surface); } + + if (scaled_glyph->color_surface != NULL) + cairo_surface_destroy (&scaled_glyph->color_surface->base); } #define ZOMBIE 0 @@ -2830,6 +2833,24 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; } +void +_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface) +{ + if (scaled_glyph->color_surface != NULL) + cairo_surface_destroy (&scaled_glyph->color_surface->base); + + /* sanity check the backend glyph contents */ + _cairo_debug_check_image_surface_is_defined (&surface->base); + scaled_glyph->color_surface = surface; + + if (surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; +} + static cairo_bool_t _cairo_scaled_glyph_page_can_remove (const void *closure) { diff --git a/src/cairoint.h b/src/cairoint.h index 4fedf861..a04a92e9 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -477,7 +477,8 @@ typedef enum _cairo_scaled_glyph_info { CAIRO_SCALED_GLYPH_INFO_METRICS = (1 << 0), CAIRO_SCALED_GLYPH_INFO_SURFACE = (1 << 1), CAIRO_SCALED_GLYPH_INFO_PATH = (1 << 2), - CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE = (1 << 3) + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE = (1 << 3), + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE = (1 << 4) } cairo_scaled_glyph_info_t; typedef struct _cairo_scaled_font_subset { @@ -1255,6 +1256,11 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font, cairo_surface_t *recording_surface); +cairo_private void +_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface); + cairo_private cairo_int_status_t _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, unsigned long index, From behdad at kemper.freedesktop.org Sat Jul 29 16:40:53 2017 From: behdad at kemper.freedesktop.org (Behdad Esfahbod) Date: Sat, 29 Jul 2017 16:40:53 +0000 (UTC) Subject: [cairo-commit] src/cairo-surface.c Message-ID: <20170729164053.7055F76154@kemper.freedesktop.org> src/cairo-surface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) New commits: commit 495cb9a0a765ccbc678f55d8bfe699829a214f39 Author: Behdad Esfahbod Date: Sat Jul 29 17:40:34 2017 +0100 Fix uninitialized status! diff --git a/src/cairo-surface.c b/src/cairo-surface.c index c524fe4b..5436ed96 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -2530,7 +2530,7 @@ ensure_scaled_glyph (cairo_scaled_font_t *scaled_font, cairo_scaled_glyph_t **scaled_glyph) { int cache_index; - cairo_int_status_t status; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; cache_index = glyph->index % GLYPH_CACHE_SIZE; *scaled_glyph = glyph_cache[cache_index]; @@ -2561,7 +2561,7 @@ composite_one_color_glyph (cairo_surface_t *surface, cairo_pattern_t *pattern; cairo_matrix_t matrix; - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; glyph_surface = scaled_glyph->color_surface; @@ -2608,7 +2608,7 @@ composite_color_glyphs (cairo_surface_t *surface, memset (glyph_cache, 0, sizeof (glyph_cache)); - status = CAIRO_STATUS_SUCCESS; + status = CAIRO_INT_STATUS_SUCCESS; _cairo_scaled_font_freeze_cache (scaled_font);