forked from AuroraMiddleware/gtk
Merge branch 'color-glyph-fixes' into 'master'
gsk: Make color glyphs Closes #4141 See merge request GNOME/gtk!3812
This commit is contained in:
commit
e1606ce8eb
@ -30,7 +30,7 @@
|
|||||||
#include "gdk/gdktextureprivate.h"
|
#include "gdk/gdktextureprivate.h"
|
||||||
#include "gdk/gdk-private.h"
|
#include "gdk/gdk-private.h"
|
||||||
|
|
||||||
#include <cairo-ft.h>
|
#include <hb-ot.h>
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
gsk_cairo_rectangle (cairo_t *cr,
|
gsk_cairo_rectangle (cairo_t *cr,
|
||||||
@ -4377,6 +4377,15 @@ gsk_text_node_draw (GskRenderNode *node,
|
|||||||
cairo_restore (cr);
|
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
|
static void
|
||||||
gsk_text_node_diff (GskRenderNode *node1,
|
gsk_text_node_diff (GskRenderNode *node1,
|
||||||
GskRenderNode *node2,
|
GskRenderNode *node2,
|
||||||
@ -4401,7 +4410,8 @@ gsk_text_node_diff (GskRenderNode *node1,
|
|||||||
info1->geometry.width == info2->geometry.width &&
|
info1->geometry.width == info2->geometry.width &&
|
||||||
info1->geometry.x_offset == info2->geometry.x_offset &&
|
info1->geometry.x_offset == info2->geometry.x_offset &&
|
||||||
info1->geometry.y_offset == info2->geometry.y_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;
|
continue;
|
||||||
|
|
||||||
gsk_render_node_diff_impossible (node1, node2, region);
|
gsk_render_node_diff_impossible (node1, node2, region);
|
||||||
@ -4415,20 +4425,43 @@ gsk_text_node_diff (GskRenderNode *node1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
font_has_color_glyphs (const PangoFont *font)
|
font_has_color_glyphs (PangoFont *font)
|
||||||
{
|
{
|
||||||
cairo_scaled_font_t *scaled_font;
|
hb_face_t *face = hb_font_get_face (pango_font_get_hb_font (font));
|
||||||
gboolean has_color = FALSE;
|
|
||||||
|
|
||||||
scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
|
return hb_ot_color_has_layers (face) ||
|
||||||
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_FT)
|
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);
|
guint length = hb_blob_get_length (blob);
|
||||||
has_color = (FT_HAS_COLOR (ft_face) != 0);
|
hb_blob_destroy (blob);
|
||||||
cairo_ft_scaled_font_unlock_face (scaled_font);
|
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;
|
GskTextNode *self;
|
||||||
GskRenderNode *node;
|
GskRenderNode *node;
|
||||||
PangoRectangle ink_rect;
|
PangoRectangle ink_rect;
|
||||||
|
PangoGlyphInfo *glyph_infos;
|
||||||
|
gboolean has_color_glyphs;
|
||||||
|
int n;
|
||||||
|
|
||||||
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
|
pango_glyph_string_extents (glyphs, font, &ink_rect, NULL);
|
||||||
pango_extents_to_pixels (&ink_rect, NULL);
|
pango_extents_to_pixels (&ink_rect, NULL);
|
||||||
@ -4466,19 +4502,36 @@ gsk_text_node_new (PangoFont *font,
|
|||||||
node = (GskRenderNode *) self;
|
node = (GskRenderNode *) self;
|
||||||
|
|
||||||
self->font = g_object_ref (font);
|
self->font = g_object_ref (font);
|
||||||
self->has_color_glyphs = font_has_color_glyphs (font);
|
|
||||||
self->color = *color;
|
self->color = *color;
|
||||||
self->offset = *offset;
|
self->offset = *offset;
|
||||||
self->glyphs = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo));
|
self->has_color_glyphs = FALSE;
|
||||||
|
|
||||||
/* skip empty glyphs */
|
glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo));
|
||||||
self->num_glyphs = 0;
|
has_color_glyphs = font_has_color_glyphs (font);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
for (int i = 0; i < glyphs->num_glyphs; i++)
|
for (int i = 0; i < glyphs->num_glyphs; i++)
|
||||||
{
|
{
|
||||||
if (glyphs->glyphs[i].glyph != PANGO_GLYPH_EMPTY)
|
/* skip empty glyphs */
|
||||||
self->glyphs[self->num_glyphs++] = glyphs->glyphs[i];
|
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,
|
graphene_rect_init (&node->bounds,
|
||||||
offset->x + ink_rect.x - 1,
|
offset->x + ink_rect.x - 1,
|
||||||
offset->y + ink_rect.y - 1,
|
offset->y + ink_rect.y - 1,
|
||||||
|
@ -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
|
static inline void
|
||||||
gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
||||||
const GskRenderNode *node,
|
const GskRenderNode *node,
|
||||||
@ -2855,7 +2858,9 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
|||||||
guint last_texture = 0;
|
guint last_texture = 0;
|
||||||
GskNglDrawVertex *vertices;
|
GskNglDrawVertex *vertices;
|
||||||
guint used = 0;
|
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;
|
const PangoGlyphInfo *gi;
|
||||||
guint i;
|
guint i;
|
||||||
int yshift;
|
int yshift;
|
||||||
@ -2864,16 +2869,11 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
|||||||
if (num_glyphs == 0)
|
if (num_glyphs == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If the font has color glyphs, we don't need to recolor anything.
|
if ((force_color || !gsk_text_node_has_color_glyphs (node)) &&
|
||||||
* We tell the shader by setting the color to vec4(-1).
|
RGBA_IS_CLEAR (color))
|
||||||
*/
|
return;
|
||||||
if (force_color || !gsk_text_node_has_color_glyphs (node))
|
|
||||||
{
|
|
||||||
if (RGBA_IS_CLEAR (color))
|
|
||||||
return;
|
|
||||||
|
|
||||||
rgba_to_half (color, c);
|
rgba_to_half (color, cc);
|
||||||
}
|
|
||||||
|
|
||||||
lookup.font = (PangoFont *)font;
|
lookup.font = (PangoFont *)font;
|
||||||
lookup.scale = (guint) (text_scale * 1024);
|
lookup.scale = (guint) (text_scale * 1024);
|
||||||
@ -2897,6 +2897,14 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
|
|||||||
|
|
||||||
lookup.glyph = gi->glyph;
|
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;
|
cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
|
||||||
lookup.xshift = compute_phase_and_pos (x + cx, &cx);
|
lookup.xshift = compute_phase_and_pos (x + cx, &cx);
|
||||||
|
|
||||||
|
@ -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'])
|
default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false'])
|
||||||
epoxy_dep = dependency('epoxy', version: epoxy_req,
|
epoxy_dep = dependency('epoxy', version: epoxy_req,
|
||||||
fallback: ['libepoxy', 'libepoxy_dep'])
|
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'],
|
fallback: ['harfbuzz', 'libharfbuzz_dep'],
|
||||||
default_options: ['coretext=enabled'])
|
default_options: ['coretext=enabled'])
|
||||||
xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
|
xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
|
||||||
|
Loading…
Reference in New Issue
Block a user