[pango/tab-align: 5/7] tabs: Add a decimal point




commit ce0df3f4334aec2b05fb0d441477d4a71f453364
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Nov 29 00:09:50 2021 -0500

    tabs: Add a decimal point
    
    This is useful for PANGO_TAB_DECIMAL.
    
    Implement this in PangoLayout, in the
    serializer, and update tests.

 pango/pango-layout-private.h  |  1 +
 pango/pango-layout.c          | 48 +++++++++++++++++-----
 pango/pango-tabs.c            | 94 +++++++++++++++++++++++++++++++++++++------
 pango/pango-tabs.h            |  7 ++++
 pango/serializer.c            | 10 ++++-
 tests/layouts/valid-12.layout | 15 ++++---
 tests/layouts/valid-13.layout | 15 ++++---
 tests/testserialize.c         | 11 +++--
 8 files changed, 165 insertions(+), 36 deletions(-)
---
diff --git a/pango/pango-layout-private.h b/pango/pango-layout-private.h
index b9f9b137..74c36126 100644
--- a/pango/pango-layout-private.h
+++ b/pango/pango-layout-private.h
@@ -74,6 +74,7 @@ struct _PangoLayout
   PangoRectangle logical_rect;
   PangoRectangle ink_rect;
   int tab_width;               /* Cached width of a tab. -1 == not yet calculated */
+  gunichar decimal;
 
   int copy_end;
 
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index dd3e6f53..b78b8ee8 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -82,6 +82,7 @@
 #include "pango-glyph-item.h"
 #include <string.h>
 #include <math.h>
+#include <locale.h>
 
 #include <hb-ot.h>
 
@@ -225,6 +226,7 @@ pango_layout_init (PangoLayout *layout)
   layout->line_count = 0;
 
   layout->tab_width = -1;
+  layout->decimal = 0;
   layout->unknown_glyphs_count = -1;
 
   layout->wrap = PANGO_WRAP_WORD;
