From 676359dce7d33d1b999888d1a33a5c96f9091a88 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Fri, 18 May 2001 16:04:40 +0000 Subject: Use ISO C99 varargs when available. Fri May 18 11:30:57 2001 Owen Taylor * pango/opentype/disasm.c: Use ISO C99 varargs when available. Thu May 17 11:16:23 2001 Owen Taylor * pango/mapping.c: Fixup docs, remove some FIXMEs that are no longer applicable. * pango/pango-layout.c: Move by graphemes, not characters. * pango/pango-layout.c (pango_layout_line_x_to_index): Position at the closest grapheme boundary, not at character boundaries. * pango/pango-layout.c (pango_layout_line_index_to_x): Return positions of grapheme boundaries, not character boundaries. --- pango/mapping.c | 28 +++--- pango/opentype/Makefile.am | 2 + pango/opentype/disasm.c | 5 ++ pango/pango-layout.c | 219 ++++++++++++++++++++++++++++++++------------- pango/pango-layout.h | 2 +- 5 files changed, 177 insertions(+), 79 deletions(-) (limited to 'pango') diff --git a/pango/mapping.c b/pango/mapping.c index f632cb61..a5e6a872 100644 --- a/pango/mapping.c +++ b/pango/mapping.c @@ -38,12 +38,12 @@ * @analysis: the analysis information return from pango_itemize() * @index: the byte index within @text * @trailing: whether we should compute the result for the beginning - * or end of the character (or cluster - the decision - * for which may be script dependent). + * or end of the character. * @x_pos: location to store result * * Converts from character position to x position. (X position - * is measured from the left edge of the run) + * is measured from the left edge of the run). Character positions + * are computed by dividing up each cluster into equal portions. */ void @@ -145,10 +145,6 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, p = g_utf8_next_char (p); } - /* Now interpolate the result. For South Asian languages - * we actually shouldn't iterpolate - */ - if (trailing) cluster_offset += 1; @@ -166,13 +162,15 @@ pango_glyph_string_index_to_x (PangoGlyphString *glyphs, * @x_pos: the x offset (in thousands of a device unit) * @index: location to store calculated byte index within @text * @trailing: location to store a integer indicating where - * in the cluster the user clicked. If the script - * allows positioning within the cluster, it is either - * 0 or 1; otherwise it is either 0 or the number - * of characters in the cluster. In either case - * 0 represents the trailing edge of the cluster. + * whether the user clicked on the leading or trailing + * edge of the character. * - * Convert from x offset to position. + * Convert from x offset to character position. Character positions + * are computed by dividing up each cluster into equal portions. + * In scripts where positioning within a cluster is not allowed + * (such as Thai), the returned value may not be a valid cursor + * position; the caller must combine the result with the logical + * attributes for the text to compute the valid cursor position. */ void pango_glyph_string_x_to_index (PangoGlyphString *glyphs, @@ -181,7 +179,7 @@ pango_glyph_string_x_to_index (PangoGlyphString *glyphs, PangoAnalysis *analysis, int x_pos, int *index, - int *trailing) + gboolean *trailing) { int i; int start_xpos = 0; @@ -293,8 +291,6 @@ pango_glyph_string_x_to_index (PangoGlyphString *glyphs, *index = (p - text); } - /* FIXME: Handle multiple character clusters better - */ if (trailing) *trailing = (cp - (int)cp > 0.5) ? 1 : 0; } diff --git a/pango/opentype/Makefile.am b/pango/opentype/Makefile.am index 553a7757..f42516df 100644 --- a/pango/opentype/Makefile.am +++ b/pango/opentype/Makefile.am @@ -30,7 +30,9 @@ libpango_ot_la_SOURCES = \ pango-ot-private.h \ pango-ot-ruleset.c +if BUILD_OT_TESTS noinst_PROGRAMS = ottest +endif ottest_SOURCES = \ ottest.c \ diff --git a/pango/opentype/disasm.c b/pango/opentype/disasm.c index 2e064ec2..d55a3593 100644 --- a/pango/opentype/disasm.c +++ b/pango/opentype/disasm.c @@ -19,11 +19,16 @@ * Boston, MA 02111-1307, USA. */ +#include /* For G_HAVE_ISO_VARARGS */ #include #include "disasm.h" +#ifdef G_HAVE_ISO_VARARGS +#define DUMP(...) dump (stream, indent, __VA_ARGS__) +#elif defined (G_HAVE_GNUC_VARARGS) #define DUMP(args...) dump (stream, indent, args) +#endif #define DUMP_FINT(strct,fld) dump (stream, indent, "<" #fld ">%d\n", (strct)->fld) #define DUMP_FUINT(strct,fld) dump (stream, indent, "<" #fld ">%u\n", (strct)->fld) #define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#4x\n", (strct)->fld) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 7e04e7dd..6016109d 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -1,7 +1,7 @@ /* Pango * pango-layout.c: Highlevel layout driver * - * Copyright (C) 2000 Red Hat Software + * Copyright (C) 2000, 2001 Red Hat Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -968,14 +968,12 @@ pango_layout_get_line (PangoLayout *layout, /** * pango_layout_line_index_to_x: - * @line: a #PangoLayoutLine - * @index: byte offset within the Layout's text - * @trailing: integer indicating where in the cluster the user clicked. - * If the script allows positioning within the cluster, it is either - * 0 or 1; otherwise it is either 0 or the number - * of characters in the cluster. In either case - * 0 represents the trailing edge of the cluster. - * @x_pos: location to store the x_offset (in thousandths of a device unit) + * @line: a #PangoLayoutLine + * @index: byte offset of a grapheme within the layout + * @trailing: an integer indicating the edge of the grapheme to retrieve the position + * of. If 0, the trailing edge of the grapheme, if > 0, the leading + * of the grapheme. + * @x_pos: location to store the x_offset (in thousandths of a device unit) * * Convert index within a line to X pos * @@ -984,9 +982,10 @@ pango_layout_get_line (PangoLayout *layout, void pango_layout_line_index_to_x (PangoLayoutLine *line, int index, - gboolean trailing, + int trailing, int *x_pos) { + PangoLayout *layout = line->layout; GSList *run_list = line->runs; int width = 0; @@ -1004,18 +1003,39 @@ pango_layout_line_index_to_x (PangoLayoutLine *line, if (shape_set) { if (x_pos) - *x_pos = width + (trailing ? logical_rect.width : 0); + *x_pos = width + (trailing > 0 ? logical_rect.width : 0); } else { + int offset = g_utf8_pointer_to_offset (layout->text, layout->text + index); + if (trailing) + { + while (index < line->start_index + line->length && + offset + 1 < layout->n_chars && + !layout->log_attrs[offset + 1].is_cursor_position) + { + offset++; + index = g_utf8_next_char (layout->text + index) - layout->text; + } + } + else + { + while (index > line->start_index && + !layout->log_attrs[offset].is_cursor_position) + { + offset--; + index = g_utf8_prev_char (layout->text + index) - layout->text; + } + + } + pango_glyph_string_index_to_x (run->glyphs, - line->layout->text + run->item->offset, + layout->text + run->item->offset, run->item->length, &run->item->analysis, index - run->item->offset, trailing, x_pos); - if (x_pos) - *x_pos += width; + *x_pos += width; } return; @@ -1030,17 +1050,17 @@ pango_layout_line_index_to_x (PangoLayoutLine *line, run_list = run_list->next; } - if(x_pos) + if (x_pos) *x_pos = width; } /** * pango_layout_index_to_line_x: * @layout: a #PangoLayout - * @index: the byte index of the character to find - * @trailing: whether we should compute the result for the beginning - * or end of the character (or cluster - the decision - * for which may be script dependent). + * @index: the byte index of a grapheme within the layout. + * @trailing: an integer indicating the edge of the grapheme to retrieve the position + * of. If 0, the trailing edge of the grapheme, if > 0, the leading + * of the grapheme. * @line: location to store resulting line index. (which will * between 0 and pango_layout_get_line_count(layout) - 1) * @x_pos: location to store resulting position within line @@ -1111,15 +1131,22 @@ pango_layout_index_to_line_x (PangoLayout *layout, /** * pango_layout_move_cursor_visually: * @layout: a #PangoLayout. - * @old_index: the old cursor byte index - * @old_trailing: + * @old_index: the byte index of the grapheme for the old index + * @old_trailing: if 0, the cursor was at the trailing edge of the + * grapheme indicated by @old_index, if > 0, the cursor + * was at the leading edge. * @direction: direction to move cursor. A negative * value indicates motion to the left. * @new_index: location to store the new cursor byte index. A value of -1 * indicates that the cursor has been moved off the beginning * of the layout. A value of G_MAXINT indicates that * the cursor has been moved off the end of the layout. - * @new_trailing: + * @new_trailing: number of characters to move forward from the location returned + * for @new_index to get the position where the cursor should + * be displayed. This allows distinguishing the position at + * the beginning of one line from the position at the end + * of the preceding line. @new_index is always on the line + * where the cursor should be displayed. * * Computes a new cursor position from an old position and * a count of positions to move visually. If @count is positive, @@ -1132,6 +1159,11 @@ pango_layout_index_to_line_x (PangoLayout *layout, * between logical and visual order will depend on the direction * of the current run, and there may be jumps when the cursor * is moved off of the end of a run. + * + * Motion here is in cursor positions, not in characters, so a + * single call to pango_layout_move_cursor_visually() may move the + * cursor over multiple characters when multiple characters combine + * to form a single grapheme. **/ void pango_layout_move_cursor_visually (PangoLayout *layout, @@ -1150,7 +1182,8 @@ pango_layout_move_cursor_visually (PangoLayout *layout, int *log2vis_map; int *vis2log_map; int n_vis; - int vis_pos; + int vis_pos, log_pos; + int start_offset; g_return_if_fail (layout != NULL); g_return_if_fail (old_index >= 0 && old_index <= layout->length); @@ -1186,7 +1219,9 @@ pango_layout_move_cursor_visually (PangoLayout *layout, else next_line = NULL; - if (old_trailing) + start_offset = g_utf8_pointer_to_offset (layout->text, layout->text + line->start_index); + + while (old_trailing--) old_index = g_utf8_next_char (layout->text + old_index) - layout->text; log2vis_map = pango_layout_line_get_log2vis_map (line, TRUE); @@ -1250,19 +1285,31 @@ pango_layout_move_cursor_visually (PangoLayout *layout, vis_pos = 0; } - vis_pos += (direction > 0) ? 1 : -1; - vis2log_map = pango_layout_line_get_vis2log_map (line, TRUE); + + do + { + vis_pos += direction > 0 ? 1 : -1; + log_pos = g_utf8_pointer_to_offset (layout->text + line->start_index, + layout->text + line->start_index + vis2log_map[vis_pos]); + } + while (vis_pos > 0 && vis_pos < n_vis && + !layout->log_attrs[start_offset + log_pos].is_cursor_position); + *new_index = line->start_index + vis2log_map[vis_pos]; g_free (vis2log_map); + *new_trailing = 0; + if (*new_index == line->start_index + line->length && line->length > 0) { - *new_index = g_utf8_prev_char (layout->text + *new_index) - layout->text; - *new_trailing = 1; + do + { + log_pos--; + *new_index = g_utf8_prev_char (layout->text + *new_index) - layout->text; + } + while (log_pos > 0 && !layout->log_attrs[start_offset + log_pos].is_cursor_position); } - else - *new_trailing = 0; } /** @@ -1274,11 +1321,9 @@ pango_layout_move_cursor_visually (PangoLayout *layout, * from the top edge of the layout * @index: location to store calculated byte index * @trailing: location to store a integer indicating where - * in the cluster the user clicked. If the script - * allows positioning within the cluster, it is either - * 0 or 1; otherwise it is either 0 or the number - * of characters in the cluster. In either case - * 0 represents the trailing edge of the cluster. + * in the grapheme the user clicked. It will either + * be zero, or the number of characters in the + * grapheme. 0 represents the trailing edge of the grapheme. * * Convert from X and Y position within a layout to the byte * index to the character at that logical position. If the @@ -1294,7 +1339,7 @@ pango_layout_xy_to_index (PangoLayout *layout, int x, int y, int *index, - gboolean *trailing) + gint *trailing) { PangoLayoutIter *iter; PangoLayoutLine *prev_line = NULL; @@ -1376,14 +1421,14 @@ pango_layout_xy_to_index (PangoLayout *layout, * pango_layout_index_to_pos: * @layout: a #PangoLayout * @index: byte index within @layout - * @pos: rectangle in which to store the position of the character + * @pos: rectangle in which to store the position of the grapheme * * Convert from an index within a PangoLayout to the onscreen position - * corresponding to that character, which is represented as rectangle. - * Note that pos->x is always the leading edge of the character. If the - * and pos->x + pos->width the trailing edge of the character. If the - * directionality of the character is right-to-left, then pos->width - * will be negative. + * corresponding to the grapheme at that index, which is represented + * as rectangle. Note that pos->x is always the leading edge of the + * grapheme and pos->x + pos->width the trailing edge of the + * grapheme. If the directionality of the grapheme is right-to-left, + * then pos->width will be negative. **/ void pango_layout_index_to_pos (PangoLayout *layout, @@ -1444,10 +1489,10 @@ pango_layout_index_to_pos (PangoLayout *layout, pos->y = logical_rect.y; pos->height = logical_rect.height; - pango_layout_line_index_to_x (layout_line, index, FALSE, &x_pos); + pango_layout_line_index_to_x (layout_line, index, 0, &x_pos); pos->x = logical_rect.x + x_pos; - pango_layout_line_index_to_x (layout_line, index, TRUE, &x_pos); + pango_layout_line_index_to_x (layout_line, index, 1, &x_pos); pos->width = (logical_rect.x + x_pos) - pos->x; } @@ -2860,13 +2905,12 @@ pango_layout_line_unref (PangoLayoutLine *line) * @line: a #PangoLayoutLine * @x_pos: the x offset (in thousands of a device unit) * from the left edge of the line. - * @index: location to store calculated byte offset. + * @index: location to store calculated byte offset for + * the grapheme in which the user clicked. * @trailing: location to store a integer indicating where - * in the cluster the user clicked. If the script - * allows positioning within the cluster, it is either - * 0 or 1; otherwise it is either 0 or the number - * of characters in the cluster. In either case - * 0 represents the trailing edge of the cluster. + * in the grapheme the user clicked. It will either + * be zero, or the number of characters in the + * grapheme. 0 represents the trailing edge of the cluster. * * Convert from x offset to the byte index of the corresponding * character within the text of the layout. If @x_pos is outside the line, @@ -2883,9 +2927,13 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, GSList *tmp_list; gint start_pos = 0; gint first_index = 0; /* line->start_index */ - gint last_index; /* last char in line */ - gint end_index; /* end iterator for line (one char past last_index) */ + gint first_offset; + gint last_index; /* start of last grapheme in line */ + gint last_offset; + gint end_index; /* end iterator for line */ + gint end_offset; /* end iterator for line */ PangoDirection base_dir; + PangoLayout *layout; gboolean last_trailing; g_return_val_if_fail (line != NULL, FALSE); @@ -2894,7 +2942,9 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, if (!LINE_IS_VALID (line)) return FALSE; - base_dir = pango_context_get_base_dir (line->layout->context); + layout = line->layout; + + base_dir = pango_context_get_base_dir (layout->context); /* Find the last index in the line */ @@ -2912,8 +2962,21 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, g_assert (line->length > 0); + first_offset = g_utf8_pointer_to_offset (layout->text, layout->text + line->start_index); + end_index = first_index + line->length; - last_index = g_utf8_prev_char (line->layout->text + end_index) - line->layout->text; + end_offset = first_offset + g_utf8_pointer_to_offset (layout->text + first_index, layout->text + end_index); + + last_index = end_index; + last_offset = end_offset; + last_trailing = 0; + do + { + last_index = g_utf8_prev_char (layout->text + last_index) - layout->text; + last_offset--; + last_trailing++; + } + while (last_offset > first_offset && !layout->log_attrs[last_offset].is_cursor_position); /* This is a HACK. If a program only keeps track if cursor (etc) * indices and not the trailing flag, then the trailing index of the @@ -2922,11 +2985,12 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, * positions with wrapped lines should distinguish leading and * trailing cursors. */ - tmp_list = line->layout->lines; + tmp_list = layout->lines; while (tmp_list->data != line) tmp_list = tmp_list->next; - last_trailing = tmp_list->next ? 0 : 1; + if (tmp_list->next) + last_trailing = 0; if (x_pos < 0) { @@ -2955,10 +3019,14 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, if (x_pos >= start_pos && x_pos < start_pos + logical_rect.width) { + int offset; + gboolean char_trailing; + int grapheme_start_offset; + int grapheme_end_offset; int pos; + int char_index; - if (index) - *index = run->item->offset; + char_index = run->item->offset; if (shape_set) { @@ -2967,15 +3035,42 @@ pango_layout_line_x_to_index (PangoLayoutLine *line, else { pango_glyph_string_x_to_index (run->glyphs, - line->layout->text + run->item->offset, run->item->length, + layout->text + run->item->offset, run->item->length, &run->item->analysis, x_pos - start_pos, - &pos, trailing); + &pos, &char_trailing); + + char_index += pos; + } - if (index) - *index += pos; + /* Convert from characters to graphemes */ + + offset = g_utf8_pointer_to_offset (layout->text, layout->text + char_index); + + grapheme_start_offset = offset; + while (grapheme_start_offset > first_offset && + !layout->log_attrs[grapheme_start_offset].is_cursor_position) + { + char_index = g_utf8_prev_char (layout->text + char_index) - layout->text; + grapheme_start_offset--; } + if (index) + *index = char_index; + if (trailing) + { + grapheme_end_offset = offset; + do + grapheme_end_offset++; + while (grapheme_end_offset < end_offset && + !layout->log_attrs[grapheme_end_offset].is_cursor_position); + + if (offset + char_trailing > (grapheme_start_offset + grapheme_end_offset) / 2) + *trailing = grapheme_end_offset - grapheme_start_offset; + else + *trailing = 0; + } + return TRUE; } diff --git a/pango/pango-layout.h b/pango/pango-layout.h index 1944398f..28b4cfcb 100644 --- a/pango/pango-layout.h +++ b/pango/pango-layout.h @@ -151,7 +151,7 @@ gboolean pango_layout_xy_to_index (PangoLayout *layout, int x, int y, int *index, - gboolean *trailing); + int *trailing); void pango_layout_get_extents (PangoLayout *layout, PangoRectangle *ink_rect, PangoRectangle *logical_rect); -- cgit v1.2.1