summaryrefslogtreecommitdiff
path: root/pango
diff options
context:
space:
mode:
Diffstat (limited to 'pango')
-rw-r--r--pango/glyphstring.c90
-rw-r--r--pango/pango-glyph.h11
-rw-r--r--pango/pango-layout.c53
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);