diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 9a9705d0fd..5e07a8f92a 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -30,7 +30,7 @@ #include "gdk/gdktextureprivate.h" #include "gdk/gdk-private.h" -#include +#include static inline void gsk_cairo_rectangle (cairo_t *cr, @@ -4377,6 +4377,15 @@ gsk_text_node_draw (GskRenderNode *node, cairo_restore (cr); } +/* We steal one of the bits in PangoGlyphVisAttr */ + +G_STATIC_ASSERT (sizeof (PangoGlyphVisAttr) == 4); + +#define COLOR_GLYPH_BIT 2 +#define GLYPH_IS_COLOR(g) (((*(guint32*)&(g)->attr) & COLOR_GLYPH_BIT) != 0) +#define GLYPH_SET_COLOR(g) (*(guint32*)(&(g)->attr) |= COLOR_GLYPH_BIT) +#define GLYPH_CLEAR_COLOR(g) (*(guint32*)(&(g)->attr) &= ~COLOR_GLYPH_BIT) + static void gsk_text_node_diff (GskRenderNode *node1, GskRenderNode *node2, @@ -4401,7 +4410,8 @@ gsk_text_node_diff (GskRenderNode *node1, info1->geometry.width == info2->geometry.width && info1->geometry.x_offset == info2->geometry.x_offset && info1->geometry.y_offset == info2->geometry.y_offset && - info1->attr.is_cluster_start == info2->attr.is_cluster_start) + info1->attr.is_cluster_start == info2->attr.is_cluster_start && + GLYPH_IS_COLOR (info1) == GLYPH_IS_COLOR (info2)) continue; gsk_render_node_diff_impossible (node1, node2, region); @@ -4415,20 +4425,43 @@ gsk_text_node_diff (GskRenderNode *node1, } static gboolean -font_has_color_glyphs (const PangoFont *font) +font_has_color_glyphs (PangoFont *font) { - cairo_scaled_font_t *scaled_font; - gboolean has_color = FALSE; + hb_face_t *face = hb_font_get_face (pango_font_get_hb_font (font)); - scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font); - if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT) + return hb_ot_color_has_layers (face) || + hb_ot_color_has_png (face) || + hb_ot_color_has_svg (face); +} + +static gboolean +glyph_has_color (PangoFont *font, + guint glyph) +{ + hb_font_t *hb_font = pango_font_get_hb_font (font); + hb_face_t *face = hb_font_get_face (hb_font); + hb_blob_t *blob; + + if (hb_ot_color_glyph_get_layers (face, glyph, 0, NULL, NULL) > 0) + return TRUE; + + blob = hb_ot_color_glyph_reference_png (hb_font, glyph); + if (blob) { - FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); - has_color = (FT_HAS_COLOR (ft_face) != 0); - cairo_ft_scaled_font_unlock_face (scaled_font); + guint length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + return length > 0; } - return has_color; + blob = hb_ot_color_glyph_reference_svg (face, glyph); + if (blob) + { + guint length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + return length > 0; + } + + return FALSE; } /** @@ -4454,6 +4487,9 @@ gsk_text_node_new (PangoFont *font, GskTextNode *self; GskRenderNode *node; PangoRectangle ink_rect; + PangoGlyphInfo *glyph_infos; + gboolean has_color_glyphs; + int n; pango_glyph_string_extents (glyphs, font, &ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL); @@ -4466,19 +4502,36 @@ gsk_text_node_new (PangoFont *font, node = (GskRenderNode *) self; self->font = g_object_ref (font); - self->has_color_glyphs = font_has_color_glyphs (font); self->color = *color; self->offset = *offset; - self->glyphs = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo)); + self->has_color_glyphs = FALSE; - /* skip empty glyphs */ - self->num_glyphs = 0; + glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo)); + has_color_glyphs = font_has_color_glyphs (font); + + n = 0; for (int i = 0; i < glyphs->num_glyphs; i++) { - if (glyphs->glyphs[i].glyph != PANGO_GLYPH_EMPTY) - self->glyphs[self->num_glyphs++] = glyphs->glyphs[i]; + /* skip empty glyphs */ + if (glyphs->glyphs[i].glyph == PANGO_GLYPH_EMPTY) + continue; + + glyph_infos[n] = glyphs->glyphs[i]; + GLYPH_CLEAR_COLOR (&glyph_infos[n]); + + if (has_color_glyphs && + glyph_has_color (font, glyph_infos[n].glyph)) + { + self->has_color_glyphs = TRUE; + GLYPH_SET_COLOR (&glyph_infos[n]); + } + + n++; } + self->glyphs = glyph_infos; + self->num_glyphs = n; + graphene_rect_init (&node->bounds, offset->x + ink_rect.x - 1, offset->y + ink_rect.y - 1, diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index 87c407cd9b..532157d1be 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -2835,6 +2835,9 @@ compute_phase_and_pos (float value, float *pos) } } +#define COLOR_GLYPH_BIT 2 +#define GLYPH_IS_COLOR(g) (((*(guint32*)&(g)->attr) & COLOR_GLYPH_BIT) != 0) + static inline void gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job, const GskRenderNode *node, @@ -2855,7 +2858,9 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job, guint last_texture = 0; GskNglDrawVertex *vertices; guint used = 0; - guint16 c[4] = { FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE }; + guint16 nc[4] = { FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE }; + guint16 cc[4]; + const guint16 *c; const PangoGlyphInfo *gi; guint i; int yshift; @@ -2864,16 +2869,11 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job, if (num_glyphs == 0) return; - /* If the font has color glyphs, we don't need to recolor anything. - * We tell the shader by setting the color to vec4(-1). - */ - if (force_color || !gsk_text_node_has_color_glyphs (node)) - { - if (RGBA_IS_CLEAR (color)) - return; + if ((force_color || !gsk_text_node_has_color_glyphs (node)) && + RGBA_IS_CLEAR (color)) + return; - rgba_to_half (color, c); - } + rgba_to_half (color, cc); lookup.font = (PangoFont *)font; lookup.scale = (guint) (text_scale * 1024); @@ -2897,6 +2897,14 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job, lookup.glyph = gi->glyph; + /* If the glyph has color, we don't need to recolor anything. + * We tell the shader by setting the color to vec4(-1). + */ + if (!force_color && GLYPH_IS_COLOR (gi)) + c = nc; + else + c = cc; + cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE; lookup.xshift = compute_phase_and_pos (x + cx, &cx); diff --git a/meson.build b/meson.build index 5a19806e55..f2aef2f646 100644 --- a/meson.build +++ b/meson.build @@ -396,7 +396,7 @@ pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req, default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false']) epoxy_dep = dependency('epoxy', version: epoxy_req, fallback: ['libepoxy', 'libepoxy_dep']) -harfbuzz_dep = dependency('harfbuzz', version: '>= 0.9', required: false, +harfbuzz_dep = dependency('harfbuzz', version: '>= 2.1.0', required: false, fallback: ['harfbuzz', 'libharfbuzz_dep'], default_options: ['coretext=enabled']) xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)