[pango/code-reorg: 2/10] Some more code reorg




commit 24061b2f48257e72f47637829a7ea99079e2a376
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Aug 20 11:34:28 2021 -0400

    Some more code reorg
    
    We use harfbuzz shaping on all platforms now, so
    just merge the code into shape.c

 pango/meson.build     |   1 -
 pango/pangofc-shape.c | 425 -------------------------------------
 pango/shape.c         | 577 +++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 496 insertions(+), 507 deletions(-)
---
diff --git a/pango/meson.build b/pango/meson.build
index b97809a1..084de229 100644
--- a/pango/meson.build
+++ b/pango/meson.build
@@ -27,7 +27,6 @@ pango_sources = [
   'pango-utils.c',
   'reorder-items.c',
   'shape.c',
-  'pangofc-shape.c',
 ]
 
 pango_headers = [
diff --git a/pango/shape.c b/pango/shape.c
index afb1db0d..f10bd5c9 100644
--- a/pango/shape.c
+++ b/pango/shape.c
@@ -10,7 +10,7 @@
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
@@ -21,13 +21,473 @@
 
 #include "config.h"
 
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+
 #include "pango-impl-utils.h"
 #include "pango-glyph.h"
 
 #include "pangohb-private.h"
 #include "pango-font-private.h"
 
-#include <string.h>
+/* {{{ Harfbuzz shaping */
+
+/* {{{{ Buffer handling */
+static hb_buffer_t *cached_buffer = NULL; /* MT-safe */
+G_LOCK_DEFINE_STATIC (cached_buffer);
+
+static hb_buffer_t *
+acquire_buffer (gboolean *free_buffer)
+{
+  hb_buffer_t *buffer;
+
+  if (G_LIKELY (G_TRYLOCK (cached_buffer)))
+    {
+      if (G_UNLIKELY (!cached_buffer))
+        cached_buffer = hb_buffer_create ();
+
+      buffer = cached_buffer;
+      *free_buffer = FALSE;
+    }
+  else
+    {
+      buffer = hb_buffer_create ();
+      *free_buffer = TRUE;
+    }
+
+  return buffer;
+}
+
+static void
+release_buffer (hb_buffer_t *buffer,
+                gboolean     free_buffer)
+{
+  if (G_LIKELY (!free_buffer))
+    {
+      hb_buffer_reset (buffer);
+      G_UNLOCK (cached_buffer);
+    }
+  else
+    hb_buffer_destroy (buffer);
+}
+/* }}}} */
+/* {{{{ Use PangoFont with Harfbuzz */
+
+typedef struct
+{
+  PangoFont *font;
+  hb_font_t *parent;
+  PangoShowFlags show_flags;
+} PangoHbShapeContext;
+
+static hb_bool_t
+pango_hb_font_get_nominal_glyph (hb_font_t      *font,
+                                 void           *font_data,
+                                 hb_codepoint_t  unicode,
+                                 hb_codepoint_t *glyph,
+                                 void           *user_data G_GNUC_UNUSED)
+{
+  PangoHbShapeContext *context = (PangoHbShapeContext *) font_data;
+
+  if (context->show_flags != 0)
+    {
+      if ((context->show_flags & PANGO_SHOW_SPACES) != 0 &&
+          g_unichar_type (unicode) == G_UNICODE_SPACE_SEPARATOR)
+        {
+          /* Replace 0x20 by visible space, since we
+           * don't draw a hex box for 0x20
+           */
+          if (unicode == 0x20)
+            *glyph = PANGO_GET_UNKNOWN_GLYPH (0x2423);
+          else
+            *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode);
+          return TRUE;
+        }
+
+      if ((context->show_flags & PANGO_SHOW_IGNORABLES) != 0 &&
+          pango_get_ignorable (unicode))
+        {
+          *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode);
+          return TRUE;
+        }
+
+      if ((context->show_flags & PANGO_SHOW_LINE_BREAKS) != 0 &&
+          unicode == 0x2028)
+        {
+          /* Always mark LS as unknown. If it ends up
+           * at the line end, PangoLayout takes care of
+           * hiding them, and if they end up in the middle
+           * of a line, we are in single paragraph mode
+           * and want to show the LS
+           */
+          *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode);
+          return TRUE;
+        }
+    }
+
+  if (hb_font_get_nominal_glyph (context->parent, unicode, glyph))
+    return TRUE;
+
+  *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode);
+
+  /* We draw our own invalid-Unicode shape, so prevent HarfBuzz
+   * from using REPLACEMENT CHARACTER. */
+  if (unicode > 0x10FFFF)
+    return TRUE;
+
+  return FALSE;
+}
+
+static hb_position_t
+pango_hb_font_get_glyph_h_advance (hb_font_t      *font,
+                                   void           *font_data,
+                                   hb_codepoint_t  glyph,
+                                   void           *user_data G_GNUC_UNUSED)
+{
+  PangoHbShapeContext *context = (PangoHbShapeContext *) font_data;
+
+  if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    {
+      PangoRectangle logical;
+
+      pango_font_get_glyph_extents (context->font, glyph, NULL, &logical);
+      return logical.width;
+    }
+
+  return hb_font_get_glyph_h_advance (context->parent, glyph);
+}
+
+static hb_position_t
+pango_hb_font_get_glyph_v_advance (hb_font_t      *font,
+                                   void           *font_data,
+                                   hb_codepoint_t  glyph,
+                                   void           *user_data G_GNUC_UNUSED)
+{
+  PangoHbShapeContext *context = (PangoHbShapeContext *) font_data;
+
+  if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    {
+      PangoRectangle logical;
+
+      pango_font_get_glyph_extents (context->font, glyph, NULL, &logical);
+      return logical.height;
+    }
+
+  return hb_font_get_glyph_v_advance (context->parent, glyph);
+}
+
+static hb_bool_t
+pango_hb_font_get_glyph_extents (hb_font_t          *font,
+                                 void               *font_data,
+                                 hb_codepoint_t      glyph,
+                                 hb_glyph_extents_t *extents,
+                                 void               *user_data G_GNUC_UNUSED)
+{
+  PangoHbShapeContext *context = (PangoHbShapeContext *) font_data;
+
+  if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+    {
+      PangoRectangle ink;
+
+      pango_font_get_glyph_extents (context->font, glyph, &ink, NULL);
+
+      extents->x_bearing = ink.x;
+      extents->y_bearing = ink.y;
+      extents->width     = ink.width;
+      extents->height    = ink.height;
+
+      return TRUE;
+    }
+
+  return hb_font_get_glyph_extents (context->parent, glyph, extents);
+}
+
+static hb_font_t *
+pango_font_get_hb_font_for_context (PangoFont           *font,
+                                    PangoHbShapeContext *context)
+{
+  hb_font_t *hb_font;
+  static hb_font_funcs_t *funcs;
+
+  hb_font = pango_font_get_hb_font (font);
+
+  if (G_UNLIKELY (!funcs))
+    {
+      funcs = hb_font_funcs_create ();
+
+      hb_font_funcs_set_nominal_glyph_func (funcs, pango_hb_font_get_nominal_glyph, NULL, NULL);
+      hb_font_funcs_set_glyph_h_advance_func (funcs, pango_hb_font_get_glyph_h_advance, NULL, NULL);
+      hb_font_funcs_set_glyph_v_advance_func (funcs, pango_hb_font_get_glyph_v_advance, NULL, NULL);
+      hb_font_funcs_set_glyph_extents_func (funcs, pango_hb_font_get_glyph_extents, NULL, NULL);
+
+      hb_font_funcs_make_immutable (funcs);
+    }
+
+  context->font = font;
+  context->parent = hb_font;
+
+  hb_font = hb_font_create_sub_font (hb_font);
+  hb_font_set_funcs (hb_font, funcs, context, NULL);
+
+  return hb_font;
+}
+
+/* }}}} */
+/* {{{{ Utilities */
+static void
+apply_extra_attributes (GSList       *attrs,
+                        hb_feature_t *features,
+                        guint         length,
+                        guint        *num_features)
+{
+  GSList *l;
+
+  for (l = attrs; l && *num_features < length; l = l->next)
+    {
+      PangoAttribute *attr = l->data;
+      if (attr->klass->type == PANGO_ATTR_FONT_FEATURES)
+        {
+          PangoAttrFontFeatures *fattr = (PangoAttrFontFeatures *) attr;
+          const gchar *feat;
+          const gchar *end;
+          int len;
+
+          feat = fattr->features;
+
+          while (feat != NULL && *num_features < length)
+            {
+              end = strchr (feat, ',');
+              if (end)
+                len = end - feat;
+              else
+                len = -1;
+              if (hb_feature_from_string (feat, len, &features[*num_features]))
+                {
+                  features[*num_features].start = attr->start_index;
+                  features[*num_features].end = attr->end_index;
+                  (*num_features)++;
+                }
+
+              if (end == NULL)
+                break;
+
+              feat = end + 1;
+            }
+        }
+    }
+
+  /* Turn off ligatures when letterspacing */
+  for (l = attrs; l && *num_features < length; l = l->next)
+    {
+      PangoAttribute *attr = l->data;
+      if (attr->klass->type == PANGO_ATTR_LETTER_SPACING)
+        {
+          hb_tag_t tags[] = {
+            HB_TAG('l','i','g','a'),
+            HB_TAG('c','l','i','g'),
+            HB_TAG('d','l','i','g'),
+          };
+          int i;
+          for (i = 0; i < G_N_ELEMENTS (tags); i++)
+            {
+              features[*num_features].tag = tags[i];
+              features[*num_features].value = 0;
+              features[*num_features].start = attr->start_index;
+              features[*num_features].end = attr->end_index;
+              (*num_features)++;
+            }
+        }
+    }
+}
+
+static PangoShowFlags
+find_show_flags (const PangoAnalysis *analysis)
+{
+  GSList *l;
+  PangoShowFlags flags = 0;
+
+  for (l = analysis->extra_attrs; l; l = l->next)
+    {
+      PangoAttribute *attr = l->data;
+
+      if (attr->klass->type == PANGO_ATTR_SHOW)
+        flags |= ((PangoAttrInt*)attr)->value;
+    }
+
+  return flags;
+}
+
+/* }}}} */
+void
+pango_hb_shape (PangoFont           *font,
+                const char          *item_text,
+                unsigned int         item_length,
+                const PangoAnalysis *analysis,
+                PangoGlyphString    *glyphs,
+                const char          *paragraph_text,
+                unsigned int         paragraph_length)
+{
+  PangoHbShapeContext context = { 0, };
+  hb_buffer_flags_t hb_buffer_flags;
+  hb_font_t *hb_font;
+  hb_buffer_t *hb_buffer;
+  hb_direction_t hb_direction;
+  gboolean free_buffer;
+  hb_glyph_info_t *hb_glyph;
+  hb_glyph_position_t *hb_position;
+  int last_cluster;
+  guint i, num_glyphs;
+  unsigned int item_offset = item_text - paragraph_text;
+  hb_feature_t features[32];
+  unsigned int num_features = 0;
+  PangoGlyphInfo *infos;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (analysis != NULL);
+
+  context.show_flags = find_show_flags (analysis);
+  hb_font = pango_font_get_hb_font_for_context (font, &context);
+  hb_buffer = acquire_buffer (&free_buffer);
+
+  hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR;
+  if (analysis->level % 2)
+    hb_direction = HB_DIRECTION_REVERSE (hb_direction);
+  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
+    hb_direction = HB_DIRECTION_REVERSE (hb_direction);
+
+  hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT;
+
+  if (context.show_flags & PANGO_SHOW_IGNORABLES)
+    hb_buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
+
+  /* setup buffer */
+
+  hb_buffer_set_direction (hb_buffer, hb_direction);
+  hb_buffer_set_script (hb_buffer, (hb_script_t) g_unicode_script_to_iso15924 (analysis->script));
+  hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), 
-1));
+  hb_buffer_set_cluster_level (hb_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+  hb_buffer_set_flags (hb_buffer, hb_buffer_flags);
+  hb_buffer_set_invisible_glyph (hb_buffer, PANGO_GLYPH_EMPTY);
+
+  hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_offset, item_length);
+  if (analysis->flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN)
+    {
+      /* Insert either a Unicode or ASCII hyphen. We may
+       * want to look for script-specific hyphens here.
+       */
+      const char *p = paragraph_text + item_offset + item_length;
+      int last_char_len = p - g_utf8_prev_char (p);
+      hb_codepoint_t glyph;
+
+      if (hb_font_get_nominal_glyph (hb_font, 0x2010, &glyph))
+        hb_buffer_add (hb_buffer, 0x2010, item_offset + item_length - last_char_len);
+      else if (hb_font_get_nominal_glyph (hb_font, '-', &glyph))
+        hb_buffer_add (hb_buffer, '-', item_offset + item_length - last_char_len);
+    }
+
+  pango_font_get_features (font, features, G_N_ELEMENTS (features), &num_features);
+  apply_extra_attributes (analysis->extra_attrs, features, G_N_ELEMENTS (features), &num_features);
+
+  hb_shape (hb_font, hb_buffer, features, num_features);
+
+  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
+    hb_buffer_reverse (hb_buffer);
+
+  /* buffer output */
+  num_glyphs = hb_buffer_get_length (hb_buffer);
+  hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);
+  pango_glyph_string_set_size (glyphs, num_glyphs);
+  infos = glyphs->glyphs;
+  last_cluster = -1;
+  for (i = 0; i < num_glyphs; i++)
+    {
+      infos[i].glyph = hb_glyph->codepoint;
+      glyphs->log_clusters[i] = hb_glyph->cluster - item_offset;
+      infos[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
+      hb_glyph++;
+      last_cluster = glyphs->log_clusters[i];
+    }
+
+  hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL);
+  if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity))
+    for (i = 0; i < num_glyphs; i++)
+      {
+        /* 90 degrees rotation counter-clockwise. */
+        infos[i].geometry.width    = - hb_position->y_advance;
+        infos[i].geometry.x_offset = - hb_position->y_offset;
+        infos[i].geometry.y_offset = - hb_position->x_offset;
+        hb_position++;
+      }
+  else /* horizontal */
+    for (i = 0; i < num_glyphs; i++)
+      {
+        infos[i].geometry.width    =   hb_position->x_advance;
+        infos[i].geometry.x_offset =   hb_position->x_offset;
+        infos[i].geometry.y_offset = - hb_position->y_offset;
+        hb_position++;
+      }
+
+  release_buffer (hb_buffer, free_buffer);
+  hb_font_destroy (hb_font);
+}
+
+/* }}} */
+/* {{{ Fallback shaping */
+
+/* This is not meant to produce reasonable results */
+
+static void
+fallback_shape (const char          *text,
+                unsigned int         length,
+                const PangoAnalysis *analysis,
+                PangoGlyphString    *glyphs)
+{
+  int n_chars;
+  const char *p;
+  int cluster = 0;
+  int i;
+
+  n_chars = text ? pango_utf8_strlen (text, length) : 0;
+
+  pango_glyph_string_set_size (glyphs, n_chars);
+
+  p = text;
+  for (i = 0; i < n_chars; i++)
+    {
+      gunichar wc;
+      PangoGlyph glyph;
+      PangoRectangle logical_rect;
+
+      wc = g_utf8_get_char (p);
+
+      if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK)
+        cluster = p - text;
+
+      if (pango_is_zero_width (wc))
+        glyph = PANGO_GLYPH_EMPTY;
+      else
+        glyph = PANGO_GET_UNKNOWN_GLYPH (wc);
+
+      pango_font_get_glyph_extents (analysis->font, glyph, NULL, &logical_rect);
+
+      glyphs->glyphs[i].glyph = glyph;
+
+      glyphs->glyphs[i].geometry.x_offset = 0;
+      glyphs->glyphs[i].geometry.y_offset = 0;
+      glyphs->glyphs[i].geometry.width = logical_rect.width;
+
+      glyphs->log_clusters[i] = cluster;
+
+      p = g_utf8_next_char (p);
+    }
+
+  if (analysis->level & 1)
+    pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
+}
+
+/* }}} */
+/* {{{ Public API */
 
 /**
  * pango_shape:
@@ -52,10 +512,10 @@
  * calling [func@shape].
  */
 void
