[pango/baseline-shift: 5/5] Add horizontal displacement




commit 4b3c63e9716ee4e54f9da67dbdaeccbb7a9a97c5
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Aug 29 17:26:52 2021 -0400

    Add horizontal displacement
    
    Apply horizontal displacements for superscripts and subscripts
    that are provided in font metrics. This noticably improves the
    placement of superscripts in italics.
    
    Currently, we only apply these displacements in post-processing,
    and ignore the width changes during line-breaking. This could
    be improved by moving the baseline handling into the line-breaking
    proper.

 pango/pango-glyph-item.c     |  4 ++
 pango/pango-glyph-item.h     | 10 ++++-
 pango/pango-layout-private.h |  5 ++-
 pango/pango-layout.c         | 94 ++++++++++++++++++++++++++++----------------
 pango/pango-renderer.c       |  4 +-
 5 files changed, 78 insertions(+), 39 deletions(-)
---
diff --git a/pango/pango-glyph-item.c b/pango/pango-glyph-item.c
index c64bfa13..7eb1737d 100644
--- a/pango/pango-glyph-item.c
+++ b/pango/pango-glyph-item.c
@@ -130,6 +130,8 @@ pango_glyph_item_split (PangoGlyphItem *orig,
   pango_glyph_string_set_size (orig->glyphs, orig->glyphs->num_glyphs - num_glyphs);
 
   new->y_offset = orig->y_offset;
+  new->start_x_offset = orig->start_x_offset;
+  new->end_x_offset = -orig->start_x_offset;
 
   return new;
 }
@@ -157,6 +159,8 @@ pango_glyph_item_copy  (PangoGlyphItem *orig)
   result->item = pango_item_copy (orig->item);
   result->glyphs = pango_glyph_string_copy (orig->glyphs);
   result->y_offset = orig->y_offset;
+  result->start_x_offset = orig->start_x_offset;
+  result->end_x_offset = orig->end_x_offset;
 
   return result;
 }
diff --git a/pango/pango-glyph-item.h b/pango/pango-glyph-item.h
index baea69fc..fd8951d2 100644
--- a/pango/pango-glyph-item.h
+++ b/pango/pango-glyph-item.h
@@ -33,8 +33,12 @@ G_BEGIN_DECLS
  * PangoGlyphItem:
  * @item: corresponding `PangoItem`
  * @glyphs: corresponding `PangoGlyphString`
- * @baseline: shift of the baseline, relative to the
- *   containing lines baseline. Positive values shift upwards
+ * @y_offset: shift of the baseline, relative to the baseline
+ *   of the containing line. Positive values shift upwards
+ * @start_x_offset: horizontal displacement to apply before the
+ *   glyph item. Positive values shift right
+ * @end_x_offset: horizontal displacement to apply after th
+ *   glyph item. Positive values shift right
  *
  * A `PangoGlyphItem` is a pair of a `PangoItem` and the glyphs
  * resulting from shaping the items text.
@@ -50,6 +54,8 @@ struct _PangoGlyphItem
   PangoItem *item;
   PangoGlyphString *glyphs;
   int y_offset;
+  int start_x_offset;
+  int end_x_offset;
 };
 
 #define PANGO_TYPE_GLYPH_ITEM (pango_glyph_item_get_type ())
diff --git a/pango/pango-layout-private.h b/pango/pango-layout-private.h
index 1805e730..b9f9b137 100644
--- a/pango/pango-layout-private.h
+++ b/pango/pango-layout-private.h
@@ -112,11 +112,12 @@ struct _PangoLayoutIter
   Extents *line_extents;
   int line_index;
 
-  /* X position of the current run */
+  /* Position of the current run */
   int run_x;
 
-  /* Width of the current run */
+  /* Width and end offset of the current run */
   int run_width;