@@ -3373,6 +3375,7 @@ get_tab_pos (PangoLayoutLine *line,
              int              index,
              int             *tab_pos,
              PangoTabAlign   *alignment,
+             gunichar        *decimal,
              gboolean        *is_default)
 {
   PangoLayout *layout = line->layout;
@@ -3407,6 +3410,8 @@ get_tab_pos (PangoLayoutLine *line,
 
       if (in_pixels)
         *tab_pos *= PANGO_SCALE;
+
+      *decimal = pango_tab_array_get_decimal_point (layout->tabs, index);
     }
   else if (n_tabs > 0)
     {
@@ -3416,6 +3421,7 @@ get_tab_pos (PangoLayoutLine *line,
       int tab_width;
 
       pango_tab_array_get_tab (layout->tabs, n_tabs - 1, alignment, &last_pos);
+      *decimal = pango_tab_array_get_decimal_point (layout->tabs, n_tabs - 1);
 
       if (n_tabs > 1)
         pango_tab_array_get_tab (layout->tabs, n_tabs - 2, NULL, &next_to_last_pos);
@@ -3439,6 +3445,8 @@ get_tab_pos (PangoLayoutLine *line,
     {
       /* No tab array set, so use default tab width */
       *tab_pos = layout->tab_width * index;
+      *alignment = PANGO_TAB_LEFT;
+      *decimal = 0;
     }
 
   *tab_pos -= offset;
@@ -3486,7 +3494,15 @@ static void break_state_set_last_tab (ParaBreakState   *state,
                                       PangoGlyphString *glyphs,
                                       int               width,
                                       int               tab_pos,
-                                      PangoTabAlign     tab_align);
+                                      PangoTabAlign     tab_align,
+                                      gunichar          tab_decimal);
+
+static void
+ensure_decimal (PangoLayout *layout)
+{
+  if (layout->decimal == 0)
+    layout->decimal = g_utf8_get_char (localeconv ()->decimal_point);
+}
 
 static void
 shape_tab (PangoLayoutLine  *line,
@@ -3498,6 +3514,7 @@ shape_tab (PangoLayoutLine  *line,
   int current_width;
   int tab_pos;
   PangoTabAlign tab_align;
+  gunichar tab_decimal;
 
   current_width = line_width (line);
 
@@ -3522,7 +3539,7 @@ shape_tab (PangoLayoutLine  *line,
     {
       gboolean is_default;
 
-      get_tab_pos (line, i, &tab_pos, &tab_align, &is_default);
+      get_tab_pos (line, i, &tab_pos, &tab_align, &tab_decimal, &is_default);
 
       /* Make sure there is at least a space-width of space between
        * tab-aligned text and the text before it. However, only do
@@ -3533,13 +3550,17 @@ shape_tab (PangoLayoutLine  *line,
       if (tab_pos >= current_width + (is_default ? space_width : 1))
         {
           glyphs->glyphs[0].geometry.width = tab_pos - current_width;
-          g_debug ("shape_tab: tab %d, align %d, width %d\n",
-                   i, tab_align, glyphs->glyphs[0].geometry.width);
           break;
         }
     }
 
-  break_state_set_last_tab (state, glyphs, current_width, tab_pos, tab_align);
+  if (tab_decimal == 0)
+    {
+      ensure_decimal (line->layout);
+      tab_decimal = line->layout->decimal;
+    }
+
+  break_state_set_last_tab (state, glyphs, current_width, tab_pos, tab_align, tab_decimal);
 }
 
 static inline gboolean
@@ -3628,6 +3649,7 @@ struct _ParaBreakState
   int last_tab_width;
   int last_tab_pos;
   PangoTabAlign last_tab_align;
+  gunichar last_tab_decimal;
 };
 
 static void
@@ -3635,13 +3657,15 @@ break_state_set_last_tab (ParaBreakState   *state,
                           PangoGlyphString *glyphs,
                           int               width,
                           int               tab_pos,
-                          PangoTabAlign     tab_align)
+                          PangoTabAlign     tab_align,
+                          gunichar          tab_decimal)
 {
 
   state->last_tab = glyphs;
   state->last_tab_width = width;
   state->last_tab_pos = tab_pos;
   state->last_tab_align = tab_align;
+  state->last_tab_decimal = tab_decimal;
 }
 
 static gboolean
@@ -3652,6 +3676,7 @@ static void
 get_decimal_prefix_width (PangoItem        *item,
                           PangoGlyphString *glyphs,
                           const char       *text,
+                          gunichar          decimal,
                           int              *width,
                           gboolean         *found)
 {
@@ -3669,7 +3694,7 @@ get_decimal_prefix_width (PangoItem        *item,
 
   for (i = 0, p = text + item->offset; i < item->num_chars; i++, p = g_utf8_next_char (p))
     {
-      if (g_utf8_get_char (p) == '.')
+      if (g_utf8_get_char (p) == decimal)
         {
           *width += log_widths[i] / 2;
           *found = TRUE;
@@ -3749,7 +3774,7 @@ shape_run (PangoLayoutLine *line,
               int width;
               gboolean found;
 
-              get_decimal_prefix_width (item, glyphs, layout->text, &width, &found);
+              get_decimal_prefix_width (item, glyphs, layout->text, state->last_tab_decimal, &width, &found);
 
               w -= width;
             }
@@ -3806,7 +3831,7 @@ insert_run (PangoLayoutLine  *line,
           int width;
           gboolean found;
 
-          get_decimal_prefix_width (run->item, run->glyphs, line->layout->text, &width, &found);
+          get_decimal_prefix_width (run->item, run->glyphs, line->layout->text, state->last_tab_decimal, 
&width, &found);
 
           state->last_tab_width += width;
           if (found)
@@ -3920,6 +3945,11 @@ compute_log_widths (PangoLayout    *layout,
   pango_glyph_item_get_logical_widths (&glyph_item, layout->text, state->log_widths);
 }
 
+/* If last_tab is set, we've added a tab and remaining_width has been updated to
+ * account for its origin width, which is last_tab_pos - last_tab_width. shape_run
+ * updates the tab width, so we need to consider the delta when comparing
+ * against remaining_width.
+ */
 static int
 tab_width_change (ParaBreakState *state)
 {
diff --git a/pango/pango-tabs.c b/pango/pango-tabs.c
index 47ac95c3..318f305b 100644
--- a/pango/pango-tabs.c
+++ b/pango/pango-tabs.c
@@ -28,12 +28,9 @@ typedef struct _PangoTab PangoTab;
 
 struct _PangoTab
 {
-  gint location;                /* Offset in pixels of this tab stop
-                                 * from the left margin of the text.
-                                 */
-  PangoTabAlign alignment;      /* Where the tab stop appears relative
-                                 * to the text.
-                                 */
+  int location;
+  PangoTabAlign alignment;
+  gunichar decimal_point;
 };
 
 /**
@@ -42,7 +39,8 @@ struct _PangoTab
  * A `PangoTabArray` contains an array of tab stops.
  *
  * `PangoTabArray` can be used to set tab stops in a `PangoLayout`.
- * Each tab stop has an alignment and a position.
+ * Each tab stop has an alignment, a position, and optionally
+ * a character to use as decimal point.
  */
 struct _PangoTabArray
 {
@@ -59,6 +57,7 @@ init_tabs (PangoTabArray *array, gint start, gint end)
     {
       array->tabs[start].location = 0;
       array->tabs[start].alignment = PANGO_TAB_LEFT;
+      array->tabs[start].decimal_point = 0;
       ++start;
     }
 }
@@ -141,6 +140,7 @@ pango_tab_array_new_with_positions (gint           size,
 
   array->tabs[0].alignment = first_alignment;
   array->tabs[0].location = first_position;
+  array->tabs[0].decimal_point = 0;
 
   if (size == 1)
     return array;
@@ -155,6 +155,7 @@ pango_tab_array_new_with_positions (gint           size,
 
       array->tabs[i].alignment = align;
       array->tabs[i].location = pos;
+      array->tabs[i].decimal_point = 0;
 
       ++i;
     }
@@ -266,9 +267,6 @@ pango_tab_array_resize (PangoTabArray *tab_array,
  * @location: tab location in Pango units
  *
  * Sets the alignment and location of a tab stop.
- *
- * @alignment must always be %PANGO_TAB_LEFT in the current
- * implementation.
  */
 void
 pango_tab_array_set_tab (PangoTabArray *tab_array,
@@ -409,6 +407,9 @@ pango_tab_array_to_string (PangoTabArray *tab_array)
       g_string_append_printf (s, "%d", tab_array->tabs[i].location);
       if (tab_array->positions_in_pixels)
         g_string_append (s, "px");
+
+      if (tab_array->tabs[i].decimal_point != 0)
+        g_string_append_printf (s, ":%d", tab_array->tabs[i].decimal_point);
     }
 
   return g_string_free (s, FALSE);
@@ -483,10 +484,9 @@ pango_tab_array_from_string (const char *text)
       pos = g_ascii_strtoll (p, &endp, 10);
       if (pos < 0 ||
           (pixels && *endp != 'p') ||
-          (!pixels && !g_ascii_isspace (*endp) && *endp != '\0')) goto fail;
+          (!pixels && !g_ascii_isspace (*endp) && *endp != ':' && *endp != '\0')) goto fail;
 
       pango_tab_array_set_tab (array, i, align, pos);
-      i++;
 
       p = (const char *)endp;
       if (pixels)
@@ -494,7 +494,23 @@ pango_tab_array_from_string (const char *text)
           if (p[0] != 'p' || p[1] != 'x') goto fail;
           p += 2;
         }
+
+      if (p[0] == ':')
+        {
+          gunichar ch;
+
+          p++;
+          ch = g_ascii_strtoll (p, &endp, 10);
+          if (!g_ascii_isspace (*endp) && *endp != '\0') goto fail;
+
+          pango_tab_array_set_decimal_point (array, i, ch);
+
+          p = (const char *)endp;
+        }
+
       p = skip_whitespace (p);
+
+      i++;
     }
 
   goto success;
@@ -506,3 +522,57 @@ fail:
 success:
   return array;
 }
+
+/**
+ * pango_tab_array_set_decimal_point:
+ * @tab_array: a `PangoTabArray`
+ * @tab_index: the index of a tab stop
+ * @decimal_point: the decimal point to use
+ *
+ * Sets the decimal point to use.
+ *
+ * This is only relevant for %PANGO_TAB_DECIMAL.
+ *
+ * By default, Pango uses the decimal point according
+ * to the current locale.
+ *
+ * Since: 1.50
+ */
+void
+pango_tab_array_set_decimal_point (PangoTabArray *tab_array,
+                                   int            tab_index,
+                                   gunichar       decimal_point)
+{
+  g_return_if_fail (tab_array != NULL);
+  g_return_if_fail (tab_index >= 0);
+
+  if (tab_index >= tab_array->size)
+    pango_tab_array_resize (tab_array, tab_index + 1);
+
+  tab_array->tabs[tab_index].decimal_point = decimal_point;
+}
+
+/**
+ * pango_tab_array_get_decimal_point:
+ * @tab_array: a `PangoTabArray`
+ * @tab_index: the index of a tab stop
+ *
+ * Gets the decimal point to use.
+ *
+ * This is only relevant for %PANGO_TAB_DECIMAL.
+ *
+ * The default value of 0 means that Pango will use the
+ * decimal point according to the current locale.
+ *
+ * Since: 1.50
+ */
+gunichar
+pango_tab_array_get_decimal_point (PangoTabArray *tab_array,
+                                   int            tab_index)
+{
+  g_return_val_if_fail (tab_array != NULL, 0);
+  g_return_val_if_fail (tab_index < tab_array->size, 0);
+  g_return_val_if_fail (tab_index >= 0, 0);
+
+  return tab_array->tabs[tab_index].decimal_point;
+}
diff --git a/pango/pango-tabs.h b/pango/pango-tabs.h
index 81ac1550..0792a36a 100644
--- a/pango/pango-tabs.h
+++ b/pango/pango-tabs.h
@@ -98,6 +98,13 @@ char *          pango_tab_array_to_string           (PangoTabArray *tab_array);
 PANGO_AVAILABLE_IN_1_50
 PangoTabArray * pango_tab_array_from_string         (const char    *text);
 
+PANGO_AVAILABLE_IN_1_50
+void            pango_tab_array_set_decimal_point   (PangoTabArray *tab_array,
+                                                     int            tab_index,
+                                                     gunichar       decimal_point);
+PANGO_AVAILABLE_IN_1_50
+gunichar        pango_tab_array_get_decimal_point   (PangoTabArray *tab_array,
+                                                     int            tab_index);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoTabArray, pango_tab_array_free)
 
diff --git a/pango/serializer.c b/pango/serializer.c
index 372fbd8b..fe0fc25c 100644
--- a/pango/serializer.c
+++ b/pango/serializer.c
@@ -226,6 +226,8 @@ add_tab_array (JsonBuilder   *builder,
       json_builder_add_int_value (builder, pos);
       json_builder_set_member_name (builder, "alignment");
       add_enum_value (builder, PANGO_TYPE_TAB_ALIGN, align, FALSE);
+      json_builder_set_member_name (builder, "decimal-point");
+      json_builder_add_int_value (builder, pango_tab_array_get_decimal_point (tabs, i));
       json_builder_end_object (builder);
     }
   json_builder_end_array (builder);
@@ -1139,7 +1141,8 @@ json_to_tab_array (JsonReader  *reader,
       for (int i = 0; i < json_reader_count_elements (reader); i++)
         {
           int pos;
-          PangoTabAlign align;
+          PangoTabAlign align = PANGO_TAB_LEFT;
+          gunichar ch = 0;
 
           json_reader_read_element (reader, i);
           if (json_reader_is_object (reader))
@@ -1156,14 +1159,17 @@ json_to_tab_array (JsonReader  *reader,
               if (align == -1)
                 goto fail;
               json_reader_end_member (reader);
+              json_reader_read_member (reader, "decimal-point");
+              ch = json_reader_get_int_value (reader);
+              json_reader_end_member (reader);
             }
           else
             {
               pos = json_reader_get_int_value (reader);
-              align = PANGO_TAB_LEFT;
             }
 
           pango_tab_array_set_tab (tabs, i, align, pos);
+          pango_tab_array_set_decimal_point (tabs, i, ch);
           json_reader_end_element (reader);
         }
     }
diff --git a/tests/layouts/valid-12.layout b/tests/layouts/valid-12.layout
index bbe9a576..247b374e 100644
--- a/tests/layouts/valid-12.layout
+++ b/tests/layouts/valid-12.layout
@@ -23,23 +23,28 @@
     "positions" : [
       {
         "position" : 0,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 50,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 100,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 150,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 200,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       }
     ]
   },
diff --git a/tests/layouts/valid-13.layout b/tests/layouts/valid-13.layout
index bc20a3c1..b557a278 100644
--- a/tests/layouts/valid-13.layout
+++ b/tests/layouts/valid-13.layout
@@ -23,23 +23,28 @@
     "positions" : [
       {
         "position" : 0,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 50,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 100,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 150,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       },
       {
         "position" : 200,
-        "alignment" : "left"
+        "alignment" : "left",
+        "decimal-point" : 0
       }
     ]
   },
diff --git a/tests/testserialize.c b/tests/testserialize.c
index 325338f1..78424eff 100644
--- a/tests/testserialize.c
+++ b/tests/testserialize.c
@@ -87,6 +87,7 @@ test_serialize_tab_array (void)
     "  0    10   ",
     "20 10",
     "left:10px right:20px center:30px decimal:40px",
+    "decimal:10240:94",
     ""
   };
   const char *roundtripped[] = {
@@ -95,6 +96,7 @@ test_serialize_tab_array (void)
     "0 10",
     "20 10",
     "10px right:20px center:30px decimal:40px",
+    "decimal:10240:94",
     ""
   };
   const char *invalid[] = {
@@ -235,15 +237,18 @@ test_serialize_layout_valid (void)
     "    \"positions\" : [\n"
     "      {\n"
     "        \"position\" : 0,\n"
-    "        \"alignment\" : \"left\"\n"
+    "        \"alignment\" : \"left\",\n"
+    "        \"decimal-point\" : 0\n"
     "      },\n"
     "      {\n"
     "        \"position\" : 50,\n"
-    "        \"alignment\" : \"center\"\n"
+    "        \"alignment\" : \"center\",\n"
+    "        \"decimal-point\" : 0\n"
     "      },\n"
     "      {\n"
     "        \"position\" : 100,\n"
-    "        \"alignment\" : \"right\"\n"
+    "        \"alignment\" : \"decimal\",\n"
+    "        \"decimal-point\" : 94\n"
     "      }\n"
     "    ]\n"
     "  },\n"


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