diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-08-27 18:00:50 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-08-27 18:00:50 +0000 |
commit | 4ad756442fecfecf52673a2f22779cdaa5d673b1 (patch) | |
tree | 6e758a314a97d1fef909657af3ef4eff522c236d | |
parent | 371171b65600729c3220826430ee1a0993541dbd (diff) | |
parent | 9979612c72ebee4674bfd99eaabb373034b5efe4 (diff) | |
download | pango-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.c | 43 | ||||
-rw-r--r-- | pango/pango-glyph.h | 13 | ||||
-rw-r--r-- | tests/test-shape.c | 44 | ||||
-rw-r--r-- | utils/viewer-pangocairo.c | 42 |
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); |