+  int end_x_offset;
 
   /* this run is left-to-right */
   gboolean ltr;
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 6c1e2e5e..098e3a3e 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -6154,18 +6154,23 @@ justify_words (PangoLayoutLine *line,
 
 typedef struct {
   PangoAttribute *attr;
-  int shift;
+  int x_offset;
+  int y_offset;
 } BaselineItem;
 
 static void
-collect_shifts (ParaBreakState *state,
-                PangoItem      *item,
-                PangoItem      *prev,
-                int            *start_shift,
-                int            *end_shift)
-{
-  *start_shift = 0;
-  *end_shift = 0;
+collect_baseline_shift (ParaBreakState *state,
+                        PangoItem      *item,
+                        PangoItem      *prev,
+                        int            *start_x_offset,
+                        int            *start_y_offset,
+                        int            *end_x_offset,
+                        int            *end_y_offset)
+{
+  *start_x_offset = 0;
+  *start_y_offset = 0;
+  *end_x_offset = 0;
+  *end_y_offset = 0;
 
   for (GSList *l = item->analysis.extra_attrs; l; l = l->next)
     {
@@ -6175,8 +6180,8 @@ collect_shifts (ParaBreakState *state,
         {
           int value = ((PangoAttrInt *)attr)->value;
 
-          *start_shift += value;
-          *end_shift -= value;
+          *start_y_offset += value;
+          *end_y_offset -= value;
         }
       else if (attr->klass->type == PANGO_ATTR_BASELINE_SHIFT)
         {
@@ -6187,51 +6192,60 @@ collect_shifts (ParaBreakState *state,
 
               entry = g_new0 (BaselineItem, 1);
               entry->attr = attr;
+              state->baseline_shifts = g_list_prepend (state->baseline_shifts, entry);
 
               value = ((PangoAttrInt *)attr)->value;
 
               if (value > 1024 || value < -1024)
                 {
-                  entry->shift = value;
+                  entry->y_offset = value;
+                  /* FIXME: compute an x_offset from value to italic angle */
                 }
               else
                 {
-                  int superscript_shift = 0;
-                  int subscript_shift = 0;
-                  hb_font_t *hb_font;
+                  int superscript_x_offset = 0;
+                  int superscript_y_offset = 0;
+                  int subscript_x_offset = 0;
+                  int subscript_y_offset = 0;
 
 
                   if (prev)
                     {
-                      hb_font = pango_font_get_hb_font (prev->analysis.font);
-                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET, 
&superscript_shift);
-                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET, 
&subscript_shift);
+                      hb_font_t *hb_font = pango_font_get_hb_font (prev->analysis.font);
+                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET, 
&superscript_y_offset);
+                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET, 
&superscript_x_offset);
+                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET, 
&subscript_y_offset);
+                      hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET, 
&subscript_x_offset);
                     }
 
-                  if (superscript_shift == 0)
-                    superscript_shift = 5000;
-                  if (subscript_shift == 0)
-                    subscript_shift = 5000;
+                  if (superscript_y_offset == 0)
+                    superscript_y_offset = 5000;
+                  if (subscript_y_offset == 0)
+                    subscript_y_offset = 5000;
 
                   switch (value)
                     {
                     case PANGO_BASELINE_SHIFT_NONE:
-                      entry->shift = 0;
+                      entry->x_offset = 0;
+                      entry->y_offset = 0;
                       break;
                     case PANGO_BASELINE_SHIFT_SUPERSCRIPT:
-                      entry->shift = superscript_shift;
+                      entry->x_offset = superscript_x_offset;
+                      entry->y_offset = superscript_y_offset;
                       break;
                     case PANGO_BASELINE_SHIFT_SUBSCRIPT:
-                      entry->shift = -subscript_shift;
+                      entry->x_offset = subscript_x_offset;
+                      entry->y_offset = -subscript_y_offset;
                       break;
                     default:
                       g_assert_not_reached ();
                     }
                 }
 
-               *start_shift += entry->shift;
-               state->baseline_shifts = g_list_prepend (state->baseline_shifts, entry);
+              *start_x_offset += entry->x_offset;
+              *start_y_offset += entry->y_offset;
             }
