gsk: Use harfbuzz for color fonts
authorMatthias Clasen <mclasen@redhat.com>
Sat, 31 Jul 2021 19:22:14 +0000 (15:22 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 31 Jul 2021 20:34:38 +0000 (16:34 -0400)
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

index c44ce88784003e72450fe1b296b098a084ee8e8a..5e07a8f92a835baf87b96c60caf583721276d548 100644 (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,
@@ -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,