summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-08-27 18:00:50 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-08-27 18:00:50 +0000
commit4ad756442fecfecf52673a2f22779cdaa5d673b1 (patch)
tree6e758a314a97d1fef909657af3ef4eff522c236d
parent371171b65600729c3220826430ee1a0993541dbd (diff)
parent9979612c72ebee4674bfd99eaabb373034b5efe4 (diff)
downloadpango-4ad756442fecfecf52673a2f22779cdaa5d673b1.tar.gz
Merge branch 'ligature-caret-rtl-fixes' into 'main'
Some fixes for ligature caret positioning in rtl See merge request GNOME/pango!445
-rw-r--r--pango/glyphstring.c43
-rw-r--r--pango/pango-glyph.h13
-rw-r--r--tests/test-shape.c44
-rw-r--r--utils/viewer-pangocairo.c42
4 files changed, 114 insertions, 28 deletions
diff --git a/pango/glyphstring.c b/pango/glyphstring.c
index 8d4aa604..30d68220 100644
--- a/pango/glyphstring.c
+++ b/pango/glyphstring.c
@@ -520,25 +520,60 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs,
* with an m-n situation, where LigatureCaretList is
* not going to help. Just give up and do the simple thing.
*/
- if (cluster_offset > 0 && cluster_offset < cluster_chars &&
- start_glyph_pos == end_glyph_pos)
+ if (cluster_offset > 0 && cluster_offset < cluster_chars)
{
hb_font_t *hb_font;
hb_position_t caret;
unsigned int caret_count = 1;
+ int glyph_pos;
hb_font = pango_font_get_hb_font (analysis->font);
+
+ if (start_glyph_pos == end_glyph_pos)
+ glyph_pos = start_glyph_pos;
+ else
+ {
+ hb_face_t *hb_face;
+
+ hb_face = hb_font_get_face (hb_font);
+
+ glyph_pos = -1;
+ for (i = start_glyph_pos; i <= end_glyph_pos; i++)
+ {
+ if (hb_ot_layout_get_glyph_class (hb_face, glyphs->glyphs[i].glyph) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+ {
+ if (glyph_pos != -1)
+ {
+ /* multiple non-mark glyphs in cluster, giving up */
+ goto fallback;
+ }
+ glyph_pos = i;
+ }
+ }
+ if (glyph_pos == -1)
+ {
+ /* no non-mark glyph in a multi-glyph cluster, giving up */
+ goto fallback;
+ }
+ }
+
hb_ot_layout_get_ligature_carets (hb_font,
(analysis->level % 2) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR,
- glyphs->glyphs[start_glyph_pos].glyph,
+ glyphs->glyphs[glyph_pos].glyph,
cluster_offset - 1, &caret_count, &caret);
if (caret_count > 0)
{
- *x_pos = start_xpos + caret;
+ if (analysis->level % 2) /* Right to left */
+ *x_pos = end_xpos + caret;
+ else
+ *x_pos = start_xpos + caret;
+ *x_pos += glyphs->glyphs[glyph_pos].geometry.x_offset;
return;
}
}
+fallback:
+
*x_pos = ((cluster_chars - cluster_offset) * start_xpos +
cluster_offset * end_xpos) / cluster_chars;
}
diff --git a/pango/pango-glyph.h b/pango/pango-glyph.h
index 4dc77fd1..2094fa53 100644
--- a/pango/pango-glyph.h
+++ b/pango/pango-glyph.h
@@ -58,6 +58,19 @@ typedef gint32 PangoGlyphUnit;
*
* The `PangoGlyphGeometry` structure contains width and positioning
* information for a single glyph.
+ *
+ * Note that @width is not guaranteed to be the same as the glyph
+ * extents. Kerning and other positioning applied during shaping will
+ * affect both the @width and the @x_offset for the glyphs in the
+ * glyph string that results from shaping.
+ *
+ * The information in this struct is intended for rendering the glyphs,
+ * as follows:
+ *
+ * 1. Render the current glyph at (x + x_offset, y + y_offset),
+ * where (x, y) is the current point
+ * 2. Advance the current point to (x + xoffset, y)
+ * 3. Render the next glyph...
*/
struct _PangoGlyphGeometry
{
diff --git a/tests/test-shape.c b/tests/test-shape.c
index 2b78e96a..674c6cc9 100644
--- a/tests/test-shape.c
+++ b/tests/test-shape.c
@@ -34,6 +34,8 @@
static PangoContext *context;
+gboolean opt_hex_chars;
+
static void
append_text (GString *s,
const char *text,
@@ -46,7 +48,9 @@ append_text (GString *s,
gunichar ch = g_utf8_get_char (p);
if (ch == ' ')
g_string_append (s, "[ ]");
- if (ch == 0x0A || ch == 0x2028 || !g_unichar_isprint (ch))
+ else if (opt_hex_chars)
+ g_string_append_printf (s, "[%#04x]", ch);
+ else if (ch == 0x0A || ch == 0x2028 || !g_unichar_isprint (ch))
g_string_append_printf (s, "[%#04x]", ch);
else
g_string_append_unichar (s, ch);
@@ -214,6 +218,18 @@ test_file (const gchar *filename, GString *string)
int len;
PangoGlyphInfo *gi = &glyphs->glyphs[i];
+
+ if (gi->attr.is_cluster_start && i > 0)
+ {
+ g_string_append (s1, " ");
+ g_string_append (s2, "|");
+ g_string_append (s3, "|");
+ g_string_append (s4, "|");
+ g_string_append (s5, " ");
+ g_string_append (s6, " ");
+ g_string_append (s7, "|");
+ }
+
char *p;
p = text + item->offset + glyphs->log_clusters[i];
if (rtl)
@@ -254,17 +270,6 @@ test_file (const gchar *filename, GString *string)
g_string_append_printf (s5, "%*s", len - (int)g_utf8_strlen (s5->str, s5->len), "");
g_string_append_printf (s6, "%*s", len - (int)g_utf8_strlen (s6->str, s6->len), "");
g_string_append_printf (s7, "%*s", len - (int)g_utf8_strlen (s7->str, s7->len), "");
-
- if (gi->attr.is_cluster_start && i + 1 < glyphs->num_glyphs)
- {
- g_string_append (s1, " ");
- g_string_append (s2, "|");
- g_string_append (s3, "|");
- g_string_append (s4, "|");
- g_string_append (s5, " ");
- g_string_append (s6, " ");
- g_string_append (s7, "|");
- }
}
pango_glyph_string_free (glyphs);
@@ -347,6 +352,21 @@ main (int argc, char *argv[])
GError *error = NULL;
const gchar *name;
gchar *path;
+ GOptionContext *option_context;
+ GOptionEntry entries[] = {
+ { "hex-chars", '0', 0, G_OPTION_ARG_NONE, &opt_hex_chars, "Print all chars in hex", NULL },
+ { NULL, 0 },
+ };
+
+ option_context = g_option_context_new ("");
+ g_option_context_add_main_entries (option_context, entries, NULL);
+ g_option_context_set_ignore_unknown_options (option_context, TRUE);
+ if (!g_option_context_parse (option_context, &argc, &argv, &error))
+ {
+ g_error ("failed to parse options: %s", error->message);
+ return 1;
+ }
+ g_option_context_free (option_context);
setlocale (LC_ALL, "");
diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c
index af4925e3..4b27c7e5 100644
--- a/utils/viewer-pangocairo.c
+++ b/utils/viewer-pangocairo.c
@@ -409,10 +409,16 @@ render_callback (PangoLayout *layout,
if (annotate & ANNOTATE_CARET_POSITIONS)
{
+ const PangoLogAttr *attrs;
+ int n_attrs;
+ int offset;
+
/* draw the caret positions in purple */
cairo_save (cr);
cairo_set_source_rgba (cr, 1.0, 0.0, 1.0, 0.5);
+ attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs);
+
iter = pango_layout_get_iter (layout);
do
{
@@ -431,24 +437,36 @@ render_callback (PangoLayout *layout,
text = pango_layout_get_text (layout);
start = text + run->item->offset;
+ offset = g_utf8_strlen (text, start - text);
+
y = pango_layout_iter_get_baseline (iter);
trailing = FALSE;
p = start;
for (int i = 0; i <= run->item->num_chars; i++)
{
- pango_glyph_string_index_to_x (run->glyphs,
- text + run->item->offset,
- run->item->length,
- &run->item->analysis,
- p - start,
- trailing,
- &x);
- x += rect.x;
-
- cairo_arc (cr, x / PANGO_SCALE, y / PANGO_SCALE, 3.0, 0, 2*G_PI);
- cairo_close_path (cr);
- cairo_fill (cr);
+ if (attrs[offset + i].is_cursor_position)
+ {
+ pango_glyph_string_index_to_x (run->glyphs,
+ text + run->item->offset,
+ run->item->length,
+ &run->item->analysis,
+ p - start,
+ trailing,
+ &x);
+ x += rect.x;
+
+ cairo_set_source_rgba (cr, 1.0, 0.0, 1.0, 0.5);
+ cairo_arc (cr, x / PANGO_SCALE, y / PANGO_SCALE, 3.0, 0, 2*G_PI);
+ cairo_close_path (cr);
+ cairo_fill (cr);
+
+ char *s = g_strdup_printf ("%d", i + trailing);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_move_to (cr, x / PANGO_SCALE - 5, y / PANGO_SCALE + 15);
+ cairo_show_text (cr, s);
+ g_free (s);
+ }
if (i < run->item->num_chars)
p = g_utf8_next_char (p);