+
           if (attr->end_index == item->offset + item->length)
             {
               BaselineItem *entry = state->baseline_shifts->data;
@@ -6239,7 +6253,10 @@ collect_shifts (ParaBreakState *state,
               if (attr->start_index == entry->attr->start_index &&
                   attr->end_index == entry->attr->end_index &&
                   ((PangoAttrInt *)attr)->value == ((PangoAttrInt *)entry->attr)->value)
-                *end_shift -= entry->shift;
+                {
+                  *end_x_offset -= entry->x_offset;
+                  *end_y_offset -= entry->y_offset;
+                }
               else
                 g_warning ("Baseline attributes mismatch\n");
 
@@ -6251,7 +6268,7 @@ collect_shifts (ParaBreakState *state,
 }
 
 static void
-apply_baseline_shifts (PangoLayoutLine *line,
+apply_baseline_shift (PangoLayoutLine *line,
                        ParaBreakState  *state)
 {
   int y_offset = 0;
@@ -6261,13 +6278,16 @@ apply_baseline_shifts (PangoLayoutLine *line,
     {
       PangoLayoutRun *run = l->data;
       PangoItem *item = run->item;
+      int start_x_offset, end_x_offset;
       int start_y_offset, end_y_offset;
 
-      collect_shifts (state, item, prev, &start_y_offset, &end_y_offset);
+      collect_baseline_shift (state, item, prev, &start_x_offset, &start_y_offset, &end_x_offset, 
&end_y_offset);
 
       y_offset += start_y_offset;
 
       run->y_offset = y_offset;
+      run->start_x_offset = start_x_offset;
+      run->end_x_offset = end_x_offset;
 
       y_offset += end_y_offset;
 
@@ -6295,7 +6315,7 @@ pango_layout_line_postprocess (PangoLayoutLine *line,
    */
   line->runs = g_slist_reverse (line->runs);
 
-  apply_baseline_shifts (line, state);
+  apply_baseline_shift (line, state);
 
   /* Ellipsize the line if necessary
    */
@@ -6543,16 +6563,22 @@ update_run (PangoLayoutIter *iter,
   if (iter->run_list_link == iter->line->runs)
     iter->run_x = line_ext->logical_rect.x;
   else
-    iter->run_x += iter->run_width;
+    {
+      iter->run_x += iter->end_x_offset + iter->run_width;
+      if (iter->run)
+        iter->run_x += iter->run->start_x_offset;
+    }
 
   if (iter->run)
     {
       iter->run_width = pango_glyph_string_get_width (iter->run->glyphs);
+      iter->end_x_offset = iter->run->end_x_offset;
     }
   else
     {
       /* The empty run at the end of a line */
       iter->run_width = 0;
+      iter->end_x_offset = 0;
     }
 
   if (iter->run)
@@ -7256,7 +7282,7 @@ pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter,
 
   if (ink_rect)
     {
-      ink_rect->x += iter->cluster_x;
+      ink_rect->x += iter->cluster_x + iter->run->start_x_offset;
       ink_rect->y -= iter->run->y_offset;
       offset_y (iter, &ink_rect->y);
     }
@@ -7264,7 +7290,7 @@ pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter,
   if (logical_rect)
     {
       g_assert (logical_rect->width == iter->cluster_width);
-      logical_rect->x += iter->cluster_x;
+      logical_rect->x += iter->cluster_x + iter->run->start_x_offset;
       logical_rect->y -= iter->run->y_offset;
       offset_y (iter, &logical_rect->y);
     }
diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c
index 231ebe7d..d47ba13a 100644
--- a/pango/pango-renderer.c
+++ b/pango/pango-renderer.c
@@ -580,7 +580,6 @@ pango_renderer_draw_layout_line (PangoRenderer   *renderer,
   gboolean got_overall = FALSE;
   PangoRectangle overall_rect;
   const char *text;
-  int y_off;
 
   g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
 
@@ -612,6 +611,7 @@ pango_renderer_draw_layout_line (PangoRenderer   *renderer,
       PangoAttrShape *shape_attr;
       PangoRectangle ink_rect, *ink = NULL;
       PangoRectangle logical_rect, *logical = NULL;
+      int y_off;
 
       if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
         logical = &logical_rect;
@@ -651,6 +651,7 @@ pango_renderer_draw_layout_line (PangoRenderer   *renderer,
 
       state.logical_rect_end = x + x_off + glyph_string_width;
 
+      x_off += run->start_x_offset;
       y_off = run->y_offset;
 
       if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
@@ -730,6 +731,7 @@ pango_renderer_draw_layout_line (PangoRenderer   *renderer,
         draw_strikethrough (renderer, &state);
 
       x_off += glyph_string_width;
+      x_off += run->end_x_offset;
     }
 
   /* Finish off any remaining underlines


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