[pango/better-hyphens: 57/66] Don't insert extra runs for hyphens



commit 1074fcae667461fda72fc85551f37a6fe7eb40ac
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Jul 15 20:58:13 2019 -0400

    Don't insert extra runs for hyphens
    
    Instead, reshape the pre-break run with the
    soft hyphen replaced by an actual hyphen.
    This is unfortunately inefficient, we copy
    the entire text for this. The alternative
    (scatter-gather populating the harfbuzz
    buffer) is too hard to manage.

 docs/pango-sections.txt |   1 +
 pango/pango-item.h      |  12 ++++-
 pango/pango-layout.c    | 133 +++++++++++-------------------------------------
 pango/pangofc-shape.c   |  14 +++++
 4 files changed, 56 insertions(+), 104 deletions(-)
---
diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt
index 9d08d0b2..f89debe6 100644
--- a/docs/pango-sections.txt
+++ b/docs/pango-sections.txt
@@ -6,6 +6,7 @@ PangoItem
 PangoAnalysis
 PANGO_ANALYSIS_FLAG_CENTERED_BASELINE
 PANGO_ANALYSIS_FLAG_IS_ELLIPSIS
+PANGO_ANALYSIS_FLAG_NEED_HYPHEN
 PANGO_TYPE_DIRECTION
 
 <SUBSECTION>
diff --git a/pango/pango-item.h b/pango/pango-item.h
index 2a7bcb2a..d4162f90 100644
--- a/pango/pango-item.h
+++ b/pango/pango-item.h
@@ -50,6 +50,16 @@ typedef struct _PangoItem PangoItem;
  */
 #define PANGO_ANALYSIS_FLAG_IS_ELLIPSIS (1 << 1)
 