-pango_shape (const gchar         *text,
-            gint                 length,
-            const PangoAnalysis *analysis,
-            PangoGlyphString    *glyphs)
+pango_shape (const char          *text,
+             int                  length,
+             const PangoAnalysis *analysis,
+             PangoGlyphString    *glyphs)
 {
   pango_shape_full (text, length, text, length, analysis, glyphs);
 }
@@ -103,55 +563,6 @@ pango_shape_full (const char          *item_text,
                           PANGO_SHAPE_NONE);
 }
 
-static void
-fallback_shape (const char          *text,
-                unsigned int         length,
-                const PangoAnalysis *analysis,
-                PangoGlyphString    *glyphs)
-{
-  int n_chars;
-  const char *p;
-  int cluster = 0;
-  int i;
-
-  n_chars = text ? pango_utf8_strlen (text, length) : 0;
-
-  pango_glyph_string_set_size (glyphs, n_chars);
-
-  p = text;
-  for (i = 0; i < n_chars; i++)
-    {
-      gunichar wc;
-      PangoGlyph glyph;
-      PangoRectangle logical_rect;
-
-      wc = g_utf8_get_char (p);
-
-      if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK)
-        cluster = p - text;
-
-      if (pango_is_zero_width (wc))
-        glyph = PANGO_GLYPH_EMPTY;
-      else
-        glyph = PANGO_GET_UNKNOWN_GLYPH (wc);
-
-      pango_font_get_glyph_extents (analysis->font, glyph, NULL, &logical_rect);
-
-      glyphs->glyphs[i].glyph = glyph;
-
-      glyphs->glyphs[i].geometry.x_offset = 0;
-      glyphs->glyphs[i].geometry.y_offset = 0;
-      glyphs->glyphs[i].geometry.width = logical_rect.width;
-
-      glyphs->log_clusters[i] = cluster;
-
-      p = g_utf8_next_char (p);
-    }
-
-  if (analysis->level & 1)
-    pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
-}
-
 /**
  * pango_shape_with_flags:
  * @item_text: valid UTF-8 text to shape
@@ -183,10 +594,10 @@ fallback_shape (const char          *text,
  * Since: 1.44
  */
 void
