diff options
Diffstat (limited to 'pango')
-rw-r--r-- | pango/glyphstring.c | 90 | ||||
-rw-r--r-- | pango/pango-glyph.h | 11 | ||||
-rw-r--r-- | pango/pango-layout.c | 53 |
3 files changed, 113 insertions, 41 deletions
diff --git a/pango/glyphstring.c b/pango/glyphstring.c index 30d68220..ea9a6398 100644 --- a/pango/glyphstring.c +++ b/pango/glyphstring.c @@ -378,7 +378,6 @@ pango_glyph_string_get_logical_widths (PangoGlyphString *glyphs, * <source srcset="glyphstring-positions-dark.png" media="(prefers-color-scheme: dark)"> * <img alt="Glyph positions" src="glyphstring-positions-light.png"> * </picture> - */ void pango_glyph_string_index_to_x (PangoGlyphString *glyphs, @@ -389,6 +388,45 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, gboolean trailing, int *x_pos) { + pango_glyph_string_index_to_x_full (glyphs, + text, length, + analysis, + NULL, + index, trailing, + x_pos); +} + +/** + * pango_glyph_string_index_to_x_full: + * @glyphs: the glyphs return from [func@shape] + * @text: the text for the run + * @length: the number of bytes (not characters) in @text. + * @analysis: the analysis information return from [func@itemize] + * @attrs: (nullable): `PangoLogAttr` array for @text + * @index_: the byte index within @text + * @trailing: whether we should compute the result for the beginning (%FALSE) + * or end (%TRUE) of the character. + * @x_pos: (out): location to store result + * + * Converts from character position to x position. + * + * This variant of [method@Pango.GlyphString.index_to_x] additionally + * accepts a `PangoLogAttr` array. The grapheme boundary information + * in it can be used to disambiguate positioning inside some complex + * clusters. + * + * Since: 1.50 + */ +void +pango_glyph_string_index_to_x_full (PangoGlyphString *glyphs, + const char *text, + int length, + PangoAnalysis *analysis, + PangoLogAttr *attrs, + int index, + gboolean trailing, + int *x_pos) +{ int i; int start_xpos = 0; int end_xpos = 0; @@ -493,12 +531,17 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, end_xpos = (analysis->level % 2) ? 0 : width; } - /* Calculate offset of character within cluster */ - - for (p = text + start_index; + /* Calculate offset of character within cluster. + * To come up with accurate answers here, we need to know grapheme + * boundaries. + */ + for (p = text + start_index, i = attrs ? g_utf8_pointer_to_offset (text, text + start_index) : 0; p < text + end_index; - p = g_utf8_next_char (p)) + p = g_utf8_next_char (p), i++) { + if (attrs && !attrs[i].is_cursor_position) + continue; + if (p < text + index) cluster_offset++; cluster_chars++; @@ -508,17 +551,14 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, cluster_offset += 1; if (G_UNLIKELY (!cluster_chars)) /* pedantic */ - { + { *x_pos = start_xpos; return; } - /* Try to get a ligature caret position for the glyph - * from the font. - * - * If start_glyph_pos != end_glyph_pos, we are dealing - * with an m-n situation, where LigatureCaretList is - * not going to help. Just give up and do the simple thing. + /* Try to get a ligature caret position for the glyph from the font. + * This only makes sense if the cluster contains a single spacing + * glyph, so we need to check that all but one of them are marks. */ if (cluster_offset > 0 && cluster_offset < cluster_chars) { @@ -526,6 +566,7 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, hb_position_t caret; unsigned int caret_count = 1; int glyph_pos; + int num_carets; hb_font = pango_font_get_hb_font (analysis->font); @@ -557,19 +598,22 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, } } - hb_ot_layout_get_ligature_carets (hb_font, - (analysis->level % 2) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, - glyphs->glyphs[glyph_pos].glyph, - cluster_offset - 1, &caret_count, &caret); - if (caret_count > 0) + num_carets = hb_ot_layout_get_ligature_carets (hb_font, + (analysis->level % 2) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, + glyphs->glyphs[glyph_pos].glyph, + cluster_offset - 1, &caret_count, &caret); + if (caret_count == 0 || num_carets == 0) { - 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; + /* no ligature caret information found for this glyph */ + goto fallback; } + + 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: diff --git a/pango/pango-glyph.h b/pango/pango-glyph.h index 2094fa53..cd29b77a 100644 --- a/pango/pango-glyph.h +++ b/pango/pango-glyph.h @@ -24,6 +24,7 @@ #include <pango/pango-types.h> #include <pango/pango-item.h> +#include <pango/pango-break.h> G_BEGIN_DECLS @@ -198,6 +199,16 @@ void pango_glyph_string_x_to_index (PangoGlyphStrin int *index_, int *trailing); +PANGO_AVAILABLE_IN_1_50 +void pango_glyph_string_index_to_x_full (PangoGlyphString *glyphs, + const char *text, + int length, + PangoAnalysis *analysis, + PangoLogAttr *attrs, + int index_, + gboolean trailing, + int *x_pos); + /* Shaping */ /** diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 86c67020..d3d93e60 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -1788,6 +1788,8 @@ pango_layout_line_index_to_x (PangoLayoutLine *line, if (run->item->offset <= index && run->item->offset + run->item->length > index) { int offset = g_utf8_pointer_to_offset (layout->text, layout->text + index); + int attr_offset; + if (trailing) { while (index < line->start_index + line->length && @@ -1806,14 +1808,20 @@ pango_layout_line_index_to_x (PangoLayoutLine *line, offset--; index = g_utf8_prev_char (layout->text + index) - layout->text; } - } - pango_glyph_string_index_to_x (run->glyphs, - layout->text + run->item->offset, - run->item->length, - &run->item->analysis, - index - run->item->offset, trailing, x_pos); + /* Note: we simply assert here, since our items are all internally + * created. If that ever changes, we need to add a fallback here. + */ + g_assert (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_HAS_CHAR_OFFSET); + attr_offset = ((PangoItemPrivate *)run->item)->char_offset; + + pango_glyph_string_index_to_x_full (run->glyphs, + layout->text + run->item->offset, + run->item->length, + &run->item->analysis, + layout->log_attrs + attr_offset, + index - run->item->offset, trailing, x_pos); if (x_pos) *x_pos += width; @@ -5039,6 +5047,7 @@ pango_layout_line_get_x_ranges (PangoLayoutLine *line, int run_start_index = MAX (start_index, run->item->offset); int run_end_index = MIN (end_index, run->item->offset + run->item->length); int run_start_x, run_end_x; + int attr_offset; g_assert (run_end_index > 0); @@ -5046,18 +5055,26 @@ pango_layout_line_get_x_ranges (PangoLayoutLine *line, run_end_index = g_utf8_prev_char (line->layout->text + run_end_index) - line->layout->text; - pango_glyph_string_index_to_x (run->glyphs, - line->layout->text + run->item->offset, - run->item->length, - &run->item->analysis, - run_start_index - run->item->offset, FALSE, - &run_start_x); - pango_glyph_string_index_to_x (run->glyphs, - line->layout->text + run->item->offset, - run->item->length, - &run->item->analysis, - run_end_index - run->item->offset, TRUE, - &run_end_x); + /* Note: we simply assert here, since our items are all internally + * created. If that ever changes, we need to add a fallback here. + */ + g_assert (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_HAS_CHAR_OFFSET); + attr_offset = ((PangoItemPrivate *)run->item)->char_offset; + + pango_glyph_string_index_to_x_full (run->glyphs, + line->layout->text + run->item->offset, + run->item->length, + &run->item->analysis, + line->layout->log_attrs + attr_offset, + run_start_index - run->item->offset, FALSE, + &run_start_x); + pango_glyph_string_index_to_x_full (run->glyphs, + line->layout->text + run->item->offset, + run->item->length, + &run->item->analysis, + line->layout->log_attrs + attr_offset, + run_end_index - run->item->offset, TRUE, + &run_end_x); (*ranges)[2*range_count] = x_offset + accumulated_width + MIN (run_start_x, run_end_x); (*ranges)[2*range_count + 1] = x_offset + accumulated_width + MAX (run_start_x, run_end_x); |