Merge branch 'color-glyph-fixes' into 'master'

gsk: Make color glyphs

Closes #4141

See merge request GNOME/gtk!3812
This commit is contained in:
Matthias Clasen 2021-07-31 20:54:39 +00:00
commit e1606ce8eb
3 changed files with 89 additions and 28 deletions

View File

@ -30,7 +30,7 @@
#include "gdk/gdktextureprivate.h"
#include "gdk/gdk-private.h"
#include <cairo-ft.h>
#include <hb-ot.h>
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,

View File

@ -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);

View File

@ -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)