summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-11-29 00:09:50 -0500
committerMatthias Clasen <mclasen@redhat.com>2021-11-29 08:12:11 -0500
commitae8297b785eacc61890b6042c0f89af6f65b3bb3 (patch)
tree2ea240fdb43f818145781910cb1116e4a1a03d17
parenta6ed4ff80188bb0472891b08c421d3ca4c846315 (diff)
downloadpango-ae8297b785eacc61890b6042c0f89af6f65b3bb3.tar.gz
tabs: Add a decimal point
This is useful for PANGO_TAB_DECIMAL. Implement this in PangoLayout, in the serializer, and update tests.
-rw-r--r--pango/pango-layout-private.h1
-rw-r--r--pango/pango-layout.c48
-rw-r--r--pango/pango-tabs.c94
-rw-r--r--pango/pango-tabs.h7
-rw-r--r--pango/serializer.c10
-rw-r--r--tests/layouts/valid-12.layout15
-rw-r--r--tests/layouts/valid-13.layout15
-rw-r--r--tests/testserialize.c11
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 743f5d09..473d1785 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;
}
@@ -3808,7 +3833,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)
@@ -3922,6 +3947,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"