[gtk/color-glyph-fixes: 2/2] gsk: Use harfbuzz for color fonts




commit 758cac0b2f47e659a3ec5a84922edc16dde66eac
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jul 31 15:22:14 2021 -0400

    gsk: Use harfbuzz for color fonts
    
    harfbuzz has all the information we need, so we
    can avoid poking directly at freetype apis. Also
    drop the caching of color glyph information until
    it turns out to be a problem.

 gsk/gskrendernodeimpl.c | 150 +++++++++++++++---------------------------------
 1 file changed, 45 insertions(+), 105 deletions(-)
---
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index c44ce88784..5e07a8f92a 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -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,
@@ -4425,119 +4425,45 @@ 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)
-    {
-      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);
-    }
-
-  return has_color;
+  return hb_ot_color_has_layers (face) ||
+         hb_ot_color_has_png (face) ||
+         hb_ot_color_has_svg (face);
 }
 
 static gboolean
-glyph_has_color (FT_Face face,
-                 guint   glyph)
+glyph_has_color (PangoFont *font,
+                 guint      glyph)
 {
-  FT_Error error;
+  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;
 
-  error = FT_Load_Glyph (face, glyph, FT_LOAD_COLOR);
-  if (error != 0)
-    return FALSE;
-
-  error = FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL);
-  if (error != 0)
-    return FALSE;
-
-  if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
+  if (hb_ot_color_glyph_get_layers (face, glyph, 0, NULL, NULL) > 0)
     return TRUE;
 
-  return FALSE;
-}
-
-static GHashTable *
-ensure_color_glyph_cache (const PangoFont *font)
-{
-  GHashTable *cache;
-
-  cache = (GHashTable *) g_object_get_data (G_OBJECT (font), "gsk-color-glyph-cache");
-  if (!cache)
+  blob = hb_ot_color_glyph_reference_png (hb_font, glyph);
+  if (blob)
     {
-      cache = g_hash_table_new (NULL, NULL);
-      g_object_set_data_full (G_OBJECT (font), "gsk-color-glyph-cache",
-                              cache, (GDestroyNotify) g_hash_table_unref);
+      guint length = hb_blob_get_length (blob);
+      hb_blob_destroy (blob);
+      return length > 0;
     }
 
-  return cache;
-}
-
-static inline gboolean
-lookup_color_glyph_cache (GHashTable *cache,
-                          PangoGlyph  glyph,
-                          gboolean   *has_color)
-{
-  gpointer value;
-
-  if (g_hash_table_lookup_extended (cache, GUINT_TO_POINTER (glyph), NULL, &value))
+  blob = hb_ot_color_glyph_reference_svg (face, glyph);
+  if (blob)
     {
-      *has_color = GPOINTER_TO_UINT (value);
-      return TRUE;
+      guint length = hb_blob_get_length (blob);
+      hb_blob_destroy (blob);
+      return length > 0;
     }
 
   return FALSE;
 }
 
-static inline void
-insert_color_glyph_cache (GHashTable *cache,
-                          PangoGlyph  glyph,
-                          gboolean has_color)
-{
-  g_hash_table_insert (cache, GUINT_TO_POINTER (glyph), GUINT_TO_POINTER (has_color));
-}
-
-static void
-mark_color_glyphs (const PangoFont *font,
-                   PangoGlyphInfo  *glyphs,
-                   int              num_glyphs)
-{
-  cairo_scaled_font_t *scaled_font;
-  FT_Face ft_face;
-  GHashTable *cache;
-
-  scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)font);
-  if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_FT)
-    return;
-
-  ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
-  if (!FT_HAS_COLOR (ft_face))
-    goto out;
-
-  cache = ensure_color_glyph_cache (font);
-
-  for (int i = 0; i < num_glyphs; i++)
-    {
-      gboolean has_color;
-
-      if (!lookup_color_glyph_cache (cache, glyphs[i].glyph, &has_color))
-        {
-          has_color = glyph_has_color (ft_face, glyphs[i].glyph);
-          insert_color_glyph_cache (cache, glyphs[i].glyph, has_color);
-        }
-
-      if (has_color)
-        GLYPH_SET_COLOR (&glyphs[i]);
-    }
-
-out:
-  cairo_ft_scaled_font_unlock_face (scaled_font);
-}
-
 /**
  * gsk_text_node_new:
  * @font: the `PangoFont` containing the glyphs
@@ -4561,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);
@@ -4573,24 +4502,35 @@ 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)
+      /* 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->glyphs[self->num_glyphs] = glyphs->glyphs[i];
-          GLYPH_CLEAR_COLOR (&self->glyphs[self->num_glyphs]);
-          self->num_glyphs++;
+          self->has_color_glyphs = TRUE;
+          GLYPH_SET_COLOR (&glyph_infos[n]);
         }
+
+      n++;
     }
 
-  mark_color_glyphs (font, self->glyphs, self->num_glyphs);
+  self->glyphs = glyph_infos;
+  self->num_glyphs = n;
 
   graphene_rect_init (&node->bounds,
                       offset->x + ink_rect.x - 1,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]