+/**
+ * PANGO_ANALYSIS_FLAG_NEED_HYPHEN:
+ *
+ * This flag tells Pango to add a hyphen at the end of the
+ * run during shaping.
+ *
+ * Since: 1.44
+ */
+#define PANGO_ANALYSIS_FLAG_NEED_HYPHEN (1 << 2)
+
 /**
  * PangoAnalysis:
  * @shape_engine: unused
@@ -57,7 +67,7 @@ typedef struct _PangoItem PangoItem;
  * @font: the font for this segment.
  * @level: the bidirectional level for this segment.
  * @gravity: the glyph orientation for this segment (A #PangoGravity).
- * @flags: boolean flags for this segment (currently only one) (Since: 1.16).
+ * @flags: boolean flags for this segment (Since: 1.16).
  * @script: the detected script for this segment (A #PangoScript) (Since: 1.18).
  * @language: the detected language for this segment.
  * @extra_attrs: extra attributes for this segment.
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 7735d6f2..2387e1cd 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -3337,9 +3337,9 @@ shape_run (PangoLayoutLine *line,
                            state->properties.shape_ink_rect, state->properties.shape_logical_rect,
                            glyphs);
       else
-       pango_shape_full (layout->text + item->offset, item->length,
-                         layout->text, layout->length,
-                         &item->analysis, glyphs);
+        pango_shape_full (layout->text + item->offset, item->length,
+                          layout->text, layout->length,
+                          &item->analysis, glyphs);
 
       if (state->properties.letter_spacing)
        {
@@ -3395,73 +3395,6 @@ insert_run (PangoLayoutLine *line,
   line->length += run_item->length;
 }
 
-static void
-advance_iterator_to (PangoAttrIterator *iter,
-                     int                new_index)
-{
-  int start, end;
-
-  do
-    {
-      pango_attr_iterator_range (iter, &start, &end);
-      if (end > new_index)
-        break;
-    }
-  while (pango_attr_iterator_next (iter));
-}
-
-static PangoLayoutRun *
-create_hyphen_run (PangoLayout *layout,
-                   PangoItem   *item)
-{
-  PangoLayoutRun *run;
-  GList *items;
-  const char *hyphen_text = "-";
-  int hyphen_len = 1;
-  PangoAttrList *attrs;
-  PangoAttrIterator *iter;
-  GSList *list, *l;
-  PangoAttrList *run_attrs;
-
-  run_attrs = pango_attr_list_new ();
-
-  attrs = pango_layout_get_effective_attributes (layout);
-  iter = pango_attr_list_get_iterator (attrs);
-
-  advance_iterator_to (iter, item->offset + item->length);
-  list = pango_attr_iterator_get_attrs (iter);
-  for (l = list; l; l = l->next)
-    {
-      PangoAttribute *attr = l->data;
-      attr->start_index = 0;
-      attr->end_index = G_MAXINT;
-      pango_attr_list_insert (attrs, attr);
-    }
-  g_slist_free (list);
-
-  items = pango_itemize (layout->context, hyphen_text, 0, hyphen_len, attrs, NULL);
-  g_assert (items->next == NULL);
-
-  run = g_slice_new (PangoGlyphItem);
-  run->glyphs = pango_glyph_string_new ();
-  run->item = items->data;
-
-  /* insert after item, use SHY as text */
-  run->item->offset = item->offset + item->length;
-  run->item->length = 2;
-  run->item->num_chars = 1;
-
-  g_list_free (items);
-
-  pango_shape (hyphen_text, hyphen_len, &run->item->analysis, run->glyphs);
-
-  pango_attr_iterator_destroy (iter);
-  pango_attr_list_unref (attrs);
-  pango_attr_list_unref (run_attrs);
-
-  return run;
-}
-
 static void
 get_need_hyphen (PangoItem  *item,
                  const char *text,
@@ -3491,23 +3424,37 @@ break_needs_hyphen (PangoLayout    *layout,
   return FALSE;
 }
 
+static int
+find_hyphen_width (PangoItem *item)
+{
+  hb_font_t *hb_font;
+  hb_codepoint_t glyph;
+
+  /* This is not technically correct, since we
+   * a) we may end up inserting a different hyphen
+   * b) we should reshape the entire run
+   * But it is close enough in practice
+   */
+  hb_font = pango_font_get_hb_font (item->analysis.font);
+  if (hb_font_get_nominal_glyph (hb_font, 0x2010, &glyph) ||
+      hb_font_get_nominal_glyph (hb_font, '-', &glyph))
+    return hb_font_get_glyph_h_advance (hb_font, glyph);
+
+  return 0;
+}
+
 static int
 find_break_extra_width (PangoLayout    *layout,
                        ParaBreakState *state,
                         int             pos)
 {
-  PangoItem *item = state->items->data;
-
   /* Check whether to insert a hyphen */
   if (break_needs_hyphen (layout, state, pos))
     {
       if (state->hyphen_width < 0)
         {
-          PangoLayoutRun *run;
-
-          run = create_hyphen_run (layout, item);
-          state->hyphen_width = pango_glyph_string_get_width (run->glyphs);
-          pango_glyph_item_free (run);
+          PangoItem *item = state->items->data;
+          state->hyphen_width = find_hyphen_width (item);
         }
 
       return state->hyphen_width;
@@ -3516,23 +3463,6 @@ find_break_extra_width (PangoLayout    *layout,
     return 0;
 }
 
-static void
-insert_hyphen_after (PangoLayoutLine *line,
-                     ParaBreakState  *state,
-                     PangoItem       *item)
-{
-  PangoLayout *layout = line->layout;
-  PangoLayoutRun *run;
-
-  /* Use the SHY as text for the hyphen run */
-  item->num_chars -= 1;
-  item->length -= 2;
-  run = create_hyphen_run (layout, item);
-  line->runs = g_slist_prepend (line->runs, run);
-
-  state->remaining_width -= pango_glyph_string_get_width (run->glyphs);
-}
-
 #if 0
 # define DEBUG debug
 void
@@ -3713,10 +3643,9 @@ process_item (PangoLayout     *layout,
 
          if (break_num_chars == item->num_chars)
            {
-              gboolean insert_hyphen = break_needs_hyphen (layout, state, break_num_chars);
+              if (break_needs_hyphen (layout, state, break_num_chars))
+                item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN;
              insert_run (line, state, item, TRUE);
-              if (insert_hyphen)
-                insert_hyphen_after (line, state, item);
 
              return BREAK_ALL_FIT;
            }
@@ -3727,26 +3656,24 @@ process_item (PangoLayout     *layout,
          else
            {
              PangoItem *new_item;
-              gboolean insert_hyphen = break_needs_hyphen (layout, state, break_num_chars);
 
              length = g_utf8_offset_to_pointer (layout->text + item->offset, break_num_chars) - 
(layout->text + item->offset);
 
              new_item = pango_item_split (item, length, break_num_chars);
 
+              if (break_needs_hyphen (layout, state, break_num_chars))
+                new_item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN;
              /* Add the width back, to the line, reshape, subtract the new width */
              state->remaining_width += break_width;
              insert_run (line, state, new_item, FALSE);
              break_width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs);
              state->remaining_width -= break_width;
 
+             state->log_widths_offset += break_num_chars;
+
              /* Shaped items should never be broken */
              g_assert (!shape_set);
 
-              if (insert_hyphen)
-                insert_hyphen_after (line, state, new_item);
-
-             state->log_widths_offset += break_num_chars;
-
              return BREAK_SOME_FIT;
            }
        }
diff --git a/pango/pangofc-shape.c b/pango/pangofc-shape.c
index 910ff4d7..12ce7ddb 100644
--- a/pango/pangofc-shape.c
+++ b/pango/pangofc-shape.c
@@ -158,6 +158,20 @@ pango_hb_shape (PangoFont           *font,
   hb_buffer_set_flags (hb_buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
 
   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_length - last_char_len);
+      else if (hb_font_get_nominal_glyph (hb_font, '-', &glyph))
+        hb_buffer_add (hb_buffer, '-', 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);


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