-pango_shape_with_flags (const gchar         *item_text,
-                        gint                 item_length,
-                        const gchar         *paragraph_text,
-                        gint                 paragraph_length,
+pango_shape_with_flags (const char         *item_text,
+                        int                 item_length,
+                        const char         *paragraph_text,
+                        int                  paragraph_length,
                         const PangoAnalysis *analysis,
                         PangoGlyphString    *glyphs,
                         PangoShapeFlags      flags)
@@ -218,19 +629,19 @@ pango_shape_with_flags (const gchar         *item_text,
                       paragraph_text, paragraph_length);
 
       if (G_UNLIKELY (glyphs->num_glyphs == 0))
-       {
-         /* If a font has been correctly chosen, but no glyphs are output,
-          * there's probably something wrong with the font.
-          *
-          * Trying to be informative, we print out the font description,
-          * and the text, but to not flood the terminal with
-          * zillions of the message, we set a flag to only err once per
-          * font.
-          */
+        {
+          /* If a font has been correctly chosen, but no glyphs are output,
+           * there's probably something wrong with the font.
+           *
+           * Trying to be informative, we print out the font description,
+           * and the text, but to not flood the terminal with
+           * zillions of the message, we set a flag to only err once per
+           * font.
+           */
           GQuark warned_quark = g_quark_from_static_string ("pango-shape-fail-warned");
 
-         if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark))
-           {
+          if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark))
+            {
               PangoFontDescription *desc;
               char *font_name;
 
@@ -246,7 +657,7 @@ pango_shape_with_flags (const gchar         *item_text,
               g_object_set_qdata (G_OBJECT (analysis->font), warned_quark,
                                   GINT_TO_POINTER (1));
             }
-       }
+        }
     }
   else
     glyphs->num_glyphs = 0;
