📄 pango-layout.c
字号:
*/voidpango_layout_index_to_line_x (PangoLayout *layout, int index, gboolean trailing, int *line, int *x_pos){ int line_num; PangoLayoutLine *layout_line = NULL; g_return_if_fail (layout != NULL); g_return_if_fail (index >= 0); g_return_if_fail (index <= layout->length); pango_layout_check_lines (layout); layout_line = pango_layout_index_to_line (layout, index, &line_num, NULL, NULL); if (layout_line) { /* use end of line if index was in the paragraph delimiters */ if (index > layout_line->start_index + layout_line->length) index = layout_line->start_index + layout_line->length; if (line) *line = line_num; pango_layout_line_index_to_x (layout_line, index, trailing, x_pos); } else { if (line) *line = -1; if (x_pos) *x_pos = -1; }}/** * pango_layout_move_cursor_visually: * @layout: a #PangoLayout. * @strong: whether the moving cursor is the strong cursor or the * weak cursor. The strong cursor is the cursor corresponding * to text insertion in the base direction for the layout. * @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: 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 @direction is positive, * then the new strong cursor position will be one position * to the right of the old cursor position. If @direction is negative, * then the new strong cursor position will be one position * to the left of the old cursor position. * * In the presence of bidirectional text, the correspondence * 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. **/voidpango_layout_move_cursor_visually (PangoLayout *layout, gboolean strong, int old_index, int old_trailing, int direction, int *new_index, int *new_trailing){ PangoLayoutLine *line = NULL; PangoLayoutLine *prev_line; PangoLayoutLine *next_line; int *log2vis_map; int *vis2log_map; int n_vis; int vis_pos, vis_pos_old, log_pos; int start_offset; gboolean off_start = FALSE; gboolean off_end = FALSE; g_return_if_fail (layout != NULL); g_return_if_fail (old_index >= 0 && old_index <= layout->length); g_return_if_fail (old_index < layout->length || old_trailing == 0); g_return_if_fail (new_index != NULL); g_return_if_fail (new_trailing != NULL); direction = (direction >= 0 ? 1 : -1); pango_layout_check_lines (layout); /* Find the line the old cursor is on */ line = pango_layout_index_to_line (layout, old_index, NULL, &prev_line, &next_line); 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, strong); n_vis = g_utf8_strlen (layout->text + line->start_index, line->length); /* Clamp old_index to fit on the line */ if (old_index > (line->start_index + line->length)) old_index = line->start_index + line->length; vis_pos = log2vis_map[old_index - line->start_index]; g_free (log2vis_map); /* Handling movement between lines */ if (vis_pos == 0 && direction < 0) { if (line->resolved_dir == PANGO_DIRECTION_LTR) off_start = TRUE; else off_end = TRUE; } else if (vis_pos == n_vis && direction > 0) { if (line->resolved_dir == PANGO_DIRECTION_LTR) off_end = TRUE; else off_start = TRUE; } if (off_start || off_end) { /* If we move over a paragraph boundary, count that as * an extra position in the motion */ gboolean paragraph_boundary; if (off_start) { if (!prev_line) { *new_index = -1; *new_trailing = 0; return; } line = prev_line; paragraph_boundary = (line->start_index + line->length != old_index); } else { if (!next_line) { *new_index = G_MAXINT; *new_trailing = 0; return; } line = next_line; paragraph_boundary = (line->start_index != old_index); } n_vis = g_utf8_strlen (layout->text + line->start_index, line->length); start_offset = g_utf8_pointer_to_offset (layout->text, layout->text + line->start_index); if (vis_pos == 0 && direction < 0) { vis_pos = n_vis; if (paragraph_boundary) vis_pos++; } else /* (vis_pos == n_vis && direction > 0) */ { vis_pos = 0; if (paragraph_boundary) vis_pos--; } } vis2log_map = pango_layout_line_get_vis2log_map (line, strong); vis_pos_old = vis_pos + direction; log_pos = g_utf8_pointer_to_offset (layout->text + line->start_index, layout->text + line->start_index + vis2log_map[vis_pos_old]); do { vis_pos += direction; log_pos += g_utf8_pointer_to_offset (layout->text + line->start_index + vis2log_map[vis_pos_old], layout->text + line->start_index + vis2log_map[vis_pos]); vis_pos_old = 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) { do { log_pos--; *new_index = g_utf8_prev_char (layout->text + *new_index) - layout->text; (*new_trailing)++; } while (log_pos > 0 && !layout->log_attrs[start_offset + log_pos].is_cursor_position); }}/** * pango_layout_xy_to_index: * @layout: a #PangoLayout * @x: the X offset (in #PangoGlyphUnit) * from the left edge of the layout. * @y: the Y offset (in #PangoGlyphUnit) * from the top edge of the layout * @index_: location to store calculated byte index * @trailing: location to store a integer indicating where * 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. * * Converts from X and Y position within a layout to the byte * index to the character at that logical position. If the * Y position is not inside the layout, the closest position is chosen * (the position will be clamped inside the layout). If the * X position is not within the layout, then the start or the * end of the line is chosen as described for pango_layout_x_to_index(). * If either the X or Y positions were not inside the layout, then the * function returns %FALSE; on an exact hit, it returns %TRUE. * * Return value: %TRUE if the coordinates were inside text, %FALSE otherwise. **/gbooleanpango_layout_xy_to_index (PangoLayout *layout, int x, int y, int *index, gint *trailing){ PangoLayoutIter *iter; PangoLayoutLine *prev_line = NULL; PangoLayoutLine *found = NULL; int found_line_x = 0; int prev_last = 0; int prev_line_x = 0; gboolean retval = FALSE; gboolean outside = FALSE; g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE); iter = pango_layout_get_iter (layout); do { PangoRectangle line_logical; int first_y, last_y; pango_layout_iter_get_line_extents (iter, NULL, &line_logical); pango_layout_iter_get_line_yrange (iter, &first_y, &last_y); if (y < first_y) { if (prev_line && y < (prev_last + (first_y - prev_last) / 2)) { found = prev_line; found_line_x = prev_line_x; } else { if (prev_line == NULL) outside = TRUE; /* off the top */ found = _pango_layout_iter_get_line (iter); found_line_x = x - line_logical.x; } } else if (y >= first_y && y < last_y) { found = _pango_layout_iter_get_line (iter); found_line_x = x - line_logical.x; } prev_line = _pango_layout_iter_get_line (iter); prev_last = last_y; prev_line_x = x - line_logical.x; if (found != NULL) break; } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); if (found == NULL) { /* Off the bottom of the layout */ outside = TRUE; found = prev_line; found_line_x = prev_line_x; } retval = pango_layout_line_x_to_index (found, found_line_x, index, trailing); if (outside) retval = FALSE; return retval;}/** * pango_layout_index_to_pos: * @layout: a #PangoLayout * @index_: byte index within @layout * @pos: rectangle in which to store the position of the grapheme * * Converts from an index within a #PangoLayout to the onscreen position * corresponding to the grapheme at that index, which is represented * as rectangle. Note that <literal>pos->x</literal> is always the leading * edge of the grapheme and <literal>pos->x + pos->width</literal> the trailing * edge of the grapheme. If the directionality of the grapheme is right-to-left, * then <literal>pos->width</literal> will be negative. **/voidpango_layout_index_to_pos (PangoLayout *layout, int index, PangoRectangle *pos){ PangoRectangle logical_rect; PangoLayoutIter *iter; PangoLayoutLine *layout_line = NULL; int x_pos; g_return_if_fail (layout != NULL); g_return_if_fail (index >= 0); g_return_if_fail (pos != NULL); iter = pango_layout_get_iter (layout); if (!ITER_IS_INVALID (iter)) { while (TRUE) { PangoLayoutLine *tmp_line = _pango_layout_iter_get_line (iter); if (tmp_line->start_index > index) { /* index is in the paragraph delimiters, move to * end of previous line */ index = layout_line->start_index + layout_line->length; break; } layout_line = tmp_line; pango_layout_iter_get_line_extents (iter, NULL, &logical_rect); if (layout_line->start_index + layout_line->length > index) break; if (!pango_layout_iter_next_line (iter)) { index = layout_line->start_index + layout_line->length; break; } } pos->y = logical_rect.y; pos->height = logical_rect.height; pango_layout_line_index_to_x (layout_line, index, 0, &x_pos); pos->x = logical_rect.x + x_pos; if (index < layout_line->start_index + layout_line->length) { pango_layout_line_index_to_x (layout_line, index, 1, &x_pos); pos->width = (logical_rect.x + x_pos) - pos->x; } else pos->width = 0; } pango_layout_iter_free (iter);}static voidpango_layout_line_get_range (PangoLayoutLine *line, char **start, char **end){ char *p; p = line->layout->text + line->start_index; if (start) *start = p; if (end) *end = p + line->length;}static int *pango_layout_line_get_vis2log_map (PangoLayoutLine *line, gboolean strong){ PangoLayout *layout = line->layout; PangoDirection prev_dir; PangoDirection cursor_dir; GSList *tmp_list; gchar *start, *end; int *result; int pos; int n_chars; pango_layout_line_get_range (line, &start, &end); n_chars = g_utf8_strlen (start, end - start); result = g_new (int, n_chars + 1); if (strong) cursor_dir = line->resolved_dir; else cursor_dir = (line->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; /* Handle the first visual position */ if (line->resolved_dir == cursor_dir) result[0] = line->resolved_dir == PANGO_DIRECTION_LTR ? 0 : end - start; prev_dir = line->resolved_dir; pos = 0; tmp_list = line->runs; while (tmp_list) { PangoLayoutRun *run = tmp_list->data; int run_n_chars = run->item->num_chars; PangoDirection run_dir = (run->item->analysis.level % 2) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; char *p = layout->text + run->item->offset; int i; /* pos is the visual position at the start of the run */ /* p is the logical byte index at the start of the run */ if (run_dir == PANGO_DIRECTION_LTR) { if ((cursor_dir == PANGO_DIRECTION_LTR) || (prev_dir == run_dir)) result[pos] = p - start; p = g_utf8_next_char (p); for (i = 1; i < run_n_chars; i++) { result[pos + i] = p - start; p = g_utf8_next_char (p); } if (cursor_dir == PANGO_DIRECTION_LTR) result[pos + run_n_chars] = p - start; } else { if (cursor_dir == PANGO_DIRECTION_RTL) result[pos + run_n_chars] = p - start; p = g_utf8_next_char (p); for (i = 1; i < run_n_chars; i++) { result[pos + run_n_chars - i] = p - start; p = g_utf8_next_char (p); } if ((cursor_dir == PANGO_DIRECTION_RTL) || (prev_dir == run_dir)) result[pos] = p - start; } pos += run_n_chars;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -