[gtk/pango2] fontexplorer: Show glyph layers



commit 390ec02e05f1f60aee9071751bd399cbc8abe9b7
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jul 9 22:08:35 2022 -0400

    fontexplorer: Show glyph layers
    
    Let the user cycle through the layers of color glyphs
    by clicking on them.

 demos/font-explorer/fontview.c  |   8 +-
 demos/font-explorer/glyphview.c | 203 ++++++++++++++++++++++++++++++++++++----
 demos/font-explorer/glyphview.h |   2 +
 3 files changed, 193 insertions(+), 20 deletions(-)
---
diff --git a/demos/font-explorer/fontview.c b/demos/font-explorer/fontview.c
index 58252f74ca..8364dc636c 100644
--- a/demos/font-explorer/fontview.c
+++ b/demos/font-explorer/fontview.c
@@ -40,6 +40,7 @@ struct _FontView
   char *variations;
   char *features;
   char *palette;
+  GQuark palette_quark;
   int letterspacing;
   float line_height;
   GdkRGBA foreground;
@@ -68,6 +69,7 @@ font_view_init (FontView *self)
   self->variations = g_strdup ("");
   self->features = g_strdup ("");
   self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
+  self->palette_quark = g_quark_from_string (self->palette);
   self->foreground = (GdkRGBA){0., 0., 0., 1. };
   self->background = (GdkRGBA){1., 1., 1., 1. };
   self->sample_text = g_strdup ("Some sample text is better than other sample text");
@@ -309,7 +311,8 @@ setup_glyph (GtkSignalListItemFactory *factory,
 
 static void
 bind_glyph (GtkSignalListItemFactory *factory,
-            GObject                  *listitem)
+            GObject                  *listitem,
+            FontView                 *self)
 {
   GlyphView *view;
   GObject *item;
@@ -318,6 +321,7 @@ bind_glyph (GtkSignalListItemFactory *factory,
   item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
   glyph_view_set_font (view, glyph_item_get_font (GLYPH_ITEM (item)));
   glyph_view_set_glyph (view, glyph_item_get_glyph (GLYPH_ITEM (item)));
+  glyph_view_set_palette (view, self->palette_quark);
 }
 
 static GtkWidget *
@@ -597,6 +601,8 @@ font_view_set_property (GObject      *object,
     case PROP_PALETTE:
       g_free (self->palette);
       self->palette = g_strdup (g_value_get_string (value));
+      self->palette_quark = g_quark_from_string (self->palette);
+      update_glyph_model (self);
       break;
 
     case PROP_SAMPLE_TEXT:
diff --git a/demos/font-explorer/glyphview.c b/demos/font-explorer/glyphview.c
index 5462403bed..2fd47a6ed7 100644
--- a/demos/font-explorer/glyphview.c
+++ b/demos/font-explorer/glyphview.c
@@ -7,7 +7,11 @@ struct _GlyphView
   GtkWidget parent;
 
   Pango2Font *font;
+  GQuark palette;
+  int palette_index;
   hb_codepoint_t glyph;
+  int n_layers;
+  int layer;
 };
 
 struct _GlyphViewClass
@@ -17,9 +21,35 @@ struct _GlyphViewClass
 
 G_DEFINE_TYPE(GlyphView, glyph_view, GTK_TYPE_WIDGET);
 
+static void
+click_cb (GtkGestureClick *gesture,
+          int              n_press,
+          double           x,
+          double           y,
+          GlyphView       *self)
+{
+  if (self->n_layers == 0)
+    return;
+
+  self->layer++;
+
+  if (self->layer == self->n_layers)
+    self->layer = -1;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
 static void
 glyph_view_init (GlyphView *self)
 {
+  GtkGesture *click;
+
+  self->n_layers = 0;
+  self->layer = -1;
+
+  click = gtk_gesture_click_new ();
+  g_signal_connect (click, "pressed", G_CALLBACK (click_cb), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (click));
 }
 
 static void
@@ -45,28 +75,75 @@ glyph_view_snapshot (GtkWidget   *widget,
 
   pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
 
+  width = gtk_widget_get_width (widget);
+  height = gtk_widget_get_height (widget);
+
+  cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
+
   glyphs = pango2_glyph_string_new ();
   pango2_glyph_string_set_size (glyphs, 1);
-  glyphs->glyphs[0].glyph = self->glyph;
+
   glyphs->glyphs[0].geometry.width = ink.width;
   glyphs->glyphs[0].geometry.x_offset = ink.x;
   glyphs->glyphs[0].geometry.y_offset = -ink.y;
 
-  width = gtk_widget_get_width (widget);
-  height = gtk_widget_get_height (widget);
+  if (self->layer == -1)
+    {
+      glyphs->glyphs[0].glyph = self->glyph;
+      cairo_set_source_rgb (cr, 0, 0, 0);
+    }
+  else
+    {
+      hb_face_t *face = hb_font_get_face (pango2_font_get_hb_font (self->font));
+      hb_ot_color_layer_t *layers;
+      unsigned int count;
 
-  cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
+      layers = g_newa (hb_ot_color_layer_t, self->n_layers);
+      count = self->n_layers;
+      hb_ot_color_glyph_get_layers (face,
+                                    self->glyph,
+                                    0,
+                                    &count,
+                                    layers);
+      glyphs->glyphs[0].glyph = layers[self->layer].glyph;
+      if (layers[self->layer].color_index == 0xffff)
+        {
+          cairo_set_source_rgb (cr, 0, 0, 0);
+        }
+      else
+        {
+          hb_color_t *colors;
+          unsigned int n_colors;
+          hb_color_t color;
+
+          n_colors = hb_ot_color_palette_get_colors (face,
+                                                     self->palette_index,
+                                                     0,
+                                                     NULL,
+                                                     NULL);
+          colors = g_newa (hb_color_t, n_colors);
+          hb_ot_color_palette_get_colors (face,
+                                          self->palette_index,
+                                          0,
+                                          &n_colors,
+                                          colors);
+          color = colors[layers[self->layer].color_index];
+          cairo_set_source_rgba (cr, hb_color_get_red (color)/255.,
+                                     hb_color_get_green (color)/255.,
+                                     hb_color_get_blue (color)/255.,
+                                     hb_color_get_alpha (color)/255.);
+        }
+    }
 
-  cairo_set_source_rgb (cr, 0, 0, 0);
   cairo_move_to (cr, (width - logical.width/1024.)/2, (height - logical.height/1024.)/2);
-  pango2_cairo_show_glyph_string (cr, self->font, glyphs);
+  pango2_cairo_show_color_glyph_string (cr, self->font, self->palette, glyphs);
 
-  if (hb_font_get_glyph_name (pango2_font_get_hb_font (self->font), self->glyph, name, sizeof (name)))
     {
       Pango2Layout *layout;
       Pango2FontDescription *desc;
-      int w, h;
       char gid[20];
+      hb_font_t *hb_font;
+      hb_face_t *hb_face;
 
       g_snprintf (gid, sizeof (gid), "%d", self->glyph);
       layout = gtk_widget_create_pango_layout (widget, gid);
@@ -78,19 +155,64 @@ glyph_view_snapshot (GtkWidget   *widget,
       gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, 5));
       gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,0.7});
       gtk_snapshot_restore (snapshot);
-      g_object_unref (layout);
 
-      layout = gtk_widget_create_pango_layout (widget, name);
-      desc = pango2_font_description_from_string ("Cantarell 8");
-      pango2_layout_set_font_description (layout, desc);
-      pango2_font_description_free (desc);
+      hb_font = pango2_font_get_hb_font (self->font);
+      hb_face = hb_font_get_face (hb_font);
 
-      pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
+      if (hb_ot_layout_has_glyph_classes (hb_face))
+        {
+          hb_ot_layout_glyph_class_t class;
+          const char *class_names[] = {
+            NULL, "Base", "Ligature", "Mark", "Component"
+          };
+          int w, h;
+
+          class = hb_ot_layout_get_glyph_class (hb_face, self->glyph);
+
+          if (class != HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
+            {
+              pango2_layout_set_text (layout, class_names[class], -1);
+              pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
+
+              gtk_snapshot_save (snapshot);
+              gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, 5));
+              gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
+              gtk_snapshot_restore (snapshot);
+            }
+        }
+
+      if (hb_font_get_glyph_name (hb_font, self->glyph, name, sizeof (name)))
+        {
+          int w, h;
+
+          pango2_layout_set_text (layout, name, -1);
+          pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
+
+          gtk_snapshot_save (snapshot);
+          gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, height - h/1024. - 5));
+          gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
+          gtk_snapshot_restore (snapshot);
+        }
+
+      if (self->n_layers > 0)
+        {
+          char buf[128];
+          int w, h;
+
+          if (self->layer == -1)
+            g_snprintf (buf, sizeof (buf), "%d Layers", self->n_layers);
+          else
+            g_snprintf (buf, sizeof (buf), "Layer %d", self->layer);
+
+          pango2_layout_set_text (layout, buf, -1);
+          pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
+
+          gtk_snapshot_save (snapshot);
+          gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, height - h/1024. - 
5));
+          gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
+          gtk_snapshot_restore (snapshot);
+        }
 