@@ -264,12 +675,12 @@ pango_shape_with_flags (const gchar         *item_text,
     {
       /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */
       if (glyphs->log_clusters[i] != last_cluster)
-       {
-         glyphs->glyphs[i].attr.is_cluster_start = TRUE;
-         last_cluster = glyphs->log_clusters[i];
-       }
+        {
+          glyphs->glyphs[i].attr.is_cluster_start = TRUE;
+          last_cluster = glyphs->log_clusters[i];
+        }
       else
-       glyphs->glyphs[i].attr.is_cluster_start = FALSE;
+        glyphs->glyphs[i].attr.is_cluster_start = FALSE;
 
 
       /* Shift glyph if width is negative, and negate width.
@@ -277,15 +688,15 @@ pango_shape_with_flags (const gchar         *item_text,
        * harm in normal cases.
        */
       if (glyphs->glyphs[i].geometry.width < 0)
-       {
-         glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width;
-         glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
-       }
+        {
+          glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width;
+          glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
+        }
     }
 
   /* Make sure glyphstring direction conforms to analysis->level */
   if (G_UNLIKELY ((analysis->level & 1) &&
-                 glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
+                  glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
     {
       g_warning ("Expected RTL run but got LTR. Fixing.");
 
@@ -355,3 +766,7 @@ pango_shape_with_flags (const gchar         *item_text,
         }
     }
 }
+
+/* }}} */
+
+/* vim:set foldmethod=marker expandtab: */


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