-      gtk_snapshot_save (snapshot);
-      gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, height - h/1024. - 5));
-      gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,1.});
-      gtk_snapshot_restore (snapshot);
       g_object_unref (layout);
     }
 }
@@ -142,6 +264,48 @@ glyph_view_set_font (GlyphView *self,
     gtk_widget_queue_resize (GTK_WIDGET (self));
 }
 
+static unsigned int
+find_palette_index_by_flag (hb_face_t                   *hbface,
+                            hb_ot_color_palette_flags_t  flag)
+{
+  unsigned int n_palettes;
+
+  n_palettes = hb_ot_color_palette_get_count (hbface);
+  for (unsigned int i = 0; i < n_palettes; i++)
+    {
+      if (hb_ot_color_palette_get_flags (hbface, i) & flag)
+        return i;
+    }
+
+  return 0;
+}
+
+void
+glyph_view_set_palette (GlyphView *self,
+                        GQuark     palette)
+{
+  if (self->palette == palette)
+    return;
+
+  self->palette = palette;
+
+  if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DEFAULT))
+    self->palette_index = 0;
+  else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_LIGHT))
+    self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font 
(self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND);
+  else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DARK))
+    self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font 
(self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND);
+  else
+    {
+      const char *str = g_quark_to_string (palette);
+      char *endp;
+      if (g_str_has_prefix (str, "palette"))
+        self->palette_index = g_ascii_strtoll (str + strlen ("palette"), &endp, 10);
+    }
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
 void
 glyph_view_set_glyph (GlyphView      *self,
                       hb_codepoint_t  glyph)
@@ -150,6 +314,7 @@ glyph_view_set_glyph (GlyphView      *self,
     return;
 
   self->glyph = glyph;
-
+  self->n_layers = hb_ot_color_glyph_get_layers (hb_font_get_face (pango2_font_get_hb_font (self->font)), 
glyph, 0, NULL, NULL);
+  self->layer = -1;
   gtk_widget_queue_resize (GTK_WIDGET (self));
 }
diff --git a/demos/font-explorer/glyphview.h b/demos/font-explorer/glyphview.h
index 11c2fa1bd8..c89862dae3 100644
--- a/demos/font-explorer/glyphview.h
+++ b/demos/font-explorer/glyphview.h
@@ -15,5 +15,7 @@ GType       glyph_view_get_type (void);
 GlyphView * glyph_view_new      (void);
 void        glyph_view_set_font (GlyphView *view,
                                  Pango2Font *font);
+void        glyph_view_set_palette (GlyphView *view,
+                                    GQuark     palette);
 void        glyph_view_set_glyph (GlyphView *view,
                                   hb_codepoint_t  glyph);


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