diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-01-20 23:59:44 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-01-25 15:29:16 -0500 |
commit | 45762d6b50b29447ee97c759c7a7cc55cb534703 (patch) | |
tree | b3f45c39f4a9d68f03130dd8527f51fc50ef719a | |
parent | 33eb81450f8572762a5b805cf0bb4740c86f45cf (diff) | |
download | pango-45762d6b50b29447ee97c759c7a7cc55cb534703.tar.gz |
The big rename of doom
simple layout -> layout
line iter -> layout iter
line -> layout line
This commit replaces the old PangoLayout implementation
with PangoSimpleLayout, and does all the necessary
cleanups.
51 files changed, 2204 insertions, 11444 deletions
diff --git a/examples/cairoshape.c b/examples/cairoshape.c index 4c1de86b..49ac3510 100644 --- a/examples/cairoshape.c +++ b/examples/cairoshape.c @@ -122,22 +122,22 @@ mini_svg_shape_renderer (cairo_t *cr, } -static PangoSimpleLayout * +static PangoLayout * get_layout (cairo_t *cr) { - PangoSimpleLayout *layout; + PangoLayout *layout; PangoAttrList *attrs; PangoRectangle ink_rect = {1 * PANGO_SCALE, -11 * PANGO_SCALE, 8 * PANGO_SCALE, 10 * PANGO_SCALE}; PangoRectangle logical_rect = {0 * PANGO_SCALE, -12 * PANGO_SCALE, 10 * PANGO_SCALE, 12 * PANGO_SCALE}; const char *p; - /* Create a PangoSimpleLayout, set the font and text */ - layout = pango_cairo_create_simple_layout (cr); + /* Create a PangoLayout, set the font and text */ + layout = pango_cairo_create_layout (cr); - pango_cairo_context_set_shape_renderer (pango_simple_layout_get_context (layout), + pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout), mini_svg_shape_renderer, NULL, NULL); - pango_simple_layout_set_text (layout, text, -1); + pango_layout_set_text (layout, text, -1); attrs = pango_attr_list_new (); @@ -157,7 +157,7 @@ get_layout (cairo_t *cr) pango_attr_list_insert (attrs, attr); } - pango_simple_layout_set_attributes (layout, attrs); + pango_layout_set_attributes (layout, attrs); pango_attr_list_unref (attrs); return layout; @@ -166,8 +166,8 @@ get_layout (cairo_t *cr) static void draw_text (cairo_t *cr, int *width, int *height) { - PangoSimpleLayout *layout = get_layout (cr); - PangoLines *lines = pango_simple_layout_get_lines (layout); + PangoLayout *layout = get_layout (cr); + PangoLines *lines = pango_layout_get_lines (layout); /* Adds a fixed 10-pixel margin on the sides. */ diff --git a/examples/cairosimple.c b/examples/cairosimple.c index 3d7a5428..6235a02a 100644 --- a/examples/cairosimple.c +++ b/examples/cairosimple.c @@ -17,7 +17,7 @@ draw_text (cairo_t *cr) */ #define TWEAKABLE_SCALE ((double) 0.1) - PangoSimpleLayout *layout; + PangoLayout *layout; PangoLines *lines; PangoFontDescription *desc; int i; @@ -26,17 +26,17 @@ draw_text (cairo_t *cr) */ cairo_translate (cr, RADIUS / TWEAKABLE_SCALE, RADIUS / TWEAKABLE_SCALE); - /* Create a PangoSimpleLayout, set the font and text */ - layout = pango_cairo_create_simple_layout (cr); + /* Create a PangoLayout, set the font and text */ + layout = pango_cairo_create_layout (cr); - pango_simple_layout_set_text (layout, "Test\nسَلام", -1); + pango_layout_set_text (layout, "Test\nسَلام", -1); desc = pango_font_description_from_string (FONT_WITH_MANUAL_SIZE); pango_font_description_set_absolute_size (desc, FONT_SIZE * DEVICE_DPI * PANGO_SCALE / (72.0 * TWEAKABLE_SCALE)); //pango_font_description_set_size(desc, 27 * PANGO_SCALE / TWEAKABLE_SCALE); printf("PANGO_SCALE = %d\n", PANGO_SCALE); - pango_simple_layout_set_font_description (layout, desc); + pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); /* Draw the layout N_WORDS times in a circle */ @@ -55,9 +55,9 @@ draw_text (cairo_t *cr) cairo_rotate (cr, angle * G_PI / 180.); /* Inform Pango to re-layout the text with the new transformation */ - pango_cairo_update_simple_layout (cr, layout); + pango_cairo_update_layout (cr, layout); - lines = pango_simple_layout_get_lines (layout); + lines = pango_layout_get_lines (layout); pango_lines_get_extents (lines, NULL, &ext); cairo_move_to (cr,( - (((double)ext.width) / PANGO_SCALE) / 2.0) , (- RADIUS) / TWEAKABLE_SCALE); diff --git a/examples/cairotwisted.c b/examples/cairotwisted.c index 8323453a..217e5e44 100644 --- a/examples/cairotwisted.c +++ b/examples/cairotwisted.c @@ -471,8 +471,8 @@ draw_text (cairo_t *cr, const char *font, const char *text) { - PangoSimpleLayout *layout; - PangoLine *line; + PangoLayout *layout; + PangoLayoutLine *line; PangoFontDescription *desc; cairo_font_options_t *font_options; @@ -484,18 +484,18 @@ draw_text (cairo_t *cr, cairo_set_font_options (cr, font_options); cairo_font_options_destroy (font_options); - layout = pango_cairo_create_simple_layout (cr); + layout = pango_cairo_create_layout (cr); desc = pango_font_description_from_string (font); - pango_simple_layout_set_font_description (layout, desc); + pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); - pango_simple_layout_set_text (layout, text, -1); + pango_layout_set_text (layout, text, -1); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); cairo_move_to (cr, x, y); - pango_cairo_line_path (cr, line); + pango_cairo_layout_line_path (cr, line); g_object_unref (layout); } diff --git a/examples/parshape.c b/examples/parshape.c index 69881d3c..219cc378 100644 --- a/examples/parshape.c +++ b/examples/parshape.c @@ -57,7 +57,7 @@ main (int argc, char *argv[]) while (!pango_line_breaker_done (breaker)) { - PangoLine *line; + PangoLayoutLine *line; PangoRectangle ext; gboolean ltr; @@ -66,8 +66,8 @@ main (int argc, char *argv[]) PANGO_WRAP_CHAR, PANGO_ELLIPSIZE_NONE); - pango_line_get_extents (line, NULL, &ext); - line = pango_line_justify (line, width); + pango_layout_line_get_extents (line, NULL, &ext); + line = pango_layout_line_justify (line, width); pango_lines_add_line (lines, line, x, y - ext.y); ltr = pango_line_breaker_get_direction (breaker) == PANGO_DIRECTION_LTR; @@ -99,11 +99,11 @@ main (int argc, char *argv[]) for (int i = 0; i < pango_lines_get_line_count (lines); i++) { - PangoLine *line = pango_lines_get_line (lines, i, &x, &y); + PangoLayoutLine *line = pango_lines_get_line (lines, i, &x, &y); cairo_save (cr); cairo_move_to (cr, x / (double)PANGO_SCALE, y / (double)PANGO_SCALE); - pango_cairo_show_line (cr, line); + pango_cairo_show_layout_line (cr, line); cairo_restore (cr); } diff --git a/pango/ellipsize.c b/pango/ellipsize.c index 7f2d2b9d..149602a6 100644 --- a/pango/ellipsize.c +++ b/pango/ellipsize.c @@ -23,11 +23,10 @@ #include <string.h> #include "pango-glyph-item.h" -#include "pango-layout-private.h" #include "pango-font-private.h" #include "pango-attributes-private.h" #include "pango-impl-utils.h" -#include "pango-line-private.h" +#include "pango-layout-line-private.h" typedef struct _EllipsizeState EllipsizeState; typedef struct _RunInfo RunInfo; @@ -742,63 +741,11 @@ current_width (EllipsizeState *state) return state->total_width - (state->gap_end_x - state->gap_start_x) + state->ellipsis_width; } -/** - * _pango_layout_line_ellipsize: - * @line: a `PangoLayoutLine` - * @attrs: Attributes being used for itemization/shaping - * @shape_flags: Flags to use when shaping - * - * Given a `PangoLayoutLine` with the runs still in logical order, ellipsize - * it according the layout's policy to fit within the set width of the layout. - * - * Return value: whether the line had to be ellipsized - **/ -gboolean -_pango_layout_line_ellipsize (PangoLayoutLine *line, - PangoAttrList *attrs, - PangoShapeFlags shape_flags, - int goal_width) -{ - PangoLayout *layout = line->layout; - PangoContext *context = layout->context; - const char *text = layout->text; - PangoLogAttr *log_attrs = layout->log_attrs; - PangoEllipsizeMode ellipsize = layout->ellipsize; - EllipsizeState state; - gboolean is_ellipsized = FALSE; - - g_return_val_if_fail (ellipsize != PANGO_ELLIPSIZE_NONE && goal_width >= 0, is_ellipsized); - - init_state (&state, context, text, line->start_index, log_attrs, ellipsize, line->runs, attrs, shape_flags); - - if (state.total_width <= goal_width) - goto out; - - find_initial_span (&state); - - while (current_width (&state) > goal_width) - { - if (!remove_one_span (&state)) - break; - } - - fixup_ellipsis_run (&state, MAX (goal_width - current_width (&state), 0)); - - g_slist_free (line->runs); - line->runs = get_run_list (&state); - is_ellipsized = TRUE; - - out: - free_state (&state); - - return is_ellipsized; -} - void -pango_line_ellipsize (PangoLine *line, - PangoContext *context, - PangoEllipsizeMode ellipsize, - int goal_width) +pango_layout_line_ellipsize (PangoLayoutLine *line, + PangoContext *context, + PangoEllipsizeMode ellipsize, + int goal_width) { EllipsizeState state; const char *text = line->data->text; diff --git a/pango/meson.build b/pango/meson.build index d29df3ba..7becb191 100644 --- a/pango/meson.build +++ b/pango/meson.build @@ -31,12 +31,11 @@ pango_sources = [ 'serializer.c', 'json/gtkjsonparser.c', 'json/gtkjsonprinter.c', + 'pango-layout-line.c', 'pango-layout-run.c', - 'pango-line.c', 'pango-line-breaker.c', 'pango-lines.c', - 'pango-line-iter.c', - 'pango-simple-layout.c', + 'pango-layout-iter.c', ] pango_headers = [ @@ -58,10 +57,10 @@ pango_headers = [ 'pango-gravity.h', 'pango-item.h', 'pango-language.h', + 'pango-layout-line.h', 'pango-layout-run.h', - 'pango-line.h', 'pango-line-breaker.h', - 'pango-line-iter.h', + 'pango-layout-iter.h', 'pango-lines.h', 'pango-layout.h', 'pango-matrix.h', @@ -69,7 +68,6 @@ pango_headers = [ 'pango-modules.h', 'pango-renderer.h', 'pango-script.h', - 'pango-simple-layout.h', 'pango-tabs.h', 'pango-types.h', 'pango-utils.h', diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 01b865bc..4d7908ff 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -1510,8 +1510,7 @@ pango_attr_overline_color_new (guint16 red, * Modify the height of logical line extents by a factor. * * This affects the values returned by - * [method@Pango.LayoutLine.get_extents], - * [method@Pango.LayoutLine.get_pixel_extents] and + * [method@Pango.LayoutLine.get_extents] and * [method@Pango.LayoutIter.get_line_extents]. * * @@ -1538,7 +1537,6 @@ pango_attr_line_height_new (double factor) * * This affects the values returned by * [method@Pango.LayoutLine.get_extents], - * [method@Pango.LayoutLine.get_pixel_extents] and * [method@Pango.LayoutIter.get_line_extents]. * * Since: 1.50 diff --git a/pango/pango-layout-iter-private.h b/pango/pango-layout-iter-private.h new file mode 100644 index 00000000..7cf69b30 --- /dev/null +++ b/pango/pango-layout-iter-private.h @@ -0,0 +1,5 @@ +#pragma once + +#include "pango-layout-iter.h" + +PangoLayoutIter * pango_layout_iter_new (PangoLines *lines); diff --git a/pango/pango-line-iter.c b/pango/pango-layout-iter.c index ca31a1a3..91d37b46 100644 --- a/pango/pango-line-iter.c +++ b/pango/pango-layout-iter.c @@ -1,13 +1,14 @@ #include "config.h" -#include "pango-line-iter-private.h" +#include "pango-layout-iter-private.h" #include "pango-lines-private.h" -#include "pango-line-private.h" +#include "pango-layout-run-private.h" +#include "pango-layout-line-private.h" #include "pango-layout-run-private.h" -/* {{{ PangoLineIter implementation */ +/* {{{ PangoLayoutIter implementation */ -struct _PangoLineIter +struct _PangoLayoutIter { PangoLines *lines; guint serial; @@ -15,7 +16,7 @@ struct _PangoLineIter int line_no; int line_x; int line_y; - PangoLine *line; + PangoLayoutLine *line; GSList *run_link; PangoLayoutRun *run; int index; @@ -36,8 +37,8 @@ struct _PangoLineIter int character_position; }; -G_DEFINE_BOXED_TYPE (PangoLineIter, pango_line_iter, - pango_line_iter_copy, pango_line_iter_free); +G_DEFINE_BOXED_TYPE (PangoLayoutIter, pango_layout_iter, + pango_layout_iter_copy, pango_layout_iter_free); /* }}} */ @@ -46,10 +47,10 @@ G_DEFINE_BOXED_TYPE (PangoLineIter, pango_line_iter, #define ITER_IS_VALID(iter) ((iter)->serial == (iter)->lines->serial) static gboolean -line_is_terminated (PangoLineIter *iter) +line_is_terminated (PangoLayoutIter *iter) { if (iter->line_no + 1 < pango_lines_get_line_count (iter->lines)) - return pango_line_ends_paragraph (iter->line); + return pango_layout_line_ends_paragraph (iter->line); return FALSE; @@ -98,7 +99,7 @@ cluster_width (PangoGlyphString *glyphs, * is the byte index of the cluster start relative to the run. */ static void -update_cluster (PangoLineIter *iter, +update_cluster (PangoLayoutIter *iter, int cluster_start_index) { PangoGlyphItem *glyph_item; @@ -151,14 +152,14 @@ update_cluster (PangoLineIter *iter, * is considered non-empty. */ static gboolean -next_nonempty_line (PangoLineIter *iter, - gboolean include_terminators) +next_nonempty_line (PangoLayoutIter *iter, + gboolean include_terminators) { gboolean result; while (TRUE) { - result = pango_line_iter_next_line (iter); + result = pango_layout_iter_next_line (iter); if (!result) break; @@ -177,14 +178,14 @@ next_nonempty_line (PangoLineIter *iter, * paragraph separator is considered non-empty. */ static gboolean -next_nonempty_run (PangoLineIter *iter, +next_nonempty_run (PangoLayoutIter *iter, gboolean include_terminators) { gboolean result; while (TRUE) { - result = pango_line_iter_next_run (iter); + result = pango_layout_iter_next_run (iter); if (!result) break; @@ -203,7 +204,7 @@ next_nonempty_run (PangoLineIter *iter, * (But not positions introduced by line wrapping). */ static gboolean -next_cluster_internal (PangoLineIter *iter, +next_cluster_internal (PangoLayoutIter *iter, gboolean include_terminators) { PangoGlyphItem *glyph_item; @@ -228,8 +229,8 @@ next_cluster_internal (PangoLineIter *iter, } static void -update_run (PangoLineIter *iter, - int start_index) +update_run (PangoLayoutIter *iter, + int start_index) { PangoGlyphItem *glyph_item; @@ -279,9 +280,9 @@ update_run (PangoLineIter *iter, } static inline void -offset_line (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +offset_line (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { if (ink_rect) { @@ -296,9 +297,9 @@ offset_line (PangoLineIter *iter, } static inline void -offset_run (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +offset_run (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { if (ink_rect) ink_rect->x += iter->run_x; @@ -309,26 +310,26 @@ offset_run (PangoLineIter *iter, /* }}} */ /* {{{ Private API */ -PangoLineIter * -pango_line_iter_new (PangoLines *lines) +PangoLayoutIter * +pango_layout_iter_new (PangoLines *lines) { - PangoLineIter *iter; + PangoLayoutIter *iter; int run_start_index; g_return_val_if_fail (PANGO_IS_LINES (lines), NULL); - iter = g_new0 (PangoLineIter, 1); + iter = g_new0 (PangoLayoutIter, 1); iter->lines = g_object_ref (lines); iter->serial = pango_lines_get_serial (lines); iter->line_no = 0; iter->line = pango_lines_get_line (iter->lines, 0, &iter->line_x, &iter->line_y); - iter->run_link = pango_line_get_runs (iter->line); + iter->run_link = pango_layout_line_get_runs (iter->line); if (iter->run_link) { iter->run = iter->run_link->data; - run_start_index = iter->run->item->offset; + run_start_index = pango_layout_run_get_glyph_item (iter->run)->item->offset; } else { @@ -345,36 +346,36 @@ pango_line_iter_new (PangoLines *lines) /* {{{ Public API */ /** - * pango_line_iter_copy: - * @iter: (nullable): a `PangoLineIter` + * pango_layout_iter_copy: + * @iter: (nullable): a `PangoLayoutIter` * - * Copies a `PangoLineIter`. + * Copies a `PangoLayoutIter`. * - * Return value: (nullable): the newly allocated `PangoLineIter` + * Return value: (nullable): the newly allocated `PangoLayoutIter` */ -PangoLineIter * -pango_line_iter_copy (PangoLineIter *iter) +PangoLayoutIter * +pango_layout_iter_copy (PangoLayoutIter *iter) { - PangoLineIter *copy; + PangoLayoutIter *copy; if (iter == NULL) return NULL; - copy = g_new0 (PangoLineIter, 1); - memcpy (iter, copy, sizeof (PangoLineIter)); + copy = g_new0 (PangoLayoutIter, 1); + memcpy (iter, copy, sizeof (PangoLayoutIter)); g_object_ref (copy->lines); return copy; } /** - * pango_line_iter_free: - * @iter: (nullable): a `PangoLineIter` + * pango_layout_iter_free: + * @iter: (nullable): a `PangoLayoutIter` * * Frees an iterator that's no longer in use. */ void -pango_line_iter_free (PangoLineIter *iter) +pango_layout_iter_free (PangoLayoutIter *iter) { if (iter == NULL) return; @@ -384,29 +385,29 @@ pango_line_iter_free (PangoLineIter *iter) } /** - * pango_line_iter_get_lines: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_lines: + * @iter: a `PangoLayoutIter` * - * Gets the `PangoLines` object associated with a `PangoLineIter`. + * Gets the `PangoLines` object associated with a `PangoLayoutIter`. * * Return value: (transfer none): the lines associated with @iter */ PangoLines * -pango_line_iter_get_lines (PangoLineIter *iter) +pango_layout_iter_get_lines (PangoLayoutIter *iter) { return iter->lines; } /** - * pango_line_iter_get_line: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_line: + * @iter: a `PangoLayoutIter` * * Gets the current line. * * Return value: (transfer none): the current line */ -PangoLine * -pango_line_iter_get_line (PangoLineIter *iter) +PangoLayoutLine * +pango_layout_iter_get_line (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), NULL); @@ -414,15 +415,15 @@ pango_line_iter_get_line (PangoLineIter *iter) } /** - * pango_line_iter_at_last_line: - * @iter: a `PangoLineIter` + * pango_layout_iter_at_last_line: + * @iter: a `PangoLayoutIter` * * Determines whether @iter is on the last line. * * Return value: %TRUE if @iter is on the last line */ gboolean -pango_line_iter_at_last_line (PangoLineIter *iter) +pango_layout_iter_at_last_line (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), FALSE); @@ -430,8 +431,8 @@ pango_line_iter_at_last_line (PangoLineIter *iter) } /** - * pango_line_iter_get_run: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_run: + * @iter: a `PangoLayoutIter` * * Gets the current run. * @@ -443,7 +444,7 @@ pango_line_iter_at_last_line (PangoLineIter *iter) * Return value: (transfer none) (nullable): the current run */ PangoLayoutRun * -pango_line_iter_get_run (PangoLineIter *iter) +pango_layout_iter_get_run (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), NULL); @@ -451,8 +452,8 @@ pango_line_iter_get_run (PangoLineIter *iter) } /** - * pango_line_iter_get_index: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_index: + * @iter: a `PangoLayoutIter` * * Gets the current byte index. * @@ -462,12 +463,12 @@ pango_line_iter_get_run (PangoLineIter *iter) * Note that iterating forward by char moves in visual order, * not logical order, so indexes may not be sequential. Also, * the index may be equal to the length of the text in the - * layout, if on the %NULL run (see [method@Pango.LineIter.get_run]). + * layout, if on the %NULL run (see [method@Pango.LayoutIter.get_run]). * * Return value: current byte index */ int -pango_line_iter_get_index (PangoLineIter *iter) +pango_layout_iter_get_index (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), 0); @@ -475,8 +476,8 @@ pango_line_iter_get_index (PangoLineIter *iter) } /** - * pango_line_iter_next_line: - * @iter: a `PangoLineIter` + * pango_layout_iter_next_line: + * @iter: a `PangoLayoutIter` * * Moves @iter forward to the start of the next line. * @@ -485,7 +486,7 @@ pango_line_iter_get_index (PangoLineIter *iter) * Return value: whether motion was possible */ gboolean -pango_line_iter_next_line (PangoLineIter *iter) +pango_layout_iter_next_line (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), FALSE); @@ -494,7 +495,7 @@ pango_line_iter_next_line (PangoLineIter *iter) return FALSE; iter->line_no++; - iter->run_link = pango_line_get_runs (iter->line); + iter->run_link = pango_layout_line_get_runs (iter->line); if (iter->run_link) iter->run = iter->run_link->data; else @@ -506,8 +507,8 @@ pango_line_iter_next_line (PangoLineIter *iter) } /** - * pango_line_iter_next_run: - * @iter: a `PangoLineIter` + * pango_layout_iter_next_run: + * @iter: a `PangoLayoutIter` * * Moves @iter forward to the next run in visual order. * @@ -516,25 +517,26 @@ pango_line_iter_next_line (PangoLineIter *iter) * Return value: whether motion was possible */ gboolean -pango_line_iter_next_run (PangoLineIter *iter) +pango_layout_iter_next_run (PangoLayoutIter *iter) { int run_start_index; g_return_val_if_fail (ITER_IS_VALID (iter), FALSE); if (iter->run == NULL) - return pango_line_iter_next_line (iter); + return pango_layout_iter_next_line (iter); iter->run_link = iter->run_link->next; if (iter->run_link == NULL) { - run_start_index = iter->run->item->offset + iter->run->item->length; + PangoItem *item = pango_layout_run_get_glyph_item (iter->run)->item; + run_start_index = item->offset + item->length; iter->run = NULL; } else { iter->run = iter->run_link->data; - run_start_index = iter->run->item->offset; + run_start_index = pango_layout_run_get_glyph_item (iter->run)->item->offset; } update_run (iter, run_start_index); @@ -543,8 +545,8 @@ pango_line_iter_next_run (PangoLineIter *iter) } /** - * pango_line_iter_next_cluster: - * @iter: a `PangoLineIter` + * pango_layout_iter_next_cluster: + * @iter: a `PangoLayoutIter` * * Moves @iter forward to the next cluster in visual order. * @@ -553,7 +555,7 @@ pango_line_iter_next_run (PangoLineIter *iter) * Return value: whether motion was possible */ gboolean -pango_line_iter_next_cluster (PangoLineIter *iter) +pango_layout_iter_next_cluster (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), FALSE); @@ -561,8 +563,8 @@ pango_line_iter_next_cluster (PangoLineIter *iter) } /** - * pango_line_iter_next_char: - * @iter: a `PangoLineIter` + * pango_layout_iter_next_char: + * @iter: a `PangoLayoutIter` * * Moves @iter forward to the next character in visual order. * @@ -571,7 +573,7 @@ pango_line_iter_next_cluster (PangoLineIter *iter) * Return value: whether motion was possible */ gboolean -pango_line_iter_next_char (PangoLineIter *iter) +pango_layout_iter_next_char (PangoLayoutIter *iter) { const char *text; @@ -607,17 +609,17 @@ pango_line_iter_next_char (PangoLineIter *iter) } /** - * pango_line_iter_get_layout_extents: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_layout_extents: + * @iter: a `PangoLayoutIter` * @ink_rect: (out) (optional): rectangle to fill with ink extents * @logical_rect: (out) (optional): rectangle to fill with logical extents * * Obtains the extents of the `PangoLines` being iterated over. */ void -pango_line_iter_get_layout_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_iter_get_layout_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { g_return_if_fail (ITER_IS_VALID (iter)); @@ -625,8 +627,8 @@ pango_line_iter_get_layout_extents (PangoLineIter *iter, } /** - * pango_line_iter_get_line_extents: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_line_extents: + * @iter: a `PangoLayoutIter` * @ink_rect: (out) (optional): rectangle to fill with ink extents * @logical_rect: (out) (optional): rectangle to fill with logical extents * @@ -635,39 +637,39 @@ pango_line_iter_get_layout_extents (PangoLineIter *iter, * Extents are in layout coordinates (origin is the top-left corner of the * entire `PangoLines`). Thus the extents returned by this function will be * the same width/height but not at the same x/y as the extents returned - * from [method@Pango.Line.get_extents]. + * from [method@Pango.LayoutLine.get_extents]. * * The logical extents returned by this function always have their leading * trimmed according to paragraph boundaries: if the line starts a paragraph, * it has its start leading trimmed; if it ends a paragraph, it has its end * leading trimmed. If you need other trimming, use - * [method@Pango.Line.get_trimmed_extents]. + * [method@Pango.LayoutLine.get_trimmed_extents]. */ void -pango_line_iter_get_line_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_iter_get_line_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { g_return_if_fail (ITER_IS_VALID (iter)); - pango_line_get_extents (iter->line, ink_rect, logical_rect); + pango_layout_line_get_extents (iter->line, ink_rect, logical_rect); offset_line (iter, ink_rect, logical_rect); } void -pango_line_iter_get_trimmed_line_extents (PangoLineIter *iter, - PangoLeadingTrim trim, - PangoRectangle *logical_rect) +pango_layout_iter_get_trimmed_line_extents (PangoLayoutIter *iter, + PangoLeadingTrim trim, + PangoRectangle *logical_rect) { g_return_if_fail (ITER_IS_VALID (iter)); - pango_line_get_trimmed_extents (iter->line, trim, logical_rect); + pango_layout_line_get_trimmed_extents (iter->line, trim, logical_rect); offset_line (iter, NULL, logical_rect); } /** - * pango_line_iter_get_run_extents: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_run_extents: + * @iter: a `PangoLayoutIter` * @ink_rect: (out) (optional): rectangle to fill with ink extents * @logical_rect: (out) (optional): rectangle to fill with logical extents * @@ -680,9 +682,9 @@ pango_line_iter_get_trimmed_line_extents (PangoLineIter *iter, * [method@Pango.LayoutRun.get_extents]. */ void -pango_line_iter_get_run_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_iter_get_run_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { g_return_if_fail (ITER_IS_VALID (iter)); @@ -692,7 +694,7 @@ pango_line_iter_get_run_extents (PangoLineIter *iter, } else { - GSList *runs = pango_line_get_runs (iter->line); + GSList *runs = pango_layout_line_get_runs (iter->line); if (runs) { /* Virtual run at the end of a nonempty line */ @@ -709,7 +711,7 @@ pango_line_iter_get_run_extents (PangoLineIter *iter, /* Empty line */ PangoRectangle r; - pango_line_get_empty_extents (iter->line, PANGO_LEADING_TRIM_BOTH, &r); + pango_layout_line_get_empty_extents (iter->line, PANGO_LEADING_TRIM_BOTH, &r); if (ink_rect) *ink_rect = r; @@ -724,8 +726,8 @@ pango_line_iter_get_run_extents (PangoLineIter *iter, } /** - * pango_line_iter_get_cluster_extents: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_cluster_extents: + * @iter: a `PangoLayoutIter` * @ink_rect: (out) (optional): rectangle to fill with ink extents * @logical_rect: (out) (optional): rectangle to fill with logical extents * @@ -734,9 +736,9 @@ pango_line_iter_get_run_extents (PangoLineIter *iter, * Layout coordinates have the origin at the top left of the entire `PangoLines`. */ void -pango_line_iter_get_cluster_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { PangoGlyphItem *glyph_item; @@ -745,7 +747,7 @@ pango_line_iter_get_cluster_extents (PangoLineIter *iter, if (iter->run == NULL) { /* When on the NULL run, all extents are the same */ - pango_line_iter_get_run_extents (iter, ink_rect, logical_rect); + pango_layout_iter_get_run_extents (iter, ink_rect, logical_rect); return; } @@ -762,20 +764,20 @@ pango_line_iter_get_cluster_extents (PangoLineIter *iter, if (ink_rect) { ink_rect->x += iter->cluster_x + glyph_item->start_x_offset; - ink_rect->y -= iter->run->y_offset; + ink_rect->y -= glyph_item->y_offset; } if (logical_rect) { g_assert (logical_rect->width == iter->cluster_width); logical_rect->x += iter->cluster_x + glyph_item->start_x_offset; - logical_rect->y -= iter->run->y_offset; + logical_rect->y -= glyph_item->y_offset; } } /** - * pango_line_iter_get_char_extents: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_char_extents: + * @iter: a `PangoLayoutIter` * @logical_rect: (out caller-allocates): rectangle to fill with logical extents * * Gets the extents of the current character, in layout coordinates. @@ -786,8 +788,8 @@ pango_line_iter_get_cluster_extents (PangoLineIter *iter, * ink extents make sense only down to the level of clusters. */ void -pango_line_iter_get_char_extents (PangoLineIter *iter, - PangoRectangle *logical_rect) +pango_layout_iter_get_char_extents (PangoLayoutIter *iter, + PangoRectangle *logical_rect) { PangoRectangle cluster_rect; int x0, x1; @@ -797,7 +799,7 @@ pango_line_iter_get_char_extents (PangoLineIter *iter, if (logical_rect == NULL) return; - pango_line_iter_get_cluster_extents (iter, NULL, &cluster_rect); + pango_layout_iter_get_cluster_extents (iter, NULL, &cluster_rect); if (iter->run == NULL) { @@ -823,8 +825,8 @@ pango_line_iter_get_char_extents (PangoLineIter *iter, } /** - * pango_line_iter_get_line_baseline: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_line_baseline: + * @iter: a `PangoLayoutIter` * * Gets the Y position of the current line's baseline, in layout * coordinates. @@ -834,7 +836,7 @@ pango_line_iter_get_char_extents (PangoLineIter *iter, * Return value: baseline of current line */ int -pango_line_iter_get_line_baseline (PangoLineIter *iter) +pango_layout_iter_get_line_baseline (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), 0); @@ -842,8 +844,8 @@ pango_line_iter_get_line_baseline (PangoLineIter *iter) } /** - * pango_line_iter_get_run_baseline: - * @iter: a `PangoLineIter` + * pango_layout_iter_get_run_baseline: + * @iter: a `PangoLayoutIter` * * Gets the Y position of the current run's baseline, in layout * coordinates. @@ -854,14 +856,14 @@ pango_line_iter_get_line_baseline (PangoLineIter *iter) * example due to superscript or subscript positioning. */ int -pango_line_iter_get_run_baseline (PangoLineIter *iter) +pango_layout_iter_get_run_baseline (PangoLayoutIter *iter) { g_return_val_if_fail (ITER_IS_VALID (iter), 0); if (iter->run) - return pango_line_iter_get_line_baseline (iter) - pango_layout_run_get_glyph_item (iter->run)->y_offset; + return pango_layout_iter_get_line_baseline (iter) - pango_layout_run_get_glyph_item (iter->run)->y_offset; else - return pango_line_iter_get_line_baseline (iter); + return pango_layout_iter_get_line_baseline (iter); } /* }}} */ diff --git a/pango/pango-layout-iter.h b/pango/pango-layout-iter.h new file mode 100644 index 00000000..3f1b5964 --- /dev/null +++ b/pango/pango-layout-iter.h @@ -0,0 +1,84 @@ +#pragma once + +#include <glib-object.h> + +#include <pango/pango-types.h> +#include <pango/pango-lines.h> +#include <pango/pango-glyph-item.h> + +G_BEGIN_DECLS + +PANGO_AVAILABLE_IN_ALL +GType pango_layout_iter_get_type (void) G_GNUC_CONST; + +PANGO_AVAILABLE_IN_ALL +PangoLayoutIter * pango_layout_iter_copy (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_free (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +PangoLines * pango_layout_iter_get_lines (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +PangoLayoutLine * pango_layout_iter_get_line (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_iter_at_last_line (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +PangoLayoutRun * pango_layout_iter_get_run (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +int pango_layout_iter_get_index (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_iter_next_line (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_iter_next_run (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_iter_next_cluster (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_iter_next_char (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_layout_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_line_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_trimmed_line_extents + (PangoLayoutIter *iter, + PangoLeadingTrim trim, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_run_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +void pango_layout_iter_get_char_extents (PangoLayoutIter *iter, + PangoRectangle *logical_rect); + +PANGO_AVAILABLE_IN_ALL +int pango_layout_iter_get_line_baseline (PangoLayoutIter *iter); + +PANGO_AVAILABLE_IN_ALL +int pango_layout_iter_get_run_baseline (PangoLayoutIter *iter); + + +G_END_DECLS diff --git a/pango/pango-layout-line-private.h b/pango/pango-layout-line-private.h new file mode 100644 index 00000000..0132401f --- /dev/null +++ b/pango/pango-layout-line-private.h @@ -0,0 +1,67 @@ +#pragma once + +#include "pango-layout-line.h" +#include "pango-break.h" +#include "pango-attributes.h" +#include "pango-glyph-item.h" + +typedef struct _LineData LineData; +struct _LineData { + char *text; + int length; + int n_chars; + PangoDirection direction; + + PangoAttrList *attrs; + PangoLogAttr *log_attrs; +}; + +LineData * line_data_new (void); +LineData * line_data_ref (LineData *data); +void line_data_unref (LineData *data); +void line_data_clear (LineData *data); + +struct _PangoLayoutLine +{ + GObject parent_instance; + + PangoContext *context; + LineData *data; + + int start_index; + int length; + int start_offset; + int n_chars; + GSList *runs; + + guint wrapped : 1; + guint ellipsized : 1; + guint hyphenated : 1; + guint justified : 1; + guint starts_paragraph : 1; + guint ends_paragraph : 1; + guint has_extents : 1; + + PangoDirection direction; + + PangoRectangle ink_rect; + PangoRectangle logical_rect; +}; + +PangoLayoutLine * pango_layout_line_new (PangoContext *context, + LineData *data); + +void pango_layout_line_ellipsize (PangoLayoutLine *line, + PangoContext *context, + PangoEllipsizeMode ellipsize, + int goal_width); + +void pango_layout_line_index_to_run (PangoLayoutLine *line, + int idx, + PangoLayoutRun **run); + +void pango_layout_line_get_empty_extents (PangoLayoutLine *line, + PangoLeadingTrim trim, + PangoRectangle *logical_rect); + +void pango_layout_line_check_invariants (PangoLayoutLine *line); diff --git a/pango/pango-line.c b/pango/pango-layout-line.c index c2fa3535..eb9f79c8 100644 --- a/pango/pango-line.c +++ b/pango/pango-layout-line.c @@ -1,6 +1,6 @@ #include "config.h" -#include "pango-line-private.h" +#include "pango-layout-line-private.h" #include "pango-tabs.h" #include "pango-impl-utils.h" @@ -40,39 +40,39 @@ line_data_unref (LineData *data) } /* }}} */ -/* {{{ PangoLine implementation */ +/* {{{ PangoLayoutLine implementation */ -struct _PangoLineClass +struct _PangoLayoutLineClass { GObjectClass parent_class; }; -G_DEFINE_TYPE (PangoLine, pango_line, G_TYPE_OBJECT) +G_DEFINE_TYPE (PangoLayoutLine, pango_layout_line, G_TYPE_OBJECT) static void -pango_line_init (PangoLine *line) +pango_layout_line_init (PangoLayoutLine *line) { } static void -pango_line_finalize (GObject *object) +pango_layout_line_finalize (GObject *object) { - PangoLine *line = PANGO_LINE (object); + PangoLayoutLine *line = PANGO_LAYOUT_LINE (object); g_object_unref (line->context); line_data_unref (line->data); g_slist_free_full (line->runs, (GDestroyNotify)pango_glyph_item_free); - G_OBJECT_CLASS (pango_line_parent_class)->finalize (object); + G_OBJECT_CLASS (pango_layout_line_parent_class)->finalize (object); } static void -pango_line_class_init (PangoLineClass *class) +pango_layout_line_class_init (PangoLayoutLineClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - object_class->finalize = pango_line_finalize; + object_class->finalize = pango_layout_line_finalize; } /* }}} */ @@ -92,7 +92,7 @@ distribute_letter_spacing (int letter_spacing, } static int -pango_line_compute_width (PangoLine *line) +pango_layout_line_compute_width (PangoLayoutLine *line) { int width = 0; @@ -109,8 +109,8 @@ pango_line_compute_width (PangoLine *line) } static void -justify_clusters (PangoLine *line, - int *remaining_width) +justify_clusters (PangoLayoutLine *line, + int *remaining_width) { int total_remaining_width, total_gaps = 0; int added_so_far, gaps_so_far; @@ -250,8 +250,8 @@ justify_clusters (PangoLine *line, } static void -justify_words (PangoLine *line, - int *remaining_width) +justify_words (PangoLayoutLine *line, + int *remaining_width) { int total_remaining_width, total_space_width = 0; int added_so_far, spaces_so_far; @@ -341,7 +341,7 @@ justify_words (PangoLine *line, /* {{{ Extents */ static void -compute_extents (PangoLine *line, +compute_extents (PangoLayoutLine *line, PangoLeadingTrim trim, PangoRectangle *ink, PangoRectangle *logical) @@ -351,7 +351,7 @@ compute_extents (PangoLine *line, if (!line->runs) { memset (ink, 0, sizeof (PangoRectangle)); - pango_line_get_empty_extents (line, trim, logical); + pango_layout_line_get_empty_extents (line, trim, logical); return; } @@ -408,7 +408,7 @@ compute_extents (PangoLine *line, /* {{{ Private API */ void -pango_line_check_invariants (PangoLine *line) +pango_layout_line_check_invariants (PangoLayoutLine *line) { /* Check that byte and char positions agree */ g_assert (g_utf8_strlen (line->data->text + line->start_index, line->length) == line->n_chars); @@ -439,9 +439,9 @@ pango_line_check_invariants (PangoLine *line) } void -pango_line_get_empty_extents (PangoLine *line, - PangoLeadingTrim trim, - PangoRectangle *logical_rect) +pango_layout_line_get_empty_extents (PangoLayoutLine *line, + PangoLeadingTrim trim, + PangoRectangle *logical_rect) { PangoFontDescription *font_desc = NULL; gboolean free_font_desc = FALSE; @@ -539,25 +539,25 @@ pango_line_get_empty_extents (PangoLine *line, } /*< private > - * pango_line_new: + * pango_layout_line_new: * @context: the `PangoContext` * @data: the `LineData` * - * Creates a new `PangoLine`. + * Creates a new `PangoLayoutLine`. * * The line shares the immutable `LineData` with other lines. * * The @context is needed for shape rendering. * - * Returns: new `PangoLine` + * Returns: new `PangoLayoutLine` */ -PangoLine * -pango_line_new (PangoContext *context, - LineData *data) +PangoLayoutLine * +pango_layout_line_new (PangoContext *context, + LineData *data) { - PangoLine *line; + PangoLayoutLine *line; - line = g_object_new (PANGO_TYPE_LINE, NULL); + line = g_object_new (PANGO_TYPE_LAYOUT_LINE, NULL); line->context = g_object_ref (context); line->data = line_data_ref (data); @@ -566,17 +566,17 @@ pango_line_new (PangoContext *context, } /*< private > - * pango_line_index_to_run: - * @line: a `PangoLine` + * pango_layout_line_index_to_run: + * @line: a `PangoLayoutLine` * @idx: a byte offset in the line * @run: (out): return location for the run * * Finds the run in @line which contains @idx. */ void -pango_line_index_to_run (PangoLine *line, - int idx, - PangoLayoutRun **run) +pango_layout_line_index_to_run (PangoLayoutLine *line, + int idx, + PangoLayoutRun **run) { *run = NULL; @@ -599,8 +599,8 @@ pango_line_index_to_run (PangoLine *line, /* {{{ Simple getters */ /** - * pango_line_get_runs: - * @line: a `PangoLine` + * pango_layout_line_get_runs: + * @line: a `PangoLayoutLine` * * Gets the runs of the line. * @@ -610,22 +610,22 @@ pango_line_index_to_run (PangoLine *line, * Returns: (transfer none) (element-type PangoGlyphItem): a list of `PangoGlyphItem` */ GSList * -pango_line_get_runs (PangoLine *line) +pango_layout_line_get_runs (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), NULL); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), NULL); return line->runs; } /** - * pango_line_get_text: - * @line: a `PangoLine` + * pango_layout_line_get_text: + * @line: a `PangoLayoutLine` * @start_index: the byte index of the first byte of @line * @length: the number of bytes in @line * * Gets the text that @line presents. * - * The `PangoLine` represents the slice from @start_index + * The `PangoLayoutLine` represents the slice from @start_index * to @start_index + @length of the returned string. * * The returned string is owned by @line and must not @@ -634,11 +634,11 @@ pango_line_get_runs (PangoLine *line) * Returns: the text */ const char * -pango_line_get_text (PangoLine *line, - int *start_index, - int *length) +pango_layout_line_get_text (PangoLayoutLine *line, + int *start_index, + int *length) { - g_return_val_if_fail (PANGO_IS_LINE (line), NULL); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), NULL); g_return_val_if_fail (start_index != NULL, NULL); g_return_val_if_fail (length != NULL, NULL); @@ -649,8 +649,8 @@ pango_line_get_text (PangoLine *line, } /** - * pango_line_get_start_index: - * @line: a `PangoLine` + * pango_layout_line_get_start_index: + * @line: a `PangoLayoutLine` * * Returns the start index of the line, as byte index * into the text of the layout. @@ -658,32 +658,32 @@ pango_line_get_text (PangoLine *line, * Returns: the start index of the line */ int -pango_line_get_start_index (PangoLine *line) +pango_layout_line_get_start_index (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), 0); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), 0); return line->start_index; } /** - * pango_line_get_length: - * @line: a `PangoLine` + * pango_layout_line_get_length: + * @line: a `PangoLayoutLine` * * Returns the length of the line, in bytes. * * Returns: the length of the line */ int -pango_line_get_length (PangoLine *line) +pango_layout_line_get_length (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), 0); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), 0); return line->length; } /** - * pango_line_get_log_attrs: - * @line: a `PangoLine` + * pango_layout_line_get_log_attrs: + * @line: a `PangoLayoutLine` * @start_offset: the character offset of the first character of @line * @n_attrs: the number of attributes that apply to @line * @@ -698,11 +698,11 @@ pango_line_get_length (PangoLine *line) * Returns: the `PangoLogAttr` array */ const PangoLogAttr * -pango_line_get_log_attrs (PangoLine *line, - int *start_offset, - int *n_attrs) +pango_layout_line_get_log_attrs (PangoLayoutLine *line, + int *start_offset, + int *n_attrs) { - g_return_val_if_fail (PANGO_IS_LINE (line), NULL); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), NULL); g_return_val_if_fail (start_offset != NULL, NULL); g_return_val_if_fail (n_attrs != NULL, NULL); @@ -713,115 +713,115 @@ pango_line_get_log_attrs (PangoLine *line, } /** - * pango_line_wrapped: - * @line: a `PangoLine` + * pango_layout_line_wrapped: + * @line: a `PangoLayoutLine` * * Gets whether the line is wrapped. * * Returns: `TRUE` if @line has been wrapped */ gboolean -pango_line_wrapped (PangoLine *line) +pango_layout_line_wrapped (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->wrapped; } /** - * pango_line_ellipsized: - * @line: a `PangoLine` + * pango_layout_line_ellipsized: + * @line: a `PangoLayoutLine` * * Gets whether the line is ellipsized. * * Returns: `TRUE` if @line has been ellipsized */ gboolean -pango_line_ellipsized (PangoLine *line) +pango_layout_line_ellipsized (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->ellipsized; } /** - * pango_line_hyphenated: - * @line: a `PangoLine` + * pango_layout_line_hyphenated: + * @line: a `PangoLayoutLine` * * Gets whether the line is hyphenated. * * Returns: `TRUE` if @line has been hyphenated */ gboolean -pango_line_hyphenated (PangoLine *line) +pango_layout_line_hyphenated (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->hyphenated; } /** - * pango_line_justified: - * @line: a `PangoLine` + * pango_layout_line_justified: + * @line: a `PangoLayoutLine` * * Gets whether the line is justified. * - * See [method@Pango.Line.justify]. + * See [method@Pango.LayoutLine.justify]. * * Returns: `TRUE` if @line has been justified */ gboolean -pango_line_justified (PangoLine *line) +pango_layout_line_justified (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->justified; } /** - * pango_line_starts_paragraph: - * @line: a `PangoLine` + * pango_layout_line_starts_paragraph: + * @line: a `PangoLayoutLine` * * Gets whether the line is the first of a paragraph. * * Returns: `TRUE` if @line starts a paragraph */ gboolean -pango_line_starts_paragraph (PangoLine *line) +pango_layout_line_starts_paragraph (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->starts_paragraph; } /** - * pango_line_ends_paragraph: - * @line: a `PangoLine` + * pango_layout_line_ends_paragraph: + * @line: a `PangoLayoutLine` * * Gets whether the line is the last of a paragraph. * * Returns: `TRUE` if @line ends a paragraph */ gboolean -pango_line_ends_paragraph (PangoLine *line) +pango_layout_line_ends_paragraph (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), FALSE); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), FALSE); return line->ends_paragraph; } /** - * pango_line_get_resolved_direction: - * @line: a `PangoLine` + * pango_layout_line_get_resolved_direction: + * @line: a `PangoLayoutLine` * * Gets the resolved direction of the line. * * Returns: the resolved direction of @line */ PangoDirection -pango_line_get_resolved_direction (PangoLine *line) +pango_layout_line_get_resolved_direction (PangoLayoutLine *line) { - g_return_val_if_fail (PANGO_IS_LINE (line), PANGO_DIRECTION_LTR); + g_return_val_if_fail (PANGO_IS_LAYOUT_LINE (line), PANGO_DIRECTION_LTR); return line->direction; } @@ -830,11 +830,11 @@ pango_line_get_resolved_direction (PangoLine *line) /* {{{ Justification */ /** - * pango_line_justify: - * @line: (transfer full): a `PangoLine` + * pango_layout_line_justify: + * @line: (transfer full): a `PangoLayoutLine` * @width: the width to justify @line to * - * Creates a new `PangoLine` that is justified + * Creates a new `PangoLayoutLine` that is justified * copy of @line. * * The content of the returned line is justified @@ -843,20 +843,20 @@ pango_line_get_resolved_direction (PangoLine *line) * * Note that this function consumes @line. * - * Returns: (transfer full): a new `PangoLine` + * Returns: (transfer full): a new `PangoLayoutLine` */ -PangoLine * -pango_line_justify (PangoLine *line, - int width) +PangoLayoutLine * +pango_layout_line_justify (PangoLayoutLine *line, + int width) { int remaining_width; - PangoLine *copy; + PangoLayoutLine *copy; - remaining_width = width - pango_line_compute_width (line); + remaining_width = width - pango_layout_line_compute_width (line); if (remaining_width <= 0) return line; - copy = pango_line_new (line->context, line->data); + copy = pango_layout_line_new (line->context, line->data); copy->start_index = line->start_index; copy->length = line->length; copy->start_offset = line->start_offset; @@ -890,8 +890,8 @@ pango_line_justify (PangoLine *line, /* {{{ Extents */ /** - * pango_line_get_extents: - * @line: a `PangoLine` + * pango_layout_line_get_extents: + * @line: a `PangoLayoutLine` * @ink_rect: (out) (optional): rectangle that will be filled with ink extents * @logical_rect: (out) (optional): rectangle that will be filled with the logical extents * @@ -901,14 +901,14 @@ pango_line_justify (PangoLine *line, * trimmed according to paragraph boundaries: if the line starts a paragraph, * it has its start leading trimmed; if it ends a paragraph, it has its end * leading trimmed. If you need other trimming, use - * [method@Pango.Line.get_trimmed_extents]. + * [method@Pango.LayoutLine.get_trimmed_extents]. * * Note that the origin is at the left end of the baseline. */ void -pango_line_get_extents (PangoLine *line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_line_get_extents (PangoLayoutLine *line, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) { PangoRectangle ink = { 0, }; PangoRectangle logical = { 0, }; @@ -936,8 +936,8 @@ cached: } /** - * pango_line_get_trimmed_extents: - * @line: a `PangoLine` + * pango_layout_line_get_trimmed_extents: + * @line: a `PangoLayoutLine` * @trim: `PangoLeadingTrim` flags * @logical_rect: (out): rectangle that will be filled with the logical extents * @@ -951,9 +951,9 @@ cached: * Note that the origin is at the left end of the baseline. */ void -pango_line_get_trimmed_extents (PangoLine *line, - PangoLeadingTrim trim, - PangoRectangle *logical_rect) +pango_layout_line_get_trimmed_extents (PangoLayoutLine *line, + PangoLeadingTrim trim, + PangoRectangle *logical_rect) { PangoRectangle ink = { 0, }; PangoLeadingTrim cached_trim = PANGO_LEADING_TRIM_NONE; @@ -976,12 +976,12 @@ pango_line_get_trimmed_extents (PangoLine *line, /* {{{ Editing API */ /** - * pango_line_layout_index_to_pos: - * @line: a `PangoLine` + * pango_layout_line_layout_index_to_pos: + * @line: a `PangoLayoutLine` * @idx: byte index within @line * @pos: (out): rectangle in which to store the position of the grapheme * - * Converts from an index within a `PangoLine` to the + * Converts from an index within a `PangoLayoutLine` to the * position corresponding to the grapheme at that index. * * The return value is represented as rectangle. Note that `pos->x` is @@ -992,16 +992,16 @@ pango_line_get_trimmed_extents (PangoLine *line, * Note that @idx is allowed to be @line->start_index + @line->length. */ void -pango_line_index_to_pos (PangoLine *line, - int idx, - PangoRectangle *pos) +pango_layout_line_index_to_pos (PangoLayoutLine *line, + int idx, + PangoRectangle *pos) { PangoRectangle run_logical; PangoRectangle line_logical; PangoLayoutRun *run = NULL; int x_pos; - pango_line_get_extents (line, NULL, &line_logical); + pango_layout_line_get_extents (line, NULL, &line_logical); if (!line->runs) { @@ -1012,7 +1012,7 @@ pango_line_index_to_pos (PangoLine *line, if (idx == line->start_index + line->length) run = g_slist_last (line->runs)->data; else - pango_line_index_to_run (line, idx, &run); + pango_layout_line_index_to_run (line, idx, &run); pango_layout_run_get_extents (run, PANGO_LEADING_TRIM_BOTH, NULL, &run_logical); @@ -1021,12 +1021,12 @@ pango_line_index_to_pos (PangoLine *line, /* FIXME: avoid iterating through the runs multiple times */ - pango_line_index_to_x (line, idx, 0, &x_pos); + pango_layout_line_index_to_x (line, idx, 0, &x_pos); pos->x = line_logical.x + x_pos; if (idx < line->start_index + line->length) { - pango_line_index_to_x (line, idx, 1, &x_pos); + pango_layout_line_index_to_x (line, idx, 1, &x_pos); pos->width = (line_logical.x + x_pos) - pos->x; } else @@ -1034,23 +1034,23 @@ pango_line_index_to_pos (PangoLine *line, } /** - * pango_line_index_to_x: - * @line: a `PangoLine` + * pango_layout_line_index_to_x: + * @line: a `PangoLayoutLine` * @idx: byte index within @line * @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: (out): location to store the x_offset (in Pango units) * - * Converts an index within a `PangoLine` to a X position. + * Converts an index within a `PangoLayoutLine` to a X position. * * Note that @idx is allowed to be @line->start_index + @line->length. */ void -pango_line_index_to_x (PangoLine *line, - int index, - int trailing, - int *x_pos) +pango_layout_line_index_to_x (PangoLayoutLine *line, + int index, + int trailing, + int *x_pos) { GSList *run_list = line->runs; int width = 0; @@ -1111,8 +1111,8 @@ pango_line_index_to_x (PangoLine *line, } /** - * pango_line_x_to_index: - * @line: a `PangoLine` + * pango_layout_line_x_to_index: + * @line: a `PangoLayoutLine` * @x: the X offset (in Pango units) from the left edge of the line * @idx: (out): location to store calculated byte index for the grapheme * in which the user clicked @@ -1135,10 +1135,10 @@ pango_line_index_to_x (PangoLine *line, * Return value: %FALSE if @x_pos was outside the line, %TRUE if inside */ gboolean -pango_line_x_to_index (PangoLine *line, - int x_pos, - int *index, - int *trailing) +pango_layout_line_x_to_index (PangoLayoutLine *line, + int x_pos, + int *index, + int *trailing) { GSList *tmp_list; gint start_pos = 0; @@ -1304,8 +1304,8 @@ pango_line_x_to_index (PangoLine *line, /* {{{ Cursor positioning */ /** - * pango_line_get_cursor_pos: - * @line: a `PangoLine` + * pango_layout_line_get_cursor_pos: + * @line: a `PangoLayoutLine` * @idx: the byte index of the cursor * @strong_pos: (out) (optional): location to store the strong cursor position * @weak_pos: (out) (optional): location to store the weak cursor position @@ -1341,10 +1341,10 @@ pango_line_x_to_index (PangoLine *line, * will insert it at the end. */ void -pango_line_get_cursor_pos (PangoLine *line, - int idx, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) +pango_layout_line_get_cursor_pos (PangoLayoutLine *line, + int idx, + PangoRectangle *strong_pos, + PangoRectangle *weak_pos) { PangoRectangle line_rect = { 666, }; PangoRectangle run_rect = { 666, }; @@ -1360,9 +1360,9 @@ pango_line_get_cursor_pos (PangoLine *line, run = g_slist_last (line->runs)->data; } else - pango_line_index_to_run (line, idx, &run); + pango_layout_line_index_to_run (line, idx, &run); - pango_line_get_extents (line, NULL, &line_rect); + pango_layout_line_get_extents (line, NULL, &line_rect); if (run) pango_layout_run_get_extents (run, PANGO_LEADING_TRIM_BOTH, NULL, &run_rect); else @@ -1396,10 +1396,10 @@ pango_line_get_cursor_pos (PangoLine *line, { PangoLayoutRun *prev_run; - pango_line_index_to_run (line, prev_index, &prev_run); + pango_layout_line_index_to_run (line, prev_index, &prev_run); level1 = pango_layout_run_get_glyph_item (prev_run)->item->analysis.level; dir1 = level1 % 2 ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; - pango_line_index_to_x (line, prev_index, TRUE, &x1_trailing); + pango_layout_line_index_to_x (line, prev_index, TRUE, &x1_trailing); } } @@ -1415,7 +1415,7 @@ pango_line_get_cursor_pos (PangoLine *line, } else { - pango_line_index_to_x (line, idx, FALSE, &x2); + pango_layout_line_index_to_x (line, idx, FALSE, &x2); level2 = pango_layout_run_get_glyph_item (run)->item->analysis.level; dir2 = level2 % 2 ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; } @@ -1453,8 +1453,8 @@ done: } /** - * pango_line_get_caret_pos: - * @line: a `PangoLine` + * pango_layout_line_get_caret_pos: + * @line: a `PangoLayoutLine` * @idx: the byte index of the cursor * @strong_pos: (out) (optional): location to store the strong cursor position * @weak_pos: (out) (optional): location to store the weak cursor position @@ -1464,7 +1464,7 @@ done: * * Note that @idx is allowed to be @line->start_index + @line->length. * - * This is a variant of [method@Pango.Line.get_cursor_pos] that applies + * This is a variant of [method@Pango.LayoutLine.get_cursor_pos] that applies * font metric information about caret slope and offset to the positions * it returns. * @@ -1474,17 +1474,17 @@ done: * </picture> */ void -pango_line_get_caret_pos (PangoLine *line, - int idx, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) +pango_layout_line_get_caret_pos (PangoLayoutLine *line, + int idx, + PangoRectangle *strong_pos, + PangoRectangle *weak_pos) { PangoLayoutRun *run = NULL; PangoGlyphItem *glyph_item; hb_font_t *hb_font; hb_position_t caret_offset, caret_run, caret_rise, descender; - pango_line_get_cursor_pos (line, idx, strong_pos, weak_pos); + pango_layout_line_get_cursor_pos (line, idx, strong_pos, weak_pos); if (idx >= line->start_index + line->length) { @@ -1492,7 +1492,7 @@ pango_line_get_caret_pos (PangoLine *line, run = g_slist_last (line->runs)->data; } else - pango_line_index_to_run (line, idx, &run); + pango_layout_line_index_to_run (line, idx, &run); if (!run) return; diff --git a/pango/pango-line.h b/pango/pango-layout-line.h index d788e66f..773d2b75 100644 --- a/pango/pango-line.h +++ b/pango/pango-layout-line.h @@ -7,93 +7,95 @@ G_BEGIN_DECLS -typedef PangoGlyphItem PangoLayoutRun; - -#define PANGO_TYPE_LINE pango_line_get_type () +#define PANGO_TYPE_LAYOUT_LINE pango_layout_line_get_type () PANGO_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (PangoLine, pango_line, PANGO, LINE, GObject); +G_DECLARE_FINAL_TYPE (PangoLayoutLine, pango_layout_line, PANGO, LAYOUT_LINE, GObject); PANGO_AVAILABLE_IN_ALL -PangoLine * pango_line_justify (PangoLine *line, +PangoLayoutLine * pango_layout_line_justify (PangoLayoutLine *line, int width); PANGO_AVAILABLE_IN_ALL -GSList * pango_line_get_runs (PangoLine *line); +GSList * pango_layout_line_get_runs (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -const char * pango_line_get_text (PangoLine *line, +const char * pango_layout_line_get_text (PangoLayoutLine *line, int *start_index, int *length); PANGO_AVAILABLE_IN_ALL -int pango_line_get_start_index (PangoLine *line); +int pango_layout_line_get_start_index (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -int pango_line_get_length (PangoLine *line); +int pango_layout_line_get_length (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -const PangoLogAttr * pango_line_get_log_attrs (PangoLine *line, +const PangoLogAttr * pango_layout_line_get_log_attrs (PangoLayoutLine *line, int *start_offset, int *n_attrs); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_wrapped (PangoLine *line); +gboolean pango_layout_line_wrapped (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_ellipsized (PangoLine *line); +gboolean pango_layout_line_ellipsized (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_hyphenated (PangoLine *line); +gboolean pango_layout_line_hyphenated (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_justified (PangoLine *line); +gboolean pango_layout_line_justified (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_starts_paragraph (PangoLine *line); +gboolean pango_layout_line_starts_paragraph + (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_ends_paragraph (PangoLine *line); +gboolean pango_layout_line_ends_paragraph + (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -PangoDirection pango_line_get_resolved_direction - (PangoLine *line); +PangoDirection pango_layout_line_get_resolved_direction + (PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -void pango_line_get_extents (PangoLine *line, +void pango_layout_line_get_extents (PangoLayoutLine *line, PangoRectangle *ink_rect, PangoRectangle *logical_rect); PANGO_AVAILABLE_IN_ALL -void pango_line_get_trimmed_extents (PangoLine *line, +void pango_layout_line_get_trimmed_extents + (PangoLayoutLine *line, PangoLeadingTrim trim, PangoRectangle *logical_rect); PANGO_AVAILABLE_IN_ALL -void pango_line_index_to_pos (PangoLine *line, +void pango_layout_line_index_to_pos (PangoLayoutLine *line, int idx, PangoRectangle *pos); PANGO_AVAILABLE_IN_ALL -void pango_line_index_to_x (PangoLine *line, +void pango_layout_line_index_to_x (PangoLayoutLine *line, int idx, int trailing, int *x_pos); PANGO_AVAILABLE_IN_ALL -gboolean pango_line_x_to_index (PangoLine *line, +gboolean pango_layout_line_x_to_index (PangoLayoutLine *line, int x, int *idx, int *trailing); PANGO_AVAILABLE_IN_ALL -void pango_line_get_cursor_pos (PangoLine *line, +void pango_layout_line_get_cursor_pos + (PangoLayoutLine *line, int idx, PangoRectangle *strong_pos, PangoRectangle *weak_pos); PANGO_AVAILABLE_IN_ALL -void pango_line_get_caret_pos (PangoLine *line, +void pango_layout_line_get_caret_pos (PangoLayoutLine *line, int idx, PangoRectangle *strong_pos, PangoRectangle *weak_pos); diff --git a/pango/pango-layout-private.h b/pango/pango-layout-private.h deleted file mode 100644 index 74c36126..00000000 --- a/pango/pango-layout-private.h +++ /dev/null @@ -1,160 +0,0 @@ -/* Pango - * pango-layout-private.h: Internal structures of PangoLayout - * - * Copyright (C) 2004 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __PANGO_LAYOUT_PRIVATE_H__ -#define __PANGO_LAYOUT_PRIVATE_H__ - -#include <pango/pango-layout.h> - -G_BEGIN_DECLS - -struct _PangoLayout -{ - GObject parent_instance; - - /* If you add fields to PangoLayout be sure to update _copy() - * unless you add a value between copy_begin and copy_end. - */ - - /* Referenced items */ - PangoContext *context; - PangoAttrList *attrs; - PangoFontDescription *font_desc; - PangoTabArray *tabs; - - /* Dupped */ - gchar *text; - - /* Value fields. These will be memcpy'd in _copy() */ - int copy_begin; - - guint serial; - guint context_serial; - - int length; /* length of text in bytes */ - int n_chars; /* number of characters in layout */ - int width; /* wrap/ellipsize width, in device units, or -1 if not set */ - int height; /* ellipsize width, in device units if positive, number of lines if negative */ - int indent; /* amount by which first line should be shorter */ - int spacing; /* spacing between lines */ - float line_spacing; /* factor to apply to line height */ - - guint justify : 1; - guint justify_last_line : 1; - guint alignment : 2; - guint single_paragraph : 1; - guint auto_dir : 1; - guint wrap : 2; /* PangoWrapMode */ - guint is_wrapped : 1; /* Whether the layout has any wrapped lines */ - guint ellipsize : 2; /* PangoEllipsizeMode */ - guint is_ellipsized : 1; /* Whether the layout has any ellipsized lines */ - int unknown_glyphs_count; /* number of unknown glyphs */ - - /* some caching */ - guint logical_rect_cached : 1; - guint ink_rect_cached : 1; - PangoRectangle logical_rect; - PangoRectangle ink_rect; - int tab_width; /* Cached width of a tab. -1 == not yet calculated */ - gunichar decimal; - - int copy_end; - - /* Not copied during _copy() */ - - PangoLogAttr *log_attrs; /* Logical attributes for layout's text */ - GSList *lines; - guint line_count; /* Number of lines in @lines. 0 if lines is %NULL */ -}; - -typedef struct _Extents Extents; -struct _Extents -{ - /* Vertical position of the line's baseline in layout coords */ - int baseline; - - /* Line extents in layout coords */ - PangoRectangle ink_rect; - PangoRectangle logical_rect; -}; - -struct _PangoLayoutIter -{ - PangoLayout *layout; - GSList *line_list_link; - PangoLayoutLine *line; - - /* If run is NULL, it means we're on a "virtual run" - * at the end of the line with 0 width - */ - GSList *run_list_link; - PangoLayoutRun *run; /* FIXME nuke this, just keep the link */ - int index; - - /* list of Extents for each line in layout coordinates */ - Extents *line_extents; - int line_index; - - /* Position of the current run */ - int run_x; - - /* Width and end offset of the current run */ - int run_width; - int end_x_offset; - - /* this run is left-to-right */ - gboolean ltr; - - /* X position of the left side of the current cluster */ - int cluster_x; - - /* The width of the current cluster */ - int cluster_width; - - /* glyph offset to the current cluster start */ - int cluster_start; - - /* first glyph in the next cluster */ - int next_cluster_glyph; - - /* number of Unicode chars in current cluster */ - int cluster_num_chars; - - /* visual position of current character within the cluster */ - int character_position; - - /* the real width of layout */ - int layout_width; -}; - -gboolean _pango_layout_line_ellipsize (PangoLayoutLine *line, - PangoAttrList *attrs, - PangoShapeFlags shape_flags, - int goal_width); - -void _pango_layout_get_iter (PangoLayout *layout, - PangoLayoutIter *iter); - -void _pango_layout_iter_destroy (PangoLayoutIter *iter); - -G_END_DECLS - -#endif /* __PANGO_LAYOUT_PRIVATE_H__ */ diff --git a/pango/pango-layout-run.h b/pango/pango-layout-run.h index b9201071..a2b76cc0 100644 --- a/pango/pango-layout-run.h +++ b/pango/pango-layout-run.h @@ -4,8 +4,6 @@ #include <pango/pango-types.h> #include <pango/pango-item.h> #include <pango/pango-glyph.h> -#include <pango/pango-layout.h> - PANGO_AVAILABLE_IN_ALL PangoItem * pango_layout_run_get_item (PangoLayoutRun *run); diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 0bd62cef..9671ab61 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -1,177 +1,66 @@ -/* Pango - * pango-layout.c: High-level layout driver - * - * Copyright (C) 2000, 2001, 2006 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * PangoLayout: - * - * A `PangoLayout` structure represents an entire paragraph of text. - * - * While complete access to the layout capabilities of Pango is provided - * using the detailed interfaces for itemization and shaping, using - * that functionality directly involves writing a fairly large amount - * of code. `PangoLayout` provides a high-level driver for formatting - * entire paragraphs of text at once. This includes paragraph-level - * functionality such as line breaking, justification, alignment and - * ellipsization. - * - * A `PangoLayout` is initialized with a `PangoContext`, UTF-8 string - * and set of attributes for that string. Once that is done, the set of - * formatted lines can be extracted from the object, the layout can be - * rendered, and conversion between logical character positions within - * the layout's text, and the physical position of the resulting glyphs - * can be made. - * - * There are a number of parameters to adjust the formatting of a - * `PangoLayout`. The following image shows adjustable parameters - * (on the left) and font metrics (on the right): - * - * <picture> - * <source srcset="layout-dark.png" media="(prefers-color-scheme: dark)"> - * <img alt="Pango Layout Parameters" src="layout-light.png"> - * </picture> - * - * The following images demonstrate the effect of alignment and - * justification on the layout of text: - * - * | | | - * | --- | --- | - * | ![align=left](align-left.png) | ![align=left, justify](align-left-justify.png) | - * | ![align=center](align-center.png) | ![align=center, justify](align-center-justify.png) | - * | ![align=right](align-right.png) | ![align=right, justify](align-right-justify.png) | - * - * - * It is possible, as well, to ignore the 2-D setup, - * and simply treat the results of a `PangoLayout` as a list of lines. - */ - -/** - * PangoLayoutIter: - * - * A `PangoLayoutIter` can be used to iterate over the visual - * extents of a `PangoLayout`. - * - * To obtain a `PangoLayoutIter`, use [method@Pango.Layout.get_iter]. - * - * The `PangoLayoutIter` structure is opaque, and has no user-visible fields. - */ - #include "config.h" -#include "pango-glyph.h" /* For pango_shape() */ -#include "pango-break.h" -#include "pango-item-private.h" -#include "pango-engine.h" -#include "pango-impl-utils.h" -#include "pango-glyph-item.h" -#include <string.h> -#include <math.h> -#include <locale.h> - -#include <hb-ot.h> -#include "pango-layout-private.h" -#include "pango-attributes-private.h" -#include "pango-font-private.h" +#include "pango-layout.h" +#include "pango-line-breaker.h" +#include "pango-layout-line-private.h" +#include "pango-enum-types.h" +#include "pango-markup.h" +#include "pango-context.h" -typedef struct _ParaBreakState ParaBreakState; -typedef struct _LastTabState LastTabState; +/* {{{ PangoLayout implementation */ -typedef struct _PangoLayoutLinePrivate PangoLayoutLinePrivate; - -struct _PangoLayoutLinePrivate +struct _PangoLayout { - PangoLayoutLine line; - guint ref_count; + GObject parent_instance; - /* Extents cache status: - * - * LEAKED means that the user has access to this line structure or a - * run included in this line, and so can change the glyphs/glyph-widths. - * If this is true, extents caching will be disabled. - */ - enum { - NOT_CACHED, - CACHED, - LEAKED - } cache_status; - PangoRectangle ink_rect; - PangoRectangle logical_rect; + PangoContext *context; + char *text; + int length; + PangoAttrList *attrs; + PangoFontDescription *font_desc; + float line_spacing; + int width; int height; + PangoTabArray *tabs; + gboolean single_paragraph; + PangoWrapMode wrap; + int indent; + guint serial; + guint context_serial; + PangoAlignment alignment; + PangoEllipsizeMode ellipsize; + gboolean auto_dir; + + PangoLines *lines; }; struct _PangoLayoutClass { GObjectClass parent_class; - - }; -#define LINE_IS_VALID(line) ((line) && (line)->layout != NULL) - -#ifdef G_DISABLE_CHECKS -#define ITER_IS_INVALID(iter) FALSE -#else -#define ITER_IS_INVALID(iter) G_UNLIKELY (check_invalid ((iter), G_STRLOC)) -static gboolean -check_invalid (PangoLayoutIter *iter, - const char *loc) -{ - if (iter->line->layout == NULL) - { - g_warning ("%s: PangoLayout changed since PangoLayoutIter was created, iterator invalid", loc); - return TRUE; - } - else - { - return FALSE; - } -} -#endif - -static void check_context_changed (PangoLayout *layout); -static void layout_changed (PangoLayout *layout); - -static void pango_layout_clear_lines (PangoLayout *layout); -static void pango_layout_check_lines (PangoLayout *layout); - -static PangoAttrList *pango_layout_get_effective_attributes (PangoLayout *layout); - -static PangoLayoutLine * pango_layout_line_new (PangoLayout *layout); -static void pango_layout_line_postprocess (PangoLayoutLine *line, - ParaBreakState *state, - gboolean wrapped); - -static void pango_layout_line_leaked (PangoLayoutLine *line); - -/* doesn't leak line */ -static PangoLayoutLine * _pango_layout_iter_get_line (PangoLayoutIter *iter); -static PangoLayoutRun * _pango_layout_iter_get_run (PangoLayoutIter *iter); - -static void pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout, - int index, - PangoRectangle *logical_rect, - gboolean apply_line_height, - int *height); +enum +{ + PROP_CONTEXT = 1, + PROP_TEXT, + PROP_ATTRIBUTES, + PROP_FONT_DESCRIPTION, + PROP_LINE_SPACING, + PROP_WIDTH, + PROP_HEIGHT, + PROP_TABS, + PROP_SINGLE_PARAGRAPH, + PROP_WRAP, + PROP_INDENT, + PROP_ALIGNMENT, + PROP_ELLIPSIZE, + PROP_AUTO_DIR, + PROP_LINES, + NUM_PROPERTIES +}; -static void pango_layout_finalize (GObject *object); +static GParamSpec *props[NUM_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (PangoLayout, pango_layout, G_TYPE_OBJECT) @@ -179,1304 +68,684 @@ static void pango_layout_init (PangoLayout *layout) { layout->serial = 1; - layout->attrs = NULL; - layout->font_desc = NULL; - layout->text = NULL; - layout->length = 0; layout->width = -1; layout->height = -1; layout->indent = 0; - layout->spacing = 0; - layout->line_spacing = 0.0; - - layout->alignment = PANGO_ALIGN_LEFT; - layout->justify = FALSE; - layout->justify_last_line = FALSE; - layout->auto_dir = TRUE; - layout->single_paragraph = FALSE; - - layout->log_attrs = NULL; - layout->lines = NULL; - layout->line_count = 0; - - layout->tab_width = -1; - layout->decimal = 0; - layout->unknown_glyphs_count = -1; - layout->wrap = PANGO_WRAP_WORD; - layout->is_wrapped = FALSE; + layout->alignment = PANGO_ALIGN_LEFT; layout->ellipsize = PANGO_ELLIPSIZE_NONE; - layout->is_ellipsized = FALSE; -} - -static void -pango_layout_class_init (PangoLayoutClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = pango_layout_finalize; + layout->line_spacing = 0.0; + layout->auto_dir = TRUE; + layout->text = g_strdup (""); + layout->length = 0; } static void pango_layout_finalize (GObject *object) { - PangoLayout *layout; - - layout = PANGO_LAYOUT (object); - - pango_layout_clear_lines (layout); - g_free (layout->log_attrs); - - if (layout->context) - g_object_unref (layout->context); - - if (layout->attrs) - pango_attr_list_unref (layout->attrs); + PangoLayout *layout = PANGO_LAYOUT (object); + g_clear_pointer (&layout->font_desc, pango_font_description_free); + g_object_unref (layout->context); g_free (layout->text); - - if (layout->font_desc) - pango_font_description_free (layout->font_desc); - - if (layout->tabs) - pango_tab_array_free (layout->tabs); + g_clear_pointer (&layout->attrs, pango_attr_list_unref); + g_clear_pointer (&layout->tabs, pango_tab_array_free); + g_clear_object (&layout->lines); G_OBJECT_CLASS (pango_layout_parent_class)->finalize (object); } -/** - * pango_layout_new: - * @context: a `PangoContext` - * - * Create a new `PangoLayout` object with attributes initialized to - * default values for a particular `PangoContext`. - * - * Return value: the newly allocated `PangoLayout` - */ -PangoLayout * -pango_layout_new (PangoContext *context) +static void +pango_layout_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - PangoLayout *layout; + PangoLayout *layout = PANGO_LAYOUT (object); - g_return_val_if_fail (context != NULL, NULL); - - layout = g_object_new (PANGO_TYPE_LAYOUT, NULL); + switch (prop_id) + { + case PROP_CONTEXT: + layout->context = g_value_dup_object (value); + layout->context_serial = pango_context_get_serial (layout->context); + break; - layout->context = context; - layout->context_serial = pango_context_get_serial (context); - g_object_ref (context); + case PROP_TEXT: + pango_layout_set_text (layout, g_value_get_string (value), -1); + break; - return layout; -} + case PROP_ATTRIBUTES: + pango_layout_set_attributes (layout, g_value_get_boxed (value)); + break; -/** - * pango_layout_copy: - * @src: a `PangoLayout` - * - * Creates a deep copy-by-value of the layout. - * - * The attribute list, tab array, and text from the original layout - * are all copied by value. - * - * Return value: (transfer full): the newly allocated `PangoLayout` - */ -PangoLayout* -pango_layout_copy (PangoLayout *src) -{ - PangoLayout *layout; + case PROP_FONT_DESCRIPTION: + pango_layout_set_font_description (layout, g_value_get_boxed (value)); + break; - g_return_val_if_fail (PANGO_IS_LAYOUT (src), NULL); + case PROP_LINE_SPACING: + pango_layout_set_line_spacing (layout, g_value_get_float (value)); + break; - /* Copy referenced members */ + case PROP_WIDTH: + pango_layout_set_width (layout, g_value_get_int (value)); + break; - layout = pango_layout_new (src->context); - if (src->attrs) - layout->attrs = pango_attr_list_copy (src->attrs); - if (src->font_desc) - layout->font_desc = pango_font_description_copy (src->font_desc); - if (src->tabs) - layout->tabs = pango_tab_array_copy (src->tabs); + case PROP_HEIGHT: + pango_layout_set_height (layout, g_value_get_int (value)); + break; - /* Dupped */ - layout->text = g_strdup (src->text); + case PROP_TABS: + pango_layout_set_tabs (layout, g_value_get_boxed (value)); + break; - /* Value fields */ - memcpy (&layout->copy_begin, &src->copy_begin, - G_STRUCT_OFFSET (PangoLayout, copy_end) - G_STRUCT_OFFSET (PangoLayout, copy_begin)); + case PROP_SINGLE_PARAGRAPH: + pango_layout_set_single_paragraph (layout, g_value_get_boolean (value)); + break; - return layout; -} + case PROP_WRAP: + pango_layout_set_wrap (layout, g_value_get_enum (value)); + break; -/** - * pango_layout_get_context: - * @layout: a `PangoLayout` - * - * Retrieves the `PangoContext` used for this layout. - * - * Return value: (transfer none): the `PangoContext` for the layout - */ -PangoContext * -pango_layout_get_context (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, NULL); + case PROP_INDENT: + pango_layout_set_indent (layout, g_value_get_int (value)); + break; - return layout->context; -} + case PROP_ALIGNMENT: + pango_layout_set_alignment (layout, g_value_get_enum (value)); + break; -/** - * pango_layout_set_width: - * @layout: a `PangoLayout`. - * @width: the desired width in Pango units, or -1 to indicate that no - * wrapping or ellipsization should be performed. - * - * Sets the width to which the lines of the `PangoLayout` should wrap or - * ellipsized. - * - * The default value is -1: no width set. - */ -void -pango_layout_set_width (PangoLayout *layout, - int width) -{ - g_return_if_fail (layout != NULL); + case PROP_ELLIPSIZE: + pango_layout_set_ellipsize (layout, g_value_get_enum (value)); + break; - if (width < 0) - width = -1; + case PROP_AUTO_DIR: + pango_layout_set_auto_dir (layout, g_value_get_boolean (value)); + break; - if (width != layout->width) - { - layout->width = width; - layout_changed (layout); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } -/** - * pango_layout_get_width: - * @layout: a `PangoLayout` - * - * Gets the width to which the lines of the `PangoLayout` should wrap. - * - * Return value: the width in Pango units, or -1 if no width set. - */ -int -pango_layout_get_width (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, 0); - return layout->width; -} - -/** - * pango_layout_set_height: - * @layout: a `PangoLayout`. - * @height: the desired height of the layout in Pango units if positive, - * or desired number of lines if negative. - * - * Sets the height to which the `PangoLayout` should be ellipsized at. - * - * There are two different behaviors, based on whether @height is positive - * or negative. - * - * If @height is positive, it will be the maximum height of the layout. Only - * lines would be shown that would fit, and if there is any text omitted, - * an ellipsis added. At least one line is included in each paragraph regardless - * of how small the height value is. A value of zero will render exactly one - * line for the entire layout. - * - * If @height is negative, it will be the (negative of) maximum number of lines - * per paragraph. That is, the total number of lines shown may well be more than - * this value if the layout contains multiple paragraphs of text. - * The default value of -1 means that the first line of each paragraph is ellipsized. - * This behavior may be changed in the future to act per layout instead of per - * paragraph. File a bug against pango at - * [https://gitlab.gnome.org/gnome/pango](https://gitlab.gnome.org/gnome/pango) - * if your code relies on this behavior. - * - * Height setting only has effect if a positive width is set on - * @layout and ellipsization mode of @layout is not %PANGO_ELLIPSIZE_NONE. - * The behavior is undefined if a height other than -1 is set and - * ellipsization mode is set to %PANGO_ELLIPSIZE_NONE, and may change in the - * future. - * - * Since: 1.20 - */ -void -pango_layout_set_height (PangoLayout *layout, - int height) +static void +pango_layout_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - g_return_if_fail (layout != NULL); + PangoLayout *layout = PANGO_LAYOUT (object); - if (height != layout->height) + switch (prop_id) { - layout->height = height; - - /* Do not invalidate if the number of lines requested is - * larger than the total number of lines in layout. - * Bug 549003 - */ - if (layout->ellipsize != PANGO_ELLIPSIZE_NONE && - !(layout->lines && layout->is_ellipsized == FALSE && - height < 0 && layout->line_count <= (guint) -height)) - layout_changed (layout); - } -} - -/** - * pango_layout_get_height: - * @layout: a `PangoLayout` - * - * Gets the height of layout used for ellipsization. - * - * See [method@Pango.Layout.set_height] for details. - * - * Return value: the height, in Pango units if positive, - * or number of lines if negative. - * - * Since: 1.20 - */ -int -pango_layout_get_height (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, 0); - return layout->height; -} - -/** - * pango_layout_set_wrap: - * @layout: a `PangoLayout` - * @wrap: the wrap mode - * - * Sets the wrap mode. - * - * The wrap mode only has effect if a width is set on the layout - * with [method@Pango.Layout.set_width]. To turn off wrapping, - * set the width to -1. - * - * The default value is %PANGO_WRAP_WORD. - */ -void -pango_layout_set_wrap (PangoLayout *layout, - PangoWrapMode wrap) -{ - g_return_if_fail (PANGO_IS_LAYOUT (layout)); + case PROP_CONTEXT: + g_value_set_object (value, layout->context); + break; - if (layout->wrap != wrap) - { - layout->wrap = wrap; + case PROP_TEXT: + g_value_set_string (value, layout->text); + break; - if (layout->width != -1) - layout_changed (layout); - } -} + case PROP_ATTRIBUTES: + g_value_set_boxed (value, layout->attrs); + break; -/** - * pango_layout_get_wrap: - * @layout: a `PangoLayout` - * - * Gets the wrap mode for the layout. - * - * Use [method@Pango.Layout.is_wrapped] to query whether - * any paragraphs were actually wrapped. - * - * Return value: active wrap mode. - */ -PangoWrapMode -pango_layout_get_wrap (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); + case PROP_FONT_DESCRIPTION: + g_value_set_boxed (value, layout->font_desc); + break; - return layout->wrap; -} + case PROP_LINE_SPACING: + g_value_set_float (value, layout->line_spacing); + break; -/** - * pango_layout_is_wrapped: - * @layout: a `PangoLayout` - * - * Queries whether the layout had to wrap any paragraphs. - * - * This returns %TRUE if a positive width is set on @layout, - * ellipsization mode of @layout is set to %PANGO_ELLIPSIZE_NONE, - * and there are paragraphs exceeding the layout width that have - * to be wrapped. - * - * Return value: %TRUE if any paragraphs had to be wrapped, %FALSE - * otherwise - * - * Since: 1.16 - */ -gboolean -pango_layout_is_wrapped (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, FALSE); + case PROP_WIDTH: + g_value_set_int (value, layout->width); + break; - pango_layout_check_lines (layout); + case PROP_HEIGHT: + g_value_set_int (value, layout->height); + break; - return layout->is_wrapped; -} + case PROP_TABS: + g_value_set_boxed (value, layout->tabs); + break; -/** - * pango_layout_set_indent: - * @layout: a `PangoLayout` - * @indent: the amount by which to indent - * - * Sets the width in Pango units to indent each paragraph. - * - * A negative value of @indent will produce a hanging indentation. - * That is, the first line will have the full width, and subsequent - * lines will be indented by the absolute value of @indent. - * - * The indent setting is ignored if layout alignment is set to - * %PANGO_ALIGN_CENTER. - * - * The default value is 0. - */ -void -pango_layout_set_indent (PangoLayout *layout, - int indent) -{ - g_return_if_fail (layout != NULL); + case PROP_SINGLE_PARAGRAPH: + g_value_set_boolean (value, layout->single_paragraph); + break; - if (indent != layout->indent) - { - layout->indent = indent; - layout_changed (layout); - } -} + case PROP_WRAP: + g_value_set_enum (value, layout->wrap); + break; -/** - * pango_layout_get_indent: - * @layout: a `PangoLayout` - * - * Gets the paragraph indent width in Pango units. - * - * A negative value indicates a hanging indentation. - * - * Return value: the indent in Pango units - */ -int -pango_layout_get_indent (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, 0); - return layout->indent; -} + case PROP_INDENT: + g_value_set_int (value, layout->indent); + break; -/** - * pango_layout_set_spacing: - * @layout: a `PangoLayout` - * @spacing: the amount of spacing - * - * Sets the amount of spacing in Pango units between - * the lines of the layout. - * - * When placing lines with spacing, Pango arranges things so that - * - * line2.top = line1.bottom + spacing - * - * The default value is 0. - * - * Note: Since 1.44, Pango is using the line height (as determined - * by the font) for placing lines when the line spacing factor is set - * to a non-zero value with [method@Pango.Layout.set_line_spacing]. - * In that case, the @spacing set with this function is ignored. - * - * Note: for semantics that are closer to the CSS line-height - * property, see [func@Pango.attr_line_height_new]. - */ -void -pango_layout_set_spacing (PangoLayout *layout, - int spacing) -{ - g_return_if_fail (layout != NULL); + case PROP_ALIGNMENT: + g_value_set_enum (value, layout->alignment); + break; - if (spacing != layout->spacing) - { - layout->spacing = spacing; - layout_changed (layout); - } -} + case PROP_ELLIPSIZE: + g_value_set_enum (value, layout->ellipsize); + break; -/** - * pango_layout_get_spacing: - * @layout: a `PangoLayout` - * - * Gets the amount of spacing between the lines of the layout. - * - * Return value: the spacing in Pango units - */ -int -pango_layout_get_spacing (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, 0); - return layout->spacing; -} + case PROP_AUTO_DIR: + g_value_set_boolean (value, layout->auto_dir); + break; -/** - * pango_layout_set_line_spacing: - * @layout: a `PangoLayout` - * @factor: the new line spacing factor - * - * Sets a factor for line spacing. - * - * Typical values are: 0, 1, 1.5, 2. The default values is 0. - * - * If @factor is non-zero, lines are placed so that - * - * baseline2 = baseline1 + factor * height2 - * - * where height2 is the line height of the second line - * (as determined by the font(s)). In this case, the spacing - * set with [method@Pango.Layout.set_spacing] is ignored. - * - * If @factor is zero (the default), spacing is applied as before. - * - * Note: for semantics that are closer to the CSS line-height - * property, see [func@Pango.attr_line_height_new]. - * - * Since: 1.44 - */ -void -pango_layout_set_line_spacing (PangoLayout *layout, - float factor) -{ - g_return_if_fail (layout != NULL); + case PROP_LINES: + g_value_set_object (value, pango_layout_get_lines (layout)); + break; - if (layout->line_spacing != factor) - { - layout->line_spacing = factor; - layout_changed (layout); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } -/** - * pango_layout_get_line_spacing: - * @layout: a `PangoLayout` - * - * Gets the line spacing factor of @layout. - * - * See [method@Pango.Layout.set_line_spacing]. - * - * Since: 1.44 - */ -float -pango_layout_get_line_spacing (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, 1.0); - return layout->line_spacing; -} - -/** - * pango_layout_set_attributes: - * @layout: a `PangoLayout` - * @attrs: (nullable) (transfer none): a `PangoAttrList` - * - * Sets the text attributes for a layout object. - * - * References @attrs, so the caller can unref its reference. - */ -void -pango_layout_set_attributes (PangoLayout *layout, - PangoAttrList *attrs) +static void +pango_layout_class_init (PangoLayoutClass *class) { - PangoAttrList *old_attrs; + GObjectClass *object_class = G_OBJECT_CLASS (class); - g_return_if_fail (layout != NULL); - - /* Both empty */ - if (!attrs && !layout->attrs) - return; + object_class->finalize = pango_layout_finalize; + object_class->set_property = pango_layout_set_property; + object_class->get_property = pango_layout_get_property; - if (layout->attrs && - pango_attr_list_equal (layout->attrs, attrs)) - return; + /** + * PangoLayout:context: (attributes org.gtk.Property.get=pango_layout_get_context) + * + * The context for the `PangoLayout`. + */ + props[PROP_CONTEXT] = g_param_spec_object ("context", "context", "context", + PANGO_TYPE_CONTEXT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - old_attrs = layout->attrs; + /** + * PangoLayout:text: (attributes org.gtk.Property.get=pango_layout_get_text org.gtk.Property.set=pango_layout_set_text) + * + * The text of the `PangoLayout`. + */ + props[PROP_TEXT] = g_param_spec_string ("text", "text", "text", + "", + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - /* We always clear lines such that this function can be called - * whenever attrs changes. + /** + * PangoLayout:attributes: (attributes org.gtk.Property.get=pango_layout_get_attributes org.gtk.Property.set=pango_layout_set_attributes) + * + * The attributes of the `PangoLayout`. + * + * Attributes can affect how the text is formatted. */ - layout->attrs = attrs; - if (layout->attrs) - pango_attr_list_ref (layout->attrs); + props[PROP_ATTRIBUTES] = g_param_spec_boxed ("attributes", "attributes", "attributes", + PANGO_TYPE_ATTR_LIST, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - g_clear_pointer (&layout->log_attrs, g_free); - layout_changed (layout); + /** + * PangoLayout:font-description: (attributes org.gtk.Property.get=pango_layout_get_font_description org.gtk.Property.set=pango_layout_set_font_description) + * + * The font description of the `PangoLayout`. + */ + props[PROP_FONT_DESCRIPTION] = g_param_spec_boxed ("font-description", "font-description", "font-description", + PANGO_TYPE_FONT_DESCRIPTION, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - if (old_attrs) - pango_attr_list_unref (old_attrs); - layout->tab_width = -1; -} + /** + * PangoLayout:line-spacing: (attributes org.gtk.Property.get=pango_layout_get_line_spacing org.gtk.Property.set=pango_layout_set_line_spacing) + * + * The line spacing factor of the `PangoLayout`. + */ + props[PROP_LINE_SPACING] = g_param_spec_float ("line-spacing", "line-spacing", "line-spacing", + 0., G_MAXFLOAT, 0., + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); -/** - * pango_layout_get_attributes: - * @layout: a `PangoLayout` - * - * Gets the attribute list for the layout, if any. - * - * Return value: (transfer none) (nullable): a `PangoAttrList` - */ -PangoAttrList* -pango_layout_get_attributes (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); + /** + * PangoLayout:width: (attributes org.gtk.Property.get=pango_layout_get_width org.gtk.Property.set=pango_layout_set_width) + * + * The width to which the text of `PangoLayout` will be broken. + * + * The width is specified in Pango units, with -1 meaning unlimited. + * + * The default value is -1. + */ + props[PROP_WIDTH] = g_param_spec_int ("width", "width", "width", + -1, G_MAXINT, -1, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - return layout->attrs; -} + /** + * PangoLayout:height: (attributes org.gtk.Property.get=pango_layout_get_height org.gtk.Property.set=pango_layout_set_height) + * + * The height to which the `PangoLayout` will be ellipsized. + * + * If @height is positive, it will be the maximum height of the + * layout. Only lines would be shown that would fit, and if there + * is any text omitted, an ellipsis added. At least one line is + * included in each paragraph regardless of how small the height + * value is. A value of zero will render exactly one line for the + * entire layout. + * + * If @height is negative, it will be the (negative of) maximum + * number of lines per paragraph. That is, the total number of lines + * shown may well be more than this value if the layout contains + * multiple paragraphs of text. + * + * The default value of -1 means that the first line of each + * paragraph is ellipsized. + * + * Height setting only has effect if a positive width is set on the + * layout and its ellipsization mode is not `PANGO_ELLIPSIZE_NONE`. + * The behavior is undefined if a height other than -1 is set and + * ellipsization mode is set to `PANGO_ELLIPSIZE_NONE`. + * + * The default value is -1. + */ + props[PROP_HEIGHT] = g_param_spec_int ("height", "height", "height", + -G_MAXINT, G_MAXINT, -1, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); -/** - * pango_layout_set_font_description: - * @layout: a `PangoLayout` - * @desc: (nullable): the new `PangoFontDescription` - * to unset the current font description - * - * Sets the default font description for the layout. - * - * If no font description is set on the layout, the - * font description from the layout's context is used. - */ -void -pango_layout_set_font_description (PangoLayout *layout, - const PangoFontDescription *desc) -{ - g_return_if_fail (layout != NULL); + /** + * PangoLayout:tabs: (attributes org.gtk.Property.get=pango_layout_get_tabs org.gtk.Property.set=pango_layout_set_tabs) + * + * The tabs to use when formatting the text of `PangoLayout`. + * + * `PangoLayout` will place content at the next tab position + * whenever it meets a Tab character (U+0009). + */ + props[PROP_TABS] = g_param_spec_boxed ("tabs", "tabs", "tabs", + PANGO_TYPE_TAB_ARRAY, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - if (desc != layout->font_desc && - (!desc || !layout->font_desc || !pango_font_description_equal(desc, layout->font_desc))) - { - if (layout->font_desc) - pango_font_description_free (layout->font_desc); + /** + * PangoLayout:single-paragraph: (attributes org.gtk.Property.get=pango_layout_get_single_paragraph org.gtk.Property.set=pango_layout_set_single_paragraph) + * + * Whether to treat newlines and similar characters as paragraph + * separators or not. If this property is `TRUE`, all text is kept + * in a single paragraph, and paragraph separator characters are + * displayed with a glyph. + * + * This is useful to allow editing of newlines on a single text line. + * + * The default value is `FALSE`. + */ + props[PROP_SINGLE_PARAGRAPH] = g_param_spec_boolean ("single-paragraph", "single-paragraph", "single-paragraph", + FALSE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - layout->font_desc = desc ? pango_font_description_copy (desc) : NULL; + /** + * PangoLayout:wrap: (attributes org.gtk.Property.get=pango_layout_get_wrap org.gtk.Property.set=pango_layout_set_wrap) + * + * The wrap mode of this `PangoLayout. + * + * The wrap mode influences how Pango chooses line breaks + * when text needs to be wrapped. + * + * The default value is `PANGO_WRAP_WORD`. + */ + props[PROP_WRAP] = g_param_spec_enum ("wrap", "wrap", "wrap", + PANGO_TYPE_WRAP_MODE, + PANGO_WRAP_WORD, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - layout_changed (layout); - layout->tab_width = -1; - } -} + /** + * PangoLayout:indent: (attributes org.gtk.Property.get=pango_layout_get_indent org.gtk.Property.set=pango_layout_set_indent) + * + * The indent of this `PangoLayout. + * + * The indent is specified in Pango units. + * + * A negative value of @indent will produce a hanging indentation. + * That is, the first line will have the full width, and subsequent + * lines will be indented by the absolute value of @indent. + * + * The default value is 0. + */ + props[PROP_INDENT] = g_param_spec_int ("indent", "indent", "indent", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); -/** - * pango_layout_get_font_description: - * @layout: a `PangoLayout` - * - * Gets the font description for the layout, if any. - * - * Return value: (transfer none) (nullable): a pointer to the - * layout's font description, or %NULL if the font description - * from the layout's context is inherited. - * - * Since: 1.8 - */ -const PangoFontDescription * -pango_layout_get_font_description (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); + /** + * PangoLayout:alignment: (attributes org.gtk.Property.get=pango_layout_get_alignment org.gtk.Property.set=pango_layout_set_alignment) + * + * The alignment mode of this `PangoLayout. + * + * The default value is `PANGO_ALIGNMENT_LEFT`. + */ + props[PROP_ALIGNMENT] = g_param_spec_enum ("alignment", "alignment", "alignment", + PANGO_TYPE_ALIGNMENT, + PANGO_ALIGN_LEFT, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - return layout->font_desc; -} + /** + * PangoLayout:ellipsize: (attributes org.gtk.Property.get=pango_layout_get_ellipsize org.gtk.Property.set=pango_layout_set_ellipsize) + * + * The ellipsization mode of this `PangoLayout. + * + * The default value is `PANGO_ELLIPSIZE_NONE`. + */ + props[PROP_ELLIPSIZE] = g_param_spec_enum ("ellipsize", "ellipsize", "ellipsize", + PANGO_TYPE_ELLIPSIZE_MODE, + PANGO_ELLIPSIZE_NONE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); -/** - * pango_layout_set_justify: - * @layout: a `PangoLayout` - * @justify: whether the lines in the layout should be justified - * - * Sets whether each complete line should be stretched to fill the - * entire width of the layout. - * - * Stretching is typically done by adding whitespace, but for some scripts - * (such as Arabic), the justification may be done in more complex ways, - * like extending the characters. - * - * Note that this setting is not implemented and so is ignored in - * Pango older than 1.18. - * - * Note that tabs and justification conflict with each other: - * Justification will move content away from its tab-aligned - * positions. - * - * The default value is %FALSE. - * - * Also see [method@Pango.Layout.set_justify_last_line]. - */ -void -pango_layout_set_justify (PangoLayout *layout, - gboolean justify) -{ - g_return_if_fail (layout != NULL); + /** + * PangoLayout:auto-dir: (attributes org.gtk.Property.get=pango_layout_get_auto_dir org.gtk.Property.set=pango_layout_set_auto_dir) + * + * Whether this `PangoLayout` determines the + * base direction from the content. + * + * The default value is `TRUE`. + */ + props[PROP_AUTO_DIR] = g_param_spec_boolean ("auto-dir", "auto-dir", "auto-dir", + TRUE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - if (justify != layout->justify) - { - layout->justify = justify; + /** + * PangoLayout:lines: (attributes org.gtk.Property.get=pango_layout_get_lines) + * + * The `PangoLines` object holding the formatted lines. + */ + props[PROP_LINES] = g_param_spec_object ("lines", "lines", "lines", + PANGO_TYPE_LINES, + G_PARAM_READABLE); - if (layout->is_ellipsized || - layout->is_wrapped || - layout->justify_last_line) - layout_changed (layout); - } + g_object_class_install_properties (object_class, NUM_PROPERTIES, props); } -/** - * pango_layout_get_justify: - * @layout: a `PangoLayout` - * - * Gets whether each complete line should be stretched to fill the entire - * width of the layout. - * - * Return value: the justify value - */ -gboolean -pango_layout_get_justify (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, FALSE); - return layout->justify; -} +/* }}} */ +/* {{{ Utilities */ -/** - * pango_layout_set_justify_last_line: - * @layout: a `PangoLayout` - * @justify: whether the last line in the layout should be justified - * - * Sets whether the last line should be stretched to fill the - * entire width of the layout. - * - * This only has an effect if [method@Pango.Layout.set_justify] has - * been called as well. - * - * The default value is %FALSE. - * - * Since: 1.50 - */ -void -pango_layout_set_justify_last_line (PangoLayout *layout, - gboolean justify) +static void +layout_changed (PangoLayout *layout) { - g_return_if_fail (layout != NULL); - - if (justify != layout->justify_last_line) - { - layout->justify_last_line = justify; - - if (layout->justify) - layout_changed (layout); - } -} + layout->serial++; + if (layout->serial == 0) + layout->serial++; -/** - * pango_layout_get_justify_last_line: - * @layout: a `PangoLayout` - * - * Gets whether the last line should be stretched - * to fill the entire width of the layout. - * - * Return value: the justify value - * - * Since: 1.50 - */ -gboolean -pango_layout_get_justify_last_line (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, FALSE); - return layout->justify_last_line; + g_clear_object (&layout->lines); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_LINES]); } -/** - * pango_layout_set_auto_dir: - * @layout: a `PangoLayout` - * @auto_dir: if %TRUE, compute the bidirectional base direction - * from the layout's contents - * - * Sets whether to calculate the base direction - * for the layout according to its contents. - * - * When this flag is on (the default), then paragraphs in @layout that - * begin with strong right-to-left characters (Arabic and Hebrew principally), - * will have right-to-left layout, paragraphs with letters from other scripts - * will have left-to-right layout. Paragraphs with only neutral characters - * get their direction from the surrounding paragraphs. - * - * When %FALSE, the choice between left-to-right and right-to-left - * layout is done according to the base direction of the layout's - * `PangoContext`. (See [method@Pango.Context.set_base_dir]). - * - * When the auto-computed direction of a paragraph differs from the - * base direction of the context, the interpretation of - * %PANGO_ALIGN_LEFT and %PANGO_ALIGN_RIGHT are swapped. - * - * Since: 1.4 - */ -void -pango_layout_set_auto_dir (PangoLayout *layout, - gboolean auto_dir) +static void +check_context_changed (PangoLayout *layout) { - g_return_if_fail (PANGO_IS_LAYOUT (layout)); + guint old_serial = layout->context_serial; - auto_dir = auto_dir != FALSE; + layout->context_serial = pango_context_get_serial (layout->context); - if (auto_dir != layout->auto_dir) - { - layout->auto_dir = auto_dir; - layout_changed (layout); - } + if (old_serial != layout->context_serial) + pango_layout_context_changed (layout); } -/** - * pango_layout_get_auto_dir: - * @layout: a `PangoLayout` - * - * Gets whether to calculate the base direction for the layout - * according to its contents. - * - * See [method@Pango.Layout.set_auto_dir]. - * - * Return value: %TRUE if the bidirectional base direction - * is computed from the layout's contents, %FALSE otherwise - * - * Since: 1.4 - */ -gboolean -pango_layout_get_auto_dir (PangoLayout *layout) +static PangoAttrList * +ensure_attrs (PangoLayout *layout, + PangoAttrList *attrs) { - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), TRUE); - - return layout->auto_dir; + if (attrs) + return attrs; + else if (layout->attrs) + return pango_attr_list_copy (layout->attrs); + else + return pango_attr_list_new (); } -/** - * pango_layout_set_alignment: - * @layout: a `PangoLayout` - * @alignment: the alignment - * - * Sets the alignment for the layout: how partial lines are - * positioned within the horizontal space available. - * - * The default alignment is %PANGO_ALIGN_LEFT. - */ -void -pango_layout_set_alignment (PangoLayout *layout, - PangoAlignment alignment) +static PangoAttrList * +get_effective_attributes (PangoLayout *layout) { - g_return_if_fail (layout != NULL); + PangoAttrList *attrs = NULL; - if (alignment != layout->alignment) + if (layout->font_desc) { - layout->alignment = alignment; - layout_changed (layout); + attrs = ensure_attrs (layout, attrs); + pango_attr_list_insert_before (attrs, + pango_attr_font_desc_new (layout->font_desc)); } -} -/** - * pango_layout_get_alignment: - * @layout: a `PangoLayout` - * - * Gets the alignment for the layout: how partial lines are - * positioned within the horizontal space available. - * - * Return value: the alignment - */ -PangoAlignment -pango_layout_get_alignment (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, PANGO_ALIGN_LEFT); - return layout->alignment; -} - - -/** - * pango_layout_set_tabs: - * @layout: a `PangoLayout` - * @tabs: (nullable): a `PangoTabArray` - * - * Sets the tabs to use for @layout, overriding the default tabs. - * - * `PangoLayout` will place content at the next tab position - * whenever it meets a Tab character (U+0009). - * - * By default, tabs are every 8 spaces. If @tabs is %NULL, the - * default tabs are reinstated. @tabs is copied into the layout; - * you must free your copy of @tabs yourself. - * - * Note that tabs and justification conflict with each other: - * Justification will move content away from its tab-aligned - * positions. The same is true for alignments other than - * %PANGO_ALIGN_LEFT. - */ -void -pango_layout_set_tabs (PangoLayout *layout, - PangoTabArray *tabs) -{ - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - - if (tabs != layout->tabs) + if (layout->line_spacing != 0.0) { - g_clear_pointer (&layout->tabs, pango_tab_array_free); - - if (tabs) - { - layout->tabs = pango_tab_array_copy (tabs); - pango_tab_array_sort (layout->tabs); - } - - layout_changed (layout); + attrs = ensure_attrs (layout, attrs); + pango_attr_list_insert_before (attrs, + pango_attr_line_height_new (layout->line_spacing)); } -} -/** - * pango_layout_get_tabs: - * @layout: a `PangoLayout` - * - * Gets the current `PangoTabArray` used by this layout. - * - * If no `PangoTabArray` has been set, then the default tabs are - * in use and %NULL is returned. Default tabs are every 8 spaces. - * - * The return value should be freed with [method@Pango.TabArray.free]. - * - * Return value: (transfer full) (nullable): a copy of the tabs for this layout - */ -PangoTabArray* -pango_layout_get_tabs (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - - if (layout->tabs) - return pango_tab_array_copy (layout->tabs); - else - return NULL; -} - -/** - * pango_layout_set_single_paragraph_mode: - * @layout: a `PangoLayout` - * @setting: new setting - * - * Sets the single paragraph mode of @layout. - * - * If @setting is %TRUE, do not treat newlines and similar characters - * as paragraph separators; instead, keep all text in a single paragraph, - * and display a glyph for paragraph separator characters. Used when - * you want to allow editing of newlines on a single text line. - * - * The default value is %FALSE. - */ -void -pango_layout_set_single_paragraph_mode (PangoLayout *layout, - gboolean setting) -{ - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - setting = setting != FALSE; - - if (layout->single_paragraph != setting) + if (layout->single_paragraph) { - layout->single_paragraph = setting; - layout_changed (layout); + attrs = ensure_attrs (layout, attrs); + pango_attr_list_insert_before (attrs, + pango_attr_paragraph_new ()); } -} -/** - * pango_layout_get_single_paragraph_mode: - * @layout: a `PangoLayout` - * - * Obtains whether @layout is in single paragraph mode. - * - * See [method@Pango.Layout.set_single_paragraph_mode]. - * - * Return value: %TRUE if the layout does not break paragraphs - * at paragraph separator characters, %FALSE otherwise - */ -gboolean -pango_layout_get_single_paragraph_mode (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE); + if (attrs) + return attrs; - return layout->single_paragraph; + return pango_attr_list_ref (layout->attrs); } -/** - * pango_layout_set_ellipsize: - * @layout: a `PangoLayout` - * @ellipsize: the new ellipsization mode for @layout - * - * Sets the type of ellipsization being performed for @layout. - * - * Depending on the ellipsization mode @ellipsize text is - * removed from the start, middle, or end of text so they - * fit within the width and height of layout set with - * [method@Pango.Layout.set_width] and [method@Pango.Layout.set_height]. - * - * If the layout contains characters such as newlines that - * force it to be layed out in multiple paragraphs, then whether - * each paragraph is ellipsized separately or the entire layout - * is ellipsized as a whole depends on the set height of the layout. - * - * The default value is %PANGO_ELLIPSIZE_NONE. - * - * See [method@Pango.Layout.set_height] for details. - * - * Since: 1.6 - */ -void -pango_layout_set_ellipsize (PangoLayout *layout, - PangoEllipsizeMode ellipsize) +static gboolean +ends_with_paragraph_separator (PangoLayout *layout) { - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - if (ellipsize != layout->ellipsize) - { - layout->ellipsize = ellipsize; + if (layout->single_paragraph) + return FALSE; - if (layout->is_ellipsized || layout->is_wrapped) - layout_changed (layout); - } + return g_str_has_suffix (layout->text, "\n") || + g_str_has_suffix (layout->text, "\r") || + g_str_has_suffix (layout->text, "\r\n") || + g_str_has_suffix (layout->text, "
"); } -/** - * pango_layout_get_ellipsize: - * @layout: a `PangoLayout` - * - * Gets the type of ellipsization being performed for @layout. - * - * See [method@Pango.Layout.set_ellipsize]. - * - * Use [method@Pango.Layout.is_ellipsized] to query whether any - * paragraphs were actually ellipsized. - * - * Return value: the current ellipsization mode for @layout - * - * Since: 1.6 - */ -PangoEllipsizeMode -pango_layout_get_ellipsize (PangoLayout *layout) +static void +ensure_lines (PangoLayout *layout) { - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), PANGO_ELLIPSIZE_NONE); + PangoLineBreaker *breaker; + PangoAttrList *attrs; + int x, y, width; + int line_no; - return layout->ellipsize; -} + check_context_changed (layout); -/** - * pango_layout_is_ellipsized: - * @layout: a `PangoLayout` - * - * Queries whether the layout had to ellipsize any paragraphs. - * - * This returns %TRUE if the ellipsization mode for @layout - * is not %PANGO_ELLIPSIZE_NONE, a positive width is set on @layout, - * and there are paragraphs exceeding that width that have to be - * ellipsized. - * - * Return value: %TRUE if any paragraphs had to be ellipsized, - * %FALSE otherwise - * - * Since: 1.16 - */ -gboolean -pango_layout_is_ellipsized (PangoLayout *layout) -{ - g_return_val_if_fail (layout != NULL, FALSE); + if (layout->lines) + return; - pango_layout_check_lines (layout); + breaker = pango_line_breaker_new (layout->context); - return layout->is_ellipsized; -} + pango_line_breaker_set_tabs (breaker, layout->tabs); + pango_line_breaker_set_base_dir (breaker, + layout->auto_dir + ? PANGO_DIRECTION_NEUTRAL + : pango_context_get_base_dir (layout->context)); -/** - * pango_layout_set_text: - * @layout: a `PangoLayout` - * @text: the text - * @length: maximum length of @text, in bytes. -1 indicates that - * the string is nul-terminated and the length should be calculated. - * The text will also be truncated on encountering a nul-termination - * even when @length is positive. - * - * Sets the text of the layout. - * - * This function validates @text and renders invalid UTF-8 - * with a placeholder glyph. - * - * Note that if you have used [method@Pango.Layout.set_markup] or - * [method@Pango.Layout.set_markup_with_accel] on @layout before, you - * may want to call [method@Pango.Layout.set_attributes] to clear the - * attributes set on the layout from the markup as this function does - * not clear attributes. - */ -void -pango_layout_set_text (PangoLayout *layout, - const char *text, - int length) -{ - char *old_text, *start, *end; - - g_return_if_fail (layout != NULL); - g_return_if_fail (length == 0 || text != NULL); + attrs = get_effective_attributes (layout); + pango_line_breaker_add_text (breaker, layout->text ? layout->text : "", -1, attrs); + if (attrs) + pango_attr_list_unref (attrs); - old_text = layout->text; + layout->lines = pango_lines_new (); - if (length < 0) - { - layout->length = strlen (text); - layout->text = g_strndup (text, layout->length); - } - else if (length > 0) - { - /* This is not exactly what we want. We don't need the padding... - */ - layout->length = length; - layout->text = g_strndup (text, length); - } - else + x = y = 0; + line_no = 0; + while (!pango_line_breaker_done (breaker)) { - layout->length = 0; - layout->text = g_malloc0 (1); - } + PangoLayoutLine *line; + PangoRectangle ext; + int offset; + PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE; - /* validate it, and replace invalid bytes with -1 */ - start = layout->text; - for (;;) { - gboolean valid; + if ((line_no == 0) == (layout->indent > 0)) + { + x = abs (layout->indent); + width = layout->width - x; + } + else + { + x = 0; + width = layout->width; + } - valid = g_utf8_validate (start, -1, (const char **)&end); + if (layout->height < 0 && line_no + 1 == - layout->height) + ellipsize = layout->ellipsize; - if (!*end) - break; +retry: + line = pango_line_breaker_next_line (breaker, x, width, layout->wrap, ellipsize); + pango_layout_line_get_extents (line, NULL, &ext); - /* Replace invalid bytes with -1. The -1 will be converted to - * ((gunichar) -1) by glib, and that in turn yields a glyph value of - * ((PangoGlyph) -1) by PANGO_GET_UNKNOWN_GLYPH(-1), - * and that's PANGO_GLYPH_INVALID_INPUT. - */ - if (!valid) - *end++ = -1; + if (layout->height >= 0 && y + 2 * ext.height >= layout->height && + ellipsize != layout->ellipsize) + { + if (pango_line_breaker_undo_line (breaker, line)) + { + g_clear_object (&line); + ellipsize = layout->ellipsize; + goto retry; + } + } - start = end; - } + /* Handle alignment and justification */ + offset = 0; + switch (layout->alignment) + { + case PANGO_ALIGN_LEFT: + break; + case PANGO_ALIGN_CENTER: + if (ext.width < width) + offset = (width - ext.width) / 2; + break; + case PANGO_ALIGN_RIGHT: + if (ext.width < width) + offset = width - ext.width; + break; + case PANGO_ALIGN_JUSTIFY: + if (!pango_layout_line_ends_paragraph (line)) + line = pango_layout_line_justify (line, width); + break; + case PANGO_ALIGN_JUSTIFY_ALL: + line = pango_layout_line_justify (line, width); + break; + default: g_assert_not_reached (); + } - if (start != layout->text) - /* TODO: Write out the beginning excerpt of text? */ - g_warning ("Invalid UTF-8 string passed to pango_layout_set_text()"); + pango_lines_add_line (layout->lines, line, x + offset, y - ext.y); - layout->n_chars = pango_utf8_strlen (layout->text, -1); - layout->length = strlen (layout->text); + y += ext.height; + line_no++; + } - g_clear_pointer (&layout->log_attrs, g_free); - layout_changed (layout); + /* Append an empty line if we end with a newline. + * And always provide at least one line + */ + if (pango_lines_get_line_count (layout->lines) == 0 || + ends_with_paragraph_separator (layout)) + { + LineData *data; + int start_index; + int start_offset; + int offset; + PangoLayoutLine *line; + PangoRectangle ext; - g_free (old_text); -} + if (pango_lines_get_line_count (layout->lines) > 0) + { + PangoLayoutLine *last; -/** - * pango_layout_get_text: - * @layout: a `PangoLayout` - * - * Gets the text in the layout. - * - * The returned text should not be freed or modified. - * - * Return value: (transfer none): the text in the @layout - */ -const char* -pango_layout_get_text (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); + last = pango_lines_get_line (layout->lines, + pango_lines_get_line_count (layout->lines) - 1, + NULL, NULL); + data = last->data; + start_index = data->length; + start_offset = last->data->n_chars; + offset = MAX (layout->indent, 0); + } + else + { + data = line_data_new (); + data->text = g_strdup (""); + data->length = 0; + data->attrs = get_effective_attributes (layout); + data->log_attrs = g_new0 (PangoLogAttr, 1); + data->log_attrs[0].is_cursor_position = TRUE; + start_index = 0; + start_offset = 0; + offset = 0; + } - /* We don't ever want to return NULL as the text. - */ - if (G_UNLIKELY (!layout->text)) - return ""; + line = pango_layout_line_new (layout->context, data); + line->starts_paragraph = TRUE; + line->ends_paragraph = TRUE; + line->start_index = start_index; + line->length = 0; + line->start_offset = start_offset; + line->n_chars = 0; - return layout->text; -} + pango_layout_line_get_extents (line, NULL, &ext); -/** - * pango_layout_get_character_count: - * @layout: a `PangoLayout` - * - * Returns the number of Unicode characters in the - * the text of @layout. - * - * Return value: the number of Unicode characters - * in the text of @layout - * - * Since: 1.30 - */ -gint -pango_layout_get_character_count (PangoLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); + pango_lines_add_line (layout->lines, line, x + offset, y - ext.y); - return layout->n_chars; -} + line_data_unref (data); + } -/** - * pango_layout_set_markup: - * @layout: a `PangoLayout` - * @markup: marked-up text - * @length: length of marked-up text in bytes, or -1 if @markup is - * `NUL`-terminated - * - * Sets the layout text and attribute list from marked-up text. - * - * See [Pango Markup](pango_markup.html)). - * - * Replaces the current text and attribute list. - * - * This is the same as [method@Pango.Layout.set_markup_with_accel], - * but the markup text isn't scanned for accelerators. - */ -void -pango_layout_set_markup (PangoLayout *layout, - const char *markup, - int length) -{ - pango_layout_set_markup_with_accel (layout, markup, length, 0, NULL); + g_object_unref (breaker); } +/* }}} */ +/* {{{ Public API */ + /** - * pango_layout_set_markup_with_accel: - * @layout: a `PangoLayout` - * @markup: marked-up text (see [Pango Markup](pango_markup.html)) - * @length: length of marked-up text in bytes, or -1 if @markup is - * `NUL`-terminated - * @accel_marker: marker for accelerators in the text - * @accel_char: (out caller-allocates) (optional): return location - * for first located accelerator - * - * Sets the layout text and attribute list from marked-up text. + * pango_layout_new: + * @context: a `PangoContext` * - * See [Pango Markup](pango_markup.html)). + * Creates a new `PangoLayout` with attribute initialized to + * default values for a particular `PangoContext` * - * Replaces the current text and attribute list. - * - * If @accel_marker is nonzero, the given character will mark the - * character following it as an accelerator. For example, @accel_marker - * might be an ampersand or underscore. All characters marked - * as an accelerator will receive a %PANGO_UNDERLINE_LOW attribute, - * and the first character so marked will be returned in @accel_char. - * Two @accel_marker characters following each other produce a single - * literal @accel_marker character. + * Return value: a newly allocated `PangoLayout` */ -void -pango_layout_set_markup_with_accel (PangoLayout *layout, - const char *markup, - int length, - gunichar accel_marker, - gunichar *accel_char) +PangoLayout * +pango_layout_new (PangoContext *context) { - PangoAttrList *list = NULL; - char *text = NULL; - GError *error; - - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - g_return_if_fail (markup != NULL); + g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL); - error = NULL; - if (!pango_parse_markup (markup, length, - accel_marker, - &list, &text, - accel_char, - &error)) - { - g_warning ("pango_layout_set_markup_with_accel: %s", error->message); - g_error_free (error); - return; - } - - pango_layout_set_text (layout, text, -1); - pango_layout_set_attributes (layout, list); - pango_attr_list_unref (list); - g_free (text); + return g_object_new (PANGO_TYPE_LAYOUT, "context", context, NULL); } /** - * pango_layout_get_unknown_glyphs_count: + * pango_layout_copy: * @layout: a `PangoLayout` * - * Counts the number of unknown glyphs in @layout. - * - * This function can be used to determine if there are any fonts - * available to render all characters in a certain string, or when - * used in combination with %PANGO_ATTR_FALLBACK, to check if a - * certain font supports all the characters in the string. + * Creates a deep copy-by-value of the layout. * - * Return value: The number of unknown glyphs in @layout + * The attribute list, tab array, and text from the original layout + * are all copied by value. * - * Since: 1.16 + * Return value: (transfer full): the newly allocated `PangoLayout` */ -int -pango_layout_get_unknown_glyphs_count (PangoLayout *layout) -{ - PangoLayoutLine *line; - PangoLayoutRun *run; - GSList *lines_list; - GSList *runs_list; - int i, count = 0; - - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); - - pango_layout_check_lines (layout); - - if (layout->unknown_glyphs_count >= 0) - return layout->unknown_glyphs_count; - - lines_list = layout->lines; - while (lines_list) - { - line = lines_list->data; - runs_list = line->runs; - - while (runs_list) - { - run = runs_list->data; - - for (i = 0; i < run->glyphs->num_glyphs; i++) - { - if (run->glyphs->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG) - count++; - } - - runs_list = runs_list->next; - } - lines_list = lines_list->next; - } - - layout->unknown_glyphs_count = count; - return count; -} - -static void -check_context_changed (PangoLayout *layout) +PangoLayout * +pango_layout_copy (PangoLayout *layout) { - guint old_serial = layout->context_serial; - - layout->context_serial = pango_context_get_serial (layout->context); - - if (old_serial != layout->context_serial) - pango_layout_context_changed (layout); -} + PangoLayout *copy; -static void -layout_changed (PangoLayout *layout) -{ - layout->serial++; - if (layout->serial == 0) - layout->serial++; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - pango_layout_clear_lines (layout); -} + copy = pango_layout_new (layout->context); -/** - * pango_layout_context_changed: - * @layout: a `PangoLayout` - * - * Forces recomputation of any state in the `PangoLayout` that - * might depend on the layout's context. - * - * This function should be called if you make changes to the context - * subsequent to creating the layout. - */ -void -pango_layout_context_changed (PangoLayout *layout) -{ - g_return_if_fail (PANGO_IS_LAYOUT (layout)); + copy->text = g_strdup (layout->text); + copy->length = layout->length; + if (layout->attrs) + copy->attrs = pango_attr_list_copy (layout->attrs); + if (layout->font_desc) + copy->font_desc = pango_font_description_copy (layout->font_desc); + copy->line_spacing = layout->line_spacing; + copy->width = layout->width; + copy->height = layout->height; + if (layout->tabs) + copy->tabs = pango_tab_array_copy (layout->tabs); + copy->single_paragraph = layout->single_paragraph; + copy->wrap = layout->wrap; + copy->indent = layout->indent; + copy->serial = layout->serial; + copy->context_serial = layout->context_serial; + copy->alignment = layout->alignment; + copy->ellipsize = layout->ellipsize; + copy->auto_dir = layout->auto_dir; - layout_changed (layout); - layout->tab_width = -1; + return copy; } /** @@ -1488,6399 +757,816 @@ pango_layout_context_changed (PangoLayout *layout) * The serial number is initialized to an small number larger than zero * when a new layout is created and is increased whenever the layout is * changed using any of the setter functions, or the `PangoContext` it - * uses has changed. The serial may wrap, but will never have the value 0. - * Since it can wrap, never compare it with "less than", always use "not equals". + * uses has changed. + * + * The serial may wrap, but will never have the value 0. Since it can + * wrap, never compare it with "less than", always use "not equals". * * This can be used to automatically detect changes to a `PangoLayout`, * and is useful for example to decide whether a layout needs redrawing. - * To force the serial to be increased, use - * [method@Pango.Layout.context_changed]. * - * Return value: The current serial number of @layout. - * - * Since: 1.32.4 + * Return value: The current serial number of @layout */ guint pango_layout_get_serial (PangoLayout *layout) { check_context_changed (layout); - return layout->serial; -} - -/** - * pango_layout_get_log_attrs: - * @layout: a `PangoLayout` - * @attrs: (out)(array length=n_attrs)(transfer container): - * location to store a pointer to an array of logical attributes. - * This value must be freed with g_free(). - * @n_attrs: (out): location to store the number of the attributes in the - * array. (The stored value will be one more than the total number - * of characters in the layout, since there need to be attributes - * corresponding to both the position before the first character - * and the position after the last character.) - * - * Retrieves an array of logical attributes for each character in - * the @layout. - */ -void -pango_layout_get_log_attrs (PangoLayout *layout, - PangoLogAttr **attrs, - gint *n_attrs) -{ - g_return_if_fail (layout != NULL); - - pango_layout_check_lines (layout); - if (attrs) - { - *attrs = g_new (PangoLogAttr, layout->n_chars + 1); - memcpy (*attrs, layout->log_attrs, sizeof(PangoLogAttr) * (layout->n_chars + 1)); - } - - if (n_attrs) - *n_attrs = layout->n_chars + 1; + return layout->serial; } /** - * pango_layout_get_log_attrs_readonly: + * pango_layout_context_changed: * @layout: a `PangoLayout` - * @n_attrs: (out): location to store the number of the attributes in - * the array - * - * Retrieves an array of logical attributes for each character in - * the @layout. - * - * This is a faster alternative to [method@Pango.Layout.get_log_attrs]. - * The returned array is part of @layout and must not be modified. - * Modifying the layout will invalidate the returned array. - * - * The number of attributes returned in @n_attrs will be one more - * than the total number of characters in the layout, since there - * need to be attributes corresponding to both the position before - * the first character and the position after the last character. - * - * Returns: (array length=n_attrs): an array of logical attributes - * - * Since: 1.30 - */ -const PangoLogAttr * -pango_layout_get_log_attrs_readonly (PangoLayout *layout, - gint *n_attrs) -{ - if (n_attrs) - *n_attrs = 0; - g_return_val_if_fail (layout != NULL, NULL); - - pango_layout_check_lines (layout); - - if (n_attrs) - *n_attrs = layout->n_chars + 1; - - return layout->log_attrs; -} - - -/** - * pango_layout_get_line_count: - * @layout: `PangoLayout` * - * Retrieves the count of lines for the @layout. + * Forces recomputation of any state in the `PangoLayout` that + * might depend on the layout's context. * - * Return value: the line count + * This function should be called if you make changes to the + * context subsequent to creating the layout. */ -int -pango_layout_get_line_count (PangoLayout *layout) +void +pango_layout_context_changed (PangoLayout *layout) { - g_return_val_if_fail (layout != NULL, 0); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - pango_layout_check_lines (layout); - return layout->line_count; + layout_changed (layout); } -/** - * pango_layout_get_lines: - * @layout: a `PangoLayout` - * - * Returns the lines of the @layout as a list. - * - * Use the faster [method@Pango.Layout.get_lines_readonly] if you do not - * plan to modify the contents of the lines (glyphs, glyph widths, etc.). - * - * Return value: (element-type Pango.LayoutLine) (transfer none): a `GSList` - * containing the lines in the layout. This points to internal data of the - * `PangoLayout` and must be used with care. It will become invalid on any - * change to the layout's text or properties. - */ -GSList * -pango_layout_get_lines (PangoLayout *layout) -{ - pango_layout_check_lines (layout); - - if (layout->lines) - { - GSList *tmp_list = layout->lines; - while (tmp_list) - { - PangoLayoutLine *line = tmp_list->data; - tmp_list = tmp_list->next; - - pango_layout_line_leaked (line); - } - } - - return layout->lines; -} +/* {{{ Property getters and setters */ /** - * pango_layout_get_lines_readonly: + * pango_layout_get_context: * @layout: a `PangoLayout` * - * Returns the lines of the @layout as a list. - * - * This is a faster alternative to [method@Pango.Layout.get_lines], - * but the user is not expected to modify the contents of the lines - * (glyphs, glyph widths, etc.). - * - * Return value: (element-type Pango.LayoutLine) (transfer none): a `GSList` - * containing the lines in the layout. This points to internal data of the - * `PangoLayout` and must be used with care. It will become invalid on any - * change to the layout's text or properties. No changes should be made to - * the lines. + * Retrieves the `PangoContext` used for this layout. * - * Since: 1.16 + * Return value: (transfer none): the `PangoContext` for the layout */ -GSList * -pango_layout_get_lines_readonly (PangoLayout *layout) +PangoContext * +pango_layout_get_context (PangoLayout *layout) { - pango_layout_check_lines (layout); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - return layout->lines; + return layout->context; } /** - * pango_layout_get_line: + * pango_layout_set_text: * @layout: a `PangoLayout` - * @line: the index of a line, which must be between 0 and - * `pango_layout_get_line_count(layout) - 1`, inclusive. - * - * Retrieves a particular line from a `PangoLayout`. - * - * Use the faster [method@Pango.Layout.get_line_readonly] if you do not - * plan to modify the contents of the line (glyphs, glyph widths, etc.). + * @text: the text + * @length: maximum length of @text, in bytes. -1 indicates that + * the string is nul-terminated * - * Return value: (transfer none) (nullable): the requested `PangoLayoutLine`, - * or %NULL if the index is out of range. This layout line can be ref'ed - * and retained, but will become invalid if changes are made to the - * `PangoLayout`. + * Sets the text of the layout. */ -PangoLayoutLine * -pango_layout_get_line (PangoLayout *layout, - int line) +void +pango_layout_set_text (PangoLayout *layout, + const char *text, + int length) { - GSList *list_item; - g_return_val_if_fail (layout != NULL, NULL); - - if (line < 0) - return NULL; - - pango_layout_check_lines (layout); - - list_item = g_slist_nth (layout->lines, line); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (list_item) - { - PangoLayoutLine *line = list_item->data; + if (length < 0) + length = strlen (text); - pango_layout_line_leaked (line); - return line; - } + g_free (layout->text); + layout->text = g_strndup (text, length); + layout->length = length; - return NULL; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TEXT]); + layout_changed (layout); } /** - * pango_layout_get_line_readonly: + * pango_layout_get_text: * @layout: a `PangoLayout` - * @line: the index of a line, which must be between 0 and - * `pango_layout_get_line_count(layout) - 1`, inclusive. - * - * Retrieves a particular line from a `PangoLayout`. - * - * This is a faster alternative to [method@Pango.Layout.get_line], - * but the user is not expected to modify the contents of the line - * (glyphs, glyph widths, etc.). * - * Return value: (transfer none) (nullable): the requested `PangoLayoutLine`, - * or %NULL if the index is out of range. This layout line can be ref'ed - * and retained, but will become invalid if changes are made to the - * `PangoLayout`. No changes should be made to the line. + * Gets the text in the layout. * - * Since: 1.16 - */ -PangoLayoutLine * -pango_layout_get_line_readonly (PangoLayout *layout, - int line) -{ - GSList *list_item; - g_return_val_if_fail (layout != NULL, NULL); - - if (line < 0) - return NULL; - - pango_layout_check_lines (layout); - - list_item = g_slist_nth (layout->lines, line); - - if (list_item) - { - PangoLayoutLine *line = list_item->data; - return line; - } - - return NULL; -} - -/** - * pango_layout_line_index_to_x: - * @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: (out): location to store the x_offset (in Pango units) + * The returned text should not be freed or modified. * - * Converts an index within a line to a X position. + * Return value: (transfer none): the text in the @layout */ -void -pango_layout_line_index_to_x (PangoLayoutLine *line, - int index, - int trailing, - int *x_pos) -{ - PangoLayout *layout = line->layout; - GSList *run_list = line->runs; - int width = 0; - - while (run_list) - { - PangoLayoutRun *run = run_list->data; - - 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 && - 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; - } - } - - /* 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; - - return; - } - - width += pango_glyph_string_get_width (run->glyphs); - - run_list = run_list->next; - } - - if (x_pos) - *x_pos = width; -} - -static PangoLayoutLine * -pango_layout_index_to_line (PangoLayout *layout, - int index, - int *line_nr, - PangoLayoutLine **line_before, - PangoLayoutLine **line_after) -{ - GSList *tmp_list; - GSList *line_list; - PangoLayoutLine *line = NULL; - PangoLayoutLine *prev_line = NULL; - int i = -1; - - line_list = tmp_list = layout->lines; - while (tmp_list) - { - PangoLayoutLine *tmp_line = tmp_list->data; - - if (tmp_line->start_index > index) - break; /* index was in paragraph delimiters */ - - prev_line = line; - line = tmp_line; - line_list = tmp_list; - i++; - - if (line->start_index + line->length > index) - break; - - tmp_list = tmp_list->next; - } - - if (line_nr) - *line_nr = i; - - if (line_before) - *line_before = prev_line; - - if (line_after) - *line_after = (line_list && line_list->next) ? line_list->next->data : NULL; - - return line; -} - -static PangoLayoutLine * -pango_layout_index_to_line_and_extents (PangoLayout *layout, - int index, - PangoRectangle *line_rect, - PangoRectangle *run_rect) +const char * +pango_layout_get_text (PangoLayout *layout) { - PangoLayoutIter iter; - PangoLayoutLine *line = NULL; - - _pango_layout_get_iter (layout, &iter); - - if (!ITER_IS_INVALID (&iter)) - while (TRUE) - { - PangoLayoutLine *tmp_line = _pango_layout_iter_get_line (&iter); - - if (tmp_line->start_index > index) - break; /* index was in paragraph delimiters */ - - line = tmp_line; - - pango_layout_iter_get_line_extents (&iter, NULL, line_rect); - - if (!iter.line_list_link->next || - ((PangoLayoutLine *)iter.line_list_link->next->data)->start_index > index) - { - if (run_rect) - { - while (TRUE) - { - PangoLayoutRun *run = _pango_layout_iter_get_run (&iter); - - pango_layout_iter_get_run_extents (&iter, NULL, run_rect); - - if (!run) - break; - - if (run->item->offset <= index && index < run->item->offset + run->item->length) - break; - - if (!pango_layout_iter_next_run (&iter)) - break; - } - } - - break; - } - - if (!pango_layout_iter_next_line (&iter)) - break; /* Use end of last line */ - } - - _pango_layout_iter_destroy (&iter); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - return line; + return layout->text; } /** - * pango_layout_index_to_line_x: + * pango_layout_set_attributes: * @layout: a `PangoLayout` - * @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: (out) (optional): location to store resulting line index. (which will - * between 0 and pango_layout_get_line_count(layout) - 1) - * @x_pos: (out) (optional): location to store resulting position within line - * (%PANGO_SCALE units per device unit) + * @attrs: (nullable) (transfer none): a `PangoAttrList` * - * Converts from byte @index_ within the @layout to line and X position. + * Sets the attributes for a layout object. * - * The X position is measured from the left edge of the line. + * References @attrs, so the caller can unref its reference. */ void -pango_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; - } -} - -typedef struct { - int x; - int pos; -} CursorPos; - -static int -compare_cursor (gconstpointer v1, - gconstpointer v2) -{ - const CursorPos *c1 = v1; - const CursorPos *c2 = v2; - - return c1->x - c2->x; -} - -static void -pango_layout_line_get_cursors (PangoLayoutLine *line, - gboolean strong, - GArray *cursors) +pango_layout_set_attributes (PangoLayout *layout, + PangoAttrList *attrs) { - PangoLayout *layout = line->layout; - int line_no; - PangoLayoutLine *line2; - const char *start, *end; - int start_offset; - int j; - const char *p; - PangoRectangle pos; - - g_assert (g_array_get_element_size (cursors) == sizeof (CursorPos)); - g_assert (cursors->len == 0); - - start = layout->text + line->start_index; - end = start + line->length; - start_offset = g_utf8_pointer_to_offset (layout->text, start); - - pango_layout_index_to_line_x (layout, line->start_index + line->length, 0, &line_no, NULL); - line2 = pango_layout_get_line (layout, line_no); - if (line2 == line) - end++; - - for (j = start_offset, p = start; p < end; j++, p = g_utf8_next_char (p)) - { - if (layout->log_attrs[j].is_cursor_position) - { - CursorPos cursor; - - pango_layout_get_cursor_pos (layout, p - layout->text, - strong ? &pos : NULL, - strong ? NULL : &pos); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - cursor.x = pos.x; - cursor.pos = p - layout->text; - g_array_append_val (cursors, cursor); - } - } + g_clear_pointer (&layout->attrs, pango_attr_list_unref); + layout->attrs = attrs; + if (layout->attrs) + pango_attr_list_ref (layout->attrs); - g_array_sort (cursors, compare_cursor); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ATTRIBUTES]); + layout_changed (layout); } /** - * pango_layout_move_cursor_visually: + * pango_layout_get_attributes: * @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 current cursor position - * @old_trailing: if 0, the cursor was at the leading edge of the - * grapheme indicated by @old_index, if > 0, the cursor - * was at the trailing edge. - * @direction: direction to move cursor. A negative - * value indicates motion to the left - * @new_index: (out): 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: (out): 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 direction. * - * If @direction is positive, then the new position will cause the strong - * or weak cursor to be displayed one position to right of where it was - * with the old cursor position. If @direction is negative, it will be - * moved to the left. - * - * 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. + * Gets the attribute list for the layout, if any. * - * Motion here is in cursor positions, not in characters, so a single - * call to this function may move the cursor over multiple characters - * when multiple characters combine to form a single grapheme. + * Return value: (transfer none) (nullable): a `PangoAttrList` */ -void -pango_layout_move_cursor_visually (PangoLayout *layout, - gboolean strong, - int old_index, - int old_trailing, - int direction, - int *new_index, - int *new_trailing) +PangoAttrList * +pango_layout_get_attributes (PangoLayout *layout) { - PangoLayoutLine *line = NULL; - PangoLayoutLine *prev_line; - PangoLayoutLine *next_line; - GArray *cursors; - int n_vis; - int vis_pos; - int start_offset; - gboolean off_start = FALSE; - gboolean off_end = FALSE; - PangoRectangle pos; - int j; - - g_return_if_fail (layout != NULL); - g_return_if_fail (old_index >= 0 && old_index <= layout->length); - g_return_if_fail (old_trailing >= 0); - 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); - - while (old_trailing--) - old_index = g_utf8_next_char (layout->text + old_index) - layout->text; - - /* Clamp old_index to fit on the line */ - if (old_index > (line->start_index + line->length)) - old_index = line->start_index + line->length; - - cursors = g_array_new (FALSE, FALSE, sizeof (CursorPos)); - pango_layout_line_get_cursors (line, strong, cursors); - - pango_layout_get_cursor_pos (layout, old_index, strong ? &pos : NULL, strong ? NULL : &pos); - - vis_pos = -1; - for (j = 0; j < cursors->len; j++) - { - CursorPos *cursor = &g_array_index (cursors, CursorPos, j); - if (cursor->x == pos.x) - { - vis_pos = j; - - /* If moving left, we pick the leftmost match, otherwise - * the rightmost one. Without this, we can get stuck - */ - if (direction < 0) - break; - } - } - - if (vis_pos == -1 && - old_index == line->start_index + line->length) - { - if (line->resolved_dir == PANGO_DIRECTION_LTR) - vis_pos = cursors->len; - else - vis_pos = 0; - } - - /* Handling movement between lines */ - if (line->resolved_dir == PANGO_DIRECTION_LTR) - { - if (old_index == line->start_index && direction < 0) - off_start = TRUE; - if (old_index == line->start_index + line->length && direction > 0) - off_end = TRUE; - } - else - { - if (old_index == line->start_index + line->length && direction < 0) - off_start = TRUE; - if (old_index == line->start_index && direction > 0) - off_end = 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; - g_array_unref (cursors); - return; - } - line = prev_line; - paragraph_boundary = (line->start_index + line->length != old_index); - } - else - { - if (!next_line) - { - *new_index = G_MAXINT; - *new_trailing = 0; - g_array_unref (cursors); - return; - } - line = next_line; - paragraph_boundary = (line->start_index != old_index); - } - - g_array_set_size (cursors, 0); - pango_layout_line_get_cursors (line, strong, cursors); - - n_vis = cursors->len; - - if (off_start && direction < 0) - { - vis_pos = n_vis; - if (paragraph_boundary) - vis_pos++; - } - else if (off_end && direction > 0) - { - vis_pos = 0; - if (paragraph_boundary) - vis_pos--; - } - } - - if (direction < 0) - vis_pos--; - else - vis_pos++; - - if (0 <= vis_pos && vis_pos < cursors->len) - *new_index = g_array_index (cursors, CursorPos, vis_pos).pos; - else if (vis_pos >= cursors->len - 1) - *new_index = line->start_index + line->length; - - *new_trailing = 0; - - if (*new_index == line->start_index + line->length && line->length > 0) - { - int log_pos; - - start_offset = g_utf8_pointer_to_offset (layout->text, layout->text + line->start_index); - log_pos = start_offset + pango_utf8_strlen (layout->text + line->start_index, line->length); - do - { - log_pos--; - *new_index = g_utf8_prev_char (layout->text + *new_index) - layout->text; - (*new_trailing)++; - } - while (log_pos > start_offset && !layout->log_attrs[log_pos].is_cursor_position); - } + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - g_array_unref (cursors); + return layout->attrs; } /** - * pango_layout_xy_to_index: + * pango_layout_set_font_description: * @layout: a `PangoLayout` - * @x: the X offset (in Pango units) from the left edge of the layout - * @y: the Y offset (in Pango units) from the top edge of the layout - * @index_: (out): location to store calculated byte index - * @trailing: (out): 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 leading 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 [method@Pango.LayoutLine.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. + * @desc: (nullable): the new `PangoFontDescription` * - * Return value: %TRUE if the coordinates were inside text, %FALSE otherwise - */ -gboolean -pango_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); - - _pango_layout_get_iter (layout, &iter); - - do - { - PangoRectangle line_logical; - int first_y, last_y; - - g_assert (!ITER_IS_INVALID (&iter)); - - 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_destroy (&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: (out): rectangle in which to store the position of the grapheme + * Sets the default font description for the layout. * - * Converts from an index within a `PangoLayout` to the onscreen position - * corresponding to the grapheme at that index. + * If no font description is set on the layout, the + * font description from the layout's context is used. * - * The return value 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. + * This method is a shorthand for adding a font-desc attribute. */ void -pango_layout_index_to_pos (PangoLayout *layout, - int index, - PangoRectangle *pos) -{ - PangoRectangle line_logical_rect = { 0, }; - PangoRectangle run_logical_rect = { 0, }; - 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); - - _pango_layout_get_iter (layout, &iter); - - 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 - * - * This shouldn’t occur in the first loop iteration as the first - * line’s start_index should always be 0. - */ - g_assert (layout_line != NULL); - index = layout_line->start_index + layout_line->length; - break; - } - - pango_layout_iter_get_line_extents (&iter, NULL, &line_logical_rect); - - layout_line = tmp_line; - - if (layout_line->start_index + layout_line->length >= index) - { - do - { - PangoLayoutRun *run = _pango_layout_iter_get_run (&iter); - - pango_layout_iter_get_run_extents (&iter, NULL, &run_logical_rect); - - if (!run) - break; - - if (run->item->offset <= index && index < run->item->offset + run->item->length) - break; - } - while (pango_layout_iter_next_run (&iter)); - - 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 = run_logical_rect.y; - pos->height = run_logical_rect.height; - - pango_layout_line_index_to_x (layout_line, index, 0, &x_pos); - pos->x = line_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 = (line_logical_rect.x + x_pos) - pos->x; - } - else - pos->width = 0; - } - - _pango_layout_iter_destroy (&iter); -} - -static PangoLayoutRun * -pango_layout_line_get_run (PangoLayoutLine *line, - int index) +pango_layout_set_font_description (PangoLayout *layout, + const PangoFontDescription *desc) { - GSList *run_list; + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - run_list = line->runs; - while (run_list) + if (desc != layout->font_desc && + (!desc || !layout->font_desc || !pango_font_description_equal (desc, layout->font_desc))) { - PangoLayoutRun *run = run_list->data; + if (layout->font_desc) + pango_font_description_free (layout->font_desc); - if (run->item->offset <= index && run->item->offset + run->item->length > index) - return run; + layout->font_desc = desc ? pango_font_description_copy (desc) : NULL; - run_list = run_list->next; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_FONT_DESCRIPTION]); + layout_changed (layout); } - - return NULL; -} - -static int -pango_layout_line_get_char_level (PangoLayoutLine *line, - int index) -{ - PangoLayoutRun *run; - - run = pango_layout_line_get_run (line, index); - - if (run) - return run->item->analysis.level; - - return 0; -} - -static PangoDirection -pango_layout_line_get_char_direction (PangoLayoutLine *layout_line, - int index) -{ - return pango_layout_line_get_char_level (layout_line, index) % 2 - ? PANGO_DIRECTION_RTL - : PANGO_DIRECTION_LTR; } /** - * pango_layout_get_direction: + * pango_layout_get_font_description: * @layout: a `PangoLayout` - * @index: the byte index of the char * - * Gets the text direction at the given character position in @layout. + * Gets the font description for the layout, if any. * - * Returns: the text direction at @index + * Return value: (transfer none) (nullable): a pointer to the + * layout's font description, or %NULL if the font description + * from the layout's context is inherited. * - * Since: 1.46 + * Since: 1.8 */ -PangoDirection -pango_layout_get_direction (PangoLayout *layout, - int index) +const PangoFontDescription * +pango_layout_get_font_description (PangoLayout *layout) { - PangoLayoutLine *line; - - line = pango_layout_index_to_line_and_extents (layout, index, NULL, NULL); - - if (line) - return pango_layout_line_get_char_direction (line, index); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - return PANGO_DIRECTION_LTR; + return layout->font_desc; } /** - * pango_layout_get_cursor_pos: + * pango_layout_set_line_spacing: * @layout: a `PangoLayout` - * @index_: the byte index of the cursor - * @strong_pos: (out) (optional): location to store the strong cursor position - * @weak_pos: (out) (optional): location to store the weak cursor position + * @line_spacing: the new line spacing factor * - * Given an index within a layout, determines the positions that of the - * strong and weak cursors if the insertion point is at that index. - * - * The position of each cursor is stored as a zero-width rectangle - * with the height of the run extents. - * - * <picture> - * <source srcset="cursor-positions-dark.png" media="(prefers-color-scheme: dark)"> - * <img alt="Cursor positions" src="cursor-positions-light.png"> - * </picture> - * - * The strong cursor location is the location where characters of the - * directionality equal to the base direction of the layout are inserted. - * The weak cursor location is the location where characters of the - * directionality opposite to the base direction of the layout are inserted. - * - * The following example shows text with both a strong and a weak cursor. - * - * <picture> - * <source srcset="split-cursor-dark.png" media="(prefers-color-scheme: dark)"> - * <img alt="Strong and weak cursors" src="split-cursor-light.png"> - * </picture> + * Sets a factor for line spacing. * - * The strong cursor has a little arrow pointing to the right, the weak - * cursor to the left. Typing a 'c' in this situation will insert the - * character after the 'b', and typing another Hebrew character, like 'ג', - * will insert it at the end. - */ -void -pango_layout_get_cursor_pos (PangoLayout *layout, - int index, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) -{ - PangoDirection dir1, dir2; - int level1, level2; - PangoRectangle line_rect = { 666, }; - PangoRectangle run_rect = { 666, }; - PangoLayoutLine *layout_line = NULL; /* Quiet GCC */ - int x1_trailing; - int x2; - - g_return_if_fail (layout != NULL); - g_return_if_fail (index >= 0 && index <= layout->length); - - layout_line = pango_layout_index_to_line_and_extents (layout, index, - &line_rect, &run_rect); - - g_assert (index >= layout_line->start_index); - - /* Examine the trailing edge of the character before the cursor */ - if (index == layout_line->start_index) - { - dir1 = layout_line->resolved_dir; - level1 = dir1 == PANGO_DIRECTION_LTR ? 0 : 1; - if (layout_line->resolved_dir == PANGO_DIRECTION_LTR) - x1_trailing = 0; - else - x1_trailing = line_rect.width; - } - else - { - gint prev_index = g_utf8_prev_char (layout->text + index) - layout->text; - level1 = pango_layout_line_get_char_level (layout_line, prev_index); - dir1 = level1 % 2 ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; - pango_layout_line_index_to_x (layout_line, prev_index, TRUE, &x1_trailing); - } - - /* Examine the leading edge of the character after the cursor */ - if (index >= layout_line->start_index + layout_line->length) - { - dir2 = layout_line->resolved_dir; - level2 = dir2 == PANGO_DIRECTION_LTR ? 0 : 1; - if (layout_line->resolved_dir == PANGO_DIRECTION_LTR) - x2 = line_rect.width; - else - x2 = 0; - } - else - { - pango_layout_line_index_to_x (layout_line, index, FALSE, &x2); - level2 = pango_layout_line_get_char_level (layout_line, index); - dir2 = level2 % 2 ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR; - } - - if (strong_pos) - { - strong_pos->x = line_rect.x; - - if (dir1 == layout_line->resolved_dir && - (dir2 != dir1 || level1 < level2)) - strong_pos->x += x1_trailing; - else - strong_pos->x += x2; - - strong_pos->y = run_rect.y; - strong_pos->width = 0; - strong_pos->height = run_rect.height; - } - - if (weak_pos) - { - weak_pos->x = line_rect.x; - - if (dir1 == layout_line->resolved_dir && - (dir2 != dir1 || level1 < level2)) - weak_pos->x += x2; - else - weak_pos->x += x1_trailing; - - weak_pos->y = run_rect.y; - weak_pos->width = 0; - weak_pos->height = run_rect.height; - } -} - -/** - * pango_layout_get_caret_pos: - * @layout: a `PangoLayout` - * @index_: the byte index of the cursor - * @strong_pos: (out) (optional): location to store the strong cursor position - * @weak_pos: (out) (optional): location to store the weak cursor position + * Typical values are: 0, 1, 1.5, 2. The default values is 0. * - * Given an index within a layout, determines the positions that of the - * strong and weak cursors if the insertion point is at that index. + * If @line_spacing is non-zero, lines are placed so that * - * This is a variant of [method@Pango.Layout.get_cursor_pos] that applies - * font metric information about caret slope and offset to the positions - * it returns. + * baseline2 = baseline1 + factor * height2 * - * <picture> - * <source srcset="caret-metrics-dark.png" media="(prefers-color-scheme: dark)"> - * <img alt="Caret metrics" src="caret-metrics-light.png"> - * </picture> + * where height2 is the line height of the second line (as determined + * by the font). * - * Since: 1.50 + * This method is a shorthand for adding a line-height attribute. */ void -pango_layout_get_caret_pos (PangoLayout *layout, - int index, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) -{ - PangoLayoutLine *line; - PangoLayoutRun *run; - hb_font_t *hb_font; - hb_position_t caret_offset, caret_run, caret_rise, descender; - - pango_layout_get_cursor_pos (layout, index, strong_pos, weak_pos); - - /* FIXME: not very efficient to re-iterate here */ - line = pango_layout_index_to_line_and_extents (layout, index, NULL, NULL); - run = pango_layout_line_get_run (line, index); - if (!run) - run = pango_layout_line_get_run (line, index - 1); - - if (!run) - return; - - hb_font = pango_font_get_hb_font (run->item->analysis.font); - - if (hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, &caret_rise) && - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, &caret_run) && - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, &caret_offset) && - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &descender)) - { - double slope_inv; - int x_scale, y_scale; - - if (strong_pos) - strong_pos->x += caret_offset; - - if (weak_pos) - weak_pos->x += caret_offset; - - if (caret_rise == 0) - return; - - hb_font_get_scale (hb_font, &x_scale, &y_scale); - slope_inv = (caret_run * y_scale) / (double) (caret_rise * x_scale); - - if (strong_pos) - { - strong_pos->x += descender * slope_inv; - strong_pos->width = strong_pos->height * slope_inv; - if (slope_inv < 0) - strong_pos->x -= strong_pos->width; - } - - if (weak_pos) - { - weak_pos->x += descender * slope_inv; - weak_pos->width = weak_pos->height * slope_inv; - if (slope_inv < 0) - weak_pos->x -= weak_pos->width; - } - } -} - -static inline int -direction_simple (PangoDirection d) -{ - switch (d) - { - case PANGO_DIRECTION_LTR : - case PANGO_DIRECTION_WEAK_LTR : - case PANGO_DIRECTION_TTB_RTL : - return 1; - case PANGO_DIRECTION_RTL : - case PANGO_DIRECTION_WEAK_RTL : - case PANGO_DIRECTION_TTB_LTR : - return -1; - case PANGO_DIRECTION_NEUTRAL : - return 0; - default: - break; - } - /* not reached */ - return 0; -} - -static PangoAlignment -get_alignment (PangoLayout *layout, - PangoLayoutLine *line) -{ - PangoAlignment alignment = layout->alignment; - - if (alignment != PANGO_ALIGN_CENTER && line->layout->auto_dir && - direction_simple (line->resolved_dir) == - -direction_simple (pango_context_get_base_dir (layout->context))) - { - if (alignment == PANGO_ALIGN_LEFT) - alignment = PANGO_ALIGN_RIGHT; - else if (alignment == PANGO_ALIGN_RIGHT) - alignment = PANGO_ALIGN_LEFT; - } - - return alignment; -} - -static void -get_x_offset (PangoLayout *layout, - PangoLayoutLine *line, - int layout_width, - int line_width, - int *x_offset) -{ - PangoAlignment alignment = get_alignment (layout, line); - - /* Alignment */ - if (layout_width == 0) - *x_offset = 0; - else if (alignment == PANGO_ALIGN_RIGHT) - *x_offset = layout_width - line_width; - else if (alignment == PANGO_ALIGN_CENTER) { - *x_offset = (layout_width - line_width) / 2; - /* hinting */ - if (((layout_width | line_width) & (PANGO_SCALE - 1)) == 0) - { - *x_offset = PANGO_UNITS_ROUND (*x_offset); - } - } else - *x_offset = 0; - - /* Indentation */ - - /* For center, we ignore indentation; I think I've seen word - * processors that still do the indentation here as if it were - * indented left/right, though we can't sensibly do that without - * knowing whether left/right is the "normal" thing for this text - */ - - if (alignment == PANGO_ALIGN_CENTER) - return; - - if (line->is_paragraph_start) - { - if (layout->indent > 0) - { - if (alignment == PANGO_ALIGN_LEFT) - *x_offset += layout->indent; - else - *x_offset -= layout->indent; - } - } - else - { - if (layout->indent < 0) - { - if (alignment == PANGO_ALIGN_LEFT) - *x_offset -= layout->indent; - else - *x_offset += layout->indent; - } - } -} - -static void -pango_layout_line_get_extents_and_height (PangoLayoutLine *line, - PangoRectangle *ink, - PangoRectangle *logical, - int *height); -static void -get_line_extents_layout_coords (PangoLayout *layout, - PangoLayoutLine *line, - int layout_width, - int y_offset, - int *baseline, - PangoRectangle *line_ink_layout, - PangoRectangle *line_logical_layout) -{ - int x_offset; - /* Line extents in line coords (origin at line baseline) */ - PangoRectangle line_ink; - PangoRectangle line_logical; - gboolean first_line; - int new_baseline; - int height; - - if (layout->lines->data == line) - first_line = TRUE; - else - first_line = FALSE; - - pango_layout_line_get_extents_and_height (line, line_ink_layout ? &line_ink : NULL, - &line_logical, - &height); - - get_x_offset (layout, line, layout_width, line_logical.width, &x_offset); - - if (first_line || !baseline || layout->line_spacing == 0.0) - new_baseline = y_offset - line_logical.y; - else - new_baseline = *baseline + layout->line_spacing * height; - - /* Convert the line's extents into layout coordinates */ - if (line_ink_layout) - { - *line_ink_layout = line_ink; - line_ink_layout->x = line_ink.x + x_offset; - line_ink_layout->y = new_baseline + line_ink.y; - } - - if (line_logical_layout) - { - *line_logical_layout = line_logical; - line_logical_layout->x = line_logical.x + x_offset; - line_logical_layout->y = new_baseline + line_logical.y; - } - - if (baseline) - *baseline = new_baseline; -} - -/* if non-NULL line_extents returns a list of line extents - * in layout coordinates - */ -static void -pango_layout_get_extents_internal (PangoLayout *layout, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect, - Extents **line_extents) +pango_layout_set_line_spacing (PangoLayout *layout, + float line_spacing) { - GSList *line_list; - int y_offset = 0; - int width; - gboolean need_width = FALSE; - int line_index = 0; - int baseline; - - g_return_if_fail (layout != NULL); - - pango_layout_check_lines (layout); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (ink_rect && layout->ink_rect_cached) - { - *ink_rect = layout->ink_rect; - ink_rect = NULL; - } - if (logical_rect && layout->logical_rect_cached) - { - *logical_rect = layout->logical_rect; - logical_rect = NULL; - } - if (!ink_rect && !logical_rect && !line_extents) + if (layout->line_spacing == line_spacing) return; - /* When we are not wrapping, we need the overall width of the layout to - * figure out the x_offsets of each line. However, we only need the - * x_offsets if we are computing the ink_rect or individual line extents. - */ - width = layout->width; - - if (layout->auto_dir) - { - /* If one of the lines of the layout is not left aligned, then we need - * the width of the layout to calculate line x-offsets; this requires - * looping through the lines for layout->auto_dir. - */ - line_list = layout->lines; - while (line_list && !need_width) - { - PangoLayoutLine *line = line_list->data; - - if (get_alignment (layout, line) != PANGO_ALIGN_LEFT) - need_width = TRUE; - - line_list = line_list->next; - } - } - else if (layout->alignment != PANGO_ALIGN_LEFT) - need_width = TRUE; - - if (width == -1 && need_width && (ink_rect || line_extents)) - { - PangoRectangle overall_logical; - - pango_layout_get_extents_internal (layout, NULL, &overall_logical, NULL); - width = overall_logical.width; - } - - if (logical_rect) - { - logical_rect->x = 0; - logical_rect->y = 0; - logical_rect->width = 0; - logical_rect->height = 0; - } - - - if (line_extents && layout->line_count > 0) - { - *line_extents = g_malloc (sizeof (Extents) * layout->line_count); - } + layout->line_spacing = line_spacing; - baseline = 0; - line_list = layout->lines; - while (line_list) - { - PangoLayoutLine *line = line_list->data; - /* Line extents in layout coords (origin at 0,0 of the layout) */ - PangoRectangle line_ink_layout; - PangoRectangle line_logical_layout; - - int new_pos; - - /* This block gets the line extents in layout coords */ - { - get_line_extents_layout_coords (layout, line, - width, y_offset, - &baseline, - ink_rect ? &line_ink_layout : NULL, - &line_logical_layout); - - if (line_extents && layout->line_count > 0) - { - Extents *ext = &(*line_extents)[line_index]; - ext->baseline = baseline; - ext->ink_rect = line_ink_layout; - ext->logical_rect = line_logical_layout; - } - } - - if (ink_rect) - { - /* Compute the union of the current ink_rect with - * line_ink_layout - */ - - if (line_list == layout->lines) - { - *ink_rect = line_ink_layout; - } - else - { - new_pos = MIN (ink_rect->x, line_ink_layout.x); - ink_rect->width = - MAX (ink_rect->x + ink_rect->width, - line_ink_layout.x + line_ink_layout.width) - new_pos; - ink_rect->x = new_pos; - - new_pos = MIN (ink_rect->y, line_ink_layout.y); - ink_rect->height = - MAX (ink_rect->y + ink_rect->height, - line_ink_layout.y + line_ink_layout.height) - new_pos; - ink_rect->y = new_pos; - } - } - - if (logical_rect) - { - if (layout->width == -1) - { - /* When no width is set on layout, we can just compute the max of the - * line lengths to get the horizontal extents ... logical_rect.x = 0. - */ - logical_rect->width = MAX (logical_rect->width, line_logical_layout.width); - } - else - { - /* When a width is set, we have to compute the union of the horizontal - * extents of all the lines. - */ - if (line_list == layout->lines) - { - logical_rect->x = line_logical_layout.x; - logical_rect->width = line_logical_layout.width; - } - else - { - new_pos = MIN (logical_rect->x, line_logical_layout.x); - logical_rect->width = - MAX (logical_rect->x + logical_rect->width, - line_logical_layout.x + line_logical_layout.width) - new_pos; - logical_rect->x = new_pos; - - } - } - - logical_rect->height = line_logical_layout.y + line_logical_layout.height - logical_rect->y; - } - - y_offset = line_logical_layout.y + line_logical_layout.height + layout->spacing; - line_list = line_list->next; - line_index ++; - } - - if (ink_rect) - { - layout->ink_rect = *ink_rect; - layout->ink_rect_cached = TRUE; - } - if (logical_rect) - { - layout->logical_rect = *logical_rect; - layout->logical_rect_cached = TRUE; - } + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_LINE_SPACING]); + layout_changed (layout); } /** - * pango_layout_get_extents: + * pango_layout_get_line_spacing: * @layout: a `PangoLayout` - * @ink_rect: (out) (optional): rectangle used to store the extents of the - * layout as drawn - * @logical_rect: (out) (optional):rectangle used to store the logical - * extents of the layout - * - * Computes the logical and ink extents of @layout. * - * Logical extents are usually what you want for positioning things. Note - * that both extents may have non-zero x and y. You may want to use those - * to offset where you render the layout. Not doing that is a very typical - * bug that shows up as right-to-left layouts not being correctly positioned - * in a layout with a set width. + * Gets the line spacing factor of @layout. * - * The extents are given in layout coordinates and in Pango units; layout - * coordinates begin at the top left corner of the layout. + * See [method@Pango.Layout.set_line_spacing]. */ -void -pango_layout_get_extents (PangoLayout *layout, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +float +pango_layout_get_line_spacing (PangoLayout *layout) { - g_return_if_fail (layout != NULL); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0.0); - pango_layout_get_extents_internal (layout, ink_rect, logical_rect, NULL); + return layout->line_spacing; } /** - * pango_layout_get_pixel_extents: - * @layout: a `PangoLayout` - * @ink_rect: (out) (optional): rectangle used to store the extents of the - * layout as drawn - * @logical_rect: (out) (optional): rectangle used to store the logical - * extents of the layout + * pango_layout_set_width: + * @layout: a `PangoLayout`. + * @width: the desired width in Pango units, or -1 to indicate that no + * wrapping or ellipsization should be performed. * - * Computes the logical and ink extents of @layout in device units. + * Sets the width to which the lines of the layout should + * be wrapped or ellipsized. * - * This function just calls [method@Pango.Layout.get_extents] followed by - * two [func@extents_to_pixels] calls, rounding @ink_rect and @logical_rect - * such that the rounded rectangles fully contain the unrounded one (that is, - * passes them as first argument to [func@Pango.extents_to_pixels]). + * The default value is -1: no width set. */ void -pango_layout_get_pixel_extents (PangoLayout *layout, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +pango_layout_set_width (PangoLayout *layout, + int width) { g_return_if_fail (PANGO_IS_LAYOUT (layout)); - pango_layout_get_extents (layout, ink_rect, logical_rect); - pango_extents_to_pixels (ink_rect, NULL); - pango_extents_to_pixels (logical_rect, NULL); -} - -/** - * pango_layout_get_size: - * @layout: a `PangoLayout` - * @width: (out) (optional): location to store the logical width - * @height: (out) (optional): location to store the logical height - * - * Determines the logical width and height of a `PangoLayout` in Pango - * units. - * - * This is simply a convenience function around [method@Pango.Layout.get_extents]. - */ -void -pango_layout_get_size (PangoLayout *layout, - int *width, - int *height) -{ - PangoRectangle logical_rect; - - pango_layout_get_extents (layout, NULL, &logical_rect); - - if (width) - *width = logical_rect.width; - if (height) - *height = logical_rect.height; -} + if (width < -1) + width = -1; -/** - * pango_layout_get_pixel_size: - * @layout: a `PangoLayout` - * @width: (out) (optional): location to store the logical width - * @height: (out) (optional): location to store the logical height - * - * Determines the logical width and height of a `PangoLayout` in device - * units. - * - * [method@Pango.Layout.get_size] returns the width and height - * scaled by %PANGO_SCALE. This is simply a convenience function - * around [method@Pango.Layout.get_pixel_extents]. - */ -void -pango_layout_get_pixel_size (PangoLayout *layout, - int *width, - int *height) -{ - PangoRectangle logical_rect; + if (layout->width == width) + return; - pango_layout_get_extents_internal (layout, NULL, &logical_rect, NULL); - pango_extents_to_pixels (&logical_rect, NULL); + layout->width = width; - if (width) - *width = logical_rect.width; - if (height) - *height = logical_rect.height; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_WIDTH]); + layout_changed (layout); } /** - * pango_layout_get_baseline: + * pango_layout_get_width: * @layout: a `PangoLayout` * - * Gets the Y position of baseline of the first line in @layout. + * Gets the width to which the lines of the layout should wrap. * - * Return value: baseline of first line, from top of @layout - * - * Since: 1.22 + * Return value: the width in Pango units, or -1 if no width set. */ int -pango_layout_get_baseline (PangoLayout *layout) -{ - int baseline; - Extents *extents = NULL; - - /* XXX this is kinda inefficient */ - pango_layout_get_extents_internal (layout, NULL, NULL, &extents); - baseline = extents ? extents[0].baseline : 0; - - g_free (extents); - - return baseline; -} - -static void -pango_layout_clear_lines (PangoLayout *layout) +pango_layout_get_width (PangoLayout *layout) { - if (layout->lines) - { - GSList *tmp_list = layout->lines; - while (tmp_list) - { - PangoLayoutLine *line = tmp_list->data; - tmp_list = tmp_list->next; - - line->layout = NULL; - pango_layout_line_unref (line); - } - - g_slist_free (layout->lines); - layout->lines = NULL; - layout->line_count = 0; - } - - layout->unknown_glyphs_count = -1; - layout->logical_rect_cached = FALSE; - layout->ink_rect_cached = FALSE; - layout->is_ellipsized = FALSE; - layout->is_wrapped = FALSE; -} - -static void -pango_layout_line_leaked (PangoLayoutLine *line) -{ - PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line; - - private->cache_status = LEAKED; - - if (line->layout) - { - line->layout->logical_rect_cached = FALSE; - line->layout->ink_rect_cached = FALSE; - } -} - - -/***************** - * Line Breaking * - *****************/ - -static void shape_tab (PangoLayoutLine *line, - LastTabState *tab_state, - ItemProperties *properties, - int current_width, - PangoItem *item, - PangoGlyphString *glyphs); - -static void -free_run (PangoLayoutRun *run, gpointer data) -{ - gboolean free_item = data != NULL; - if (free_item) - pango_item_free (run->item); - - pango_glyph_string_free (run->glyphs); - g_slice_free (PangoLayoutRun, run); -} - -static PangoItem * -uninsert_run (PangoLayoutLine *line) -{ - PangoLayoutRun *run; - PangoItem *item; - - GSList *tmp_node = line->runs; - - run = tmp_node->data; - item = run->item; - - line->runs = tmp_node->next; - line->length -= item->length; - - g_slist_free_1 (tmp_node); - free_run (run, (gpointer)FALSE); - - return item; -} - -static void -ensure_tab_width (PangoLayout *layout) -{ - if (layout->tab_width == -1) - { - /* Find out how wide 8 spaces are in the context's default - * font. Utter performance killer. :-( - */ - PangoGlyphString *glyphs = pango_glyph_string_new (); - PangoItem *item; - GList *items; - PangoAttribute *attr; - PangoAttrList *layout_attrs; - PangoAttrList tmp_attrs; - PangoFontDescription *font_desc = pango_font_description_copy_static (pango_context_get_font_description (layout->context)); - PangoLanguage *language = NULL; - PangoShapeFlags shape_flags = PANGO_SHAPE_NONE; - - if (pango_context_get_round_glyph_positions (layout->context)) - shape_flags |= PANGO_SHAPE_ROUND_POSITIONS; - - layout_attrs = pango_layout_get_effective_attributes (layout); - if (layout_attrs) - { - PangoAttrIterator iter; - - _pango_attr_list_get_iterator (layout_attrs, &iter); - pango_attr_iterator_get_font (&iter, font_desc, &language, NULL); - _pango_attr_iterator_destroy (&iter); - } - - _pango_attr_list_init (&tmp_attrs); - - attr = pango_attr_font_desc_new (font_desc); - pango_font_description_free (font_desc); - pango_attr_list_insert_before (&tmp_attrs, attr); - - if (language) - { - attr = pango_attr_language_new (language); - pango_attr_list_insert_before (&tmp_attrs, attr); - } - - items = pango_itemize (layout->context, " ", 0, 1, &tmp_attrs, NULL); - - if (layout_attrs != layout->attrs) - { - pango_attr_list_unref (layout_attrs); - layout_attrs = NULL; - } - _pango_attr_list_destroy (&tmp_attrs); - - item = items->data; - pango_shape_with_flags (" ", 8, " ", 8, &item->analysis, glyphs, shape_flags); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), -1); - pango_item_free (item); - g_list_free (items); - - layout->tab_width = pango_glyph_string_get_width (glyphs); - - pango_glyph_string_free (glyphs); - - /* We need to make sure the tab_width is > 0 so finding tab positions - * terminates. This check should be necessary only under extreme - * problems with the font. - */ - if (layout->tab_width <= 0) - layout->tab_width = 50 * PANGO_SCALE; /* pretty much arbitrary */ - } -} - -static void -get_tab_pos (PangoLayoutLine *line, - int index, - int *tab_pos, - PangoTabAlign *alignment, - gunichar *decimal, - gboolean *is_default) -{ - PangoLayout *layout = line->layout; - int n_tabs; - gboolean in_pixels; - int offset = 0; - - if (layout->alignment != PANGO_ALIGN_CENTER) - { - if (line->is_paragraph_start && layout->indent >= 0) - offset = layout->indent; - else if (!line->is_paragraph_start && layout->indent < 0) - offset = - layout->indent; - } - - if (layout->tabs) - { - n_tabs = pango_tab_array_get_size (layout->tabs); - in_pixels = pango_tab_array_get_positions_in_pixels (layout->tabs); - *is_default = FALSE; - } - else - { - n_tabs = 0; - in_pixels = FALSE; - *is_default = TRUE; - } - - if (index < n_tabs) - { - pango_tab_array_get_tab (layout->tabs, index, alignment, tab_pos); - - if (in_pixels) - *tab_pos *= PANGO_SCALE; - - *decimal = pango_tab_array_get_decimal_point (layout->tabs, index); - } - else if (n_tabs > 0) - { - /* Extrapolate tab position, repeating the last tab gap to infinity. */ - int last_pos = 0; - int next_to_last_pos = 0; - int tab_width; - - pango_tab_array_get_tab (layout->tabs, n_tabs - 1, alignment, &last_pos); - *decimal = pango_tab_array_get_decimal_point (layout->tabs, n_tabs - 1); - - if (n_tabs > 1) - pango_tab_array_get_tab (layout->tabs, n_tabs - 2, NULL, &next_to_last_pos); - else - next_to_last_pos = 0; - - if (in_pixels) - { - next_to_last_pos *= PANGO_SCALE; - last_pos *= PANGO_SCALE; - } - - if (last_pos > next_to_last_pos) - tab_width = last_pos - next_to_last_pos; - else - tab_width = layout->tab_width; - - *tab_pos = last_pos + tab_width * (index - n_tabs + 1); - } - else - { - /* No tab array set, so use default tab width */ - *tab_pos = layout->tab_width * index; - *alignment = PANGO_TAB_LEFT; - *decimal = 0; - } - - *tab_pos -= offset; -} - -static void -ensure_decimal (PangoLayout *layout) -{ - if (layout->decimal == 0) - layout->decimal = g_utf8_get_char (localeconv ()->decimal_point); -} - -struct _LastTabState { - PangoGlyphString *glyphs; - int index; - int width; - int pos; - PangoTabAlign align; - gunichar decimal; -}; - -static void -shape_tab (PangoLayoutLine *line, - LastTabState *tab_state, - ItemProperties *properties, - int current_width, - PangoItem *item, - PangoGlyphString *glyphs) -{ - int i, space_width; - int tab_pos; - PangoTabAlign tab_align; - gunichar tab_decimal; - - pango_glyph_string_set_size (glyphs, 1); - - if (properties->showing_space) - glyphs->glyphs[0].glyph = PANGO_GET_UNKNOWN_GLYPH ('\t'); - else - glyphs->glyphs[0].glyph = PANGO_GLYPH_EMPTY; - - glyphs->glyphs[0].geometry.x_offset = 0; - glyphs->glyphs[0].geometry.y_offset = 0; - glyphs->glyphs[0].attr.is_cluster_start = 1; - glyphs->glyphs[0].attr.is_color = 0; - - glyphs->log_clusters[0] = 0; - - ensure_tab_width (line->layout); - space_width = line->layout->tab_width / 8; - - for (i = tab_state->index; ; i++) - { - gboolean is_default; - - get_tab_pos (line, i, &tab_pos, &tab_align, &tab_decimal, &is_default); - - /* Make sure there is at least a space-width of space between - * tab-aligned text and the text before it. However, only do - * this if no tab array is set on the layout, ie. using default - * tab positions. If the user has set tab positions, respect it - * to the pixel. - */ - if (tab_pos >= current_width + (is_default ? space_width : 1)) - { - glyphs->glyphs[0].geometry.width = tab_pos - current_width; - break; - } - } - - if (tab_decimal == 0) - { - ensure_decimal (line->layout); - tab_decimal = line->layout->decimal; - } - - tab_state->glyphs = glyphs; - tab_state->index = i; - tab_state->width = current_width; - tab_state->pos = tab_pos; - tab_state->align = tab_align; - tab_state->decimal = tab_decimal; -} - -static inline gboolean -can_break_at (PangoLayout *layout, - gint offset, - PangoWrapMode wrap) -{ - if (offset == layout->n_chars) - return TRUE; - else if (wrap == PANGO_WRAP_CHAR) - return layout->log_attrs[offset].is_char_break; - else - return layout->log_attrs[offset].is_line_break; -} - -static inline gboolean -can_break_in (PangoLayout *layout, - int start_offset, - int num_chars, - gboolean allow_break_at_start) -{ - int i; - - for (i = allow_break_at_start ? 0 : 1; i < num_chars; i++) - if (can_break_at (layout, start_offset + i, layout->wrap)) - return TRUE; - - return FALSE; -} - -static inline void -distribute_letter_spacing (int letter_spacing, - int *space_left, - int *space_right) -{ - *space_left = letter_spacing / 2; - /* hinting */ - if ((letter_spacing & (PANGO_SCALE - 1)) == 0) - { - *space_left = PANGO_UNITS_ROUND (*space_left); - } - *space_right = letter_spacing - *space_left; -} - -typedef enum -{ - BREAK_NONE_FIT, - BREAK_SOME_FIT, - BREAK_ALL_FIT, - BREAK_EMPTY_FIT, - BREAK_LINE_SEPARATOR -} BreakResult; - -struct _ParaBreakState -{ - /* maintained per layout */ - int line_height; /* Estimate of height of current line; < 0 is no estimate */ - int remaining_height; /* Remaining height of the layout; only defined if layout->height >= 0 */ - - /* maintained per paragraph */ - PangoAttrList *attrs; /* Attributes being used for itemization */ - GList *items; /* This paragraph turned into items */ - PangoDirection base_dir; /* Current resolved base direction */ - int line_of_par; /* Line of the paragraph, starting at 1 for first line */ - - PangoGlyphString *glyphs; /* Glyphs for the first item in state->items */ - int start_offset; /* Character offset of first item in state->items in layout->text */ - ItemProperties properties; /* Properties for the first item in state->items */ - int *log_widths; /* Logical widths for first item in state->items.. */ - int num_log_widths; /* Length of log_widths */ - int log_widths_offset; /* Offset into log_widths to the point corresponding - * to the remaining portion of the first item */ - - int line_start_index; /* Start index (byte offset) of line in layout->text */ - int line_start_offset; /* Character offset of line in layout->text */ - - /* maintained per line */ - int line_width; /* Goal width of line currently processing; < 0 is infinite */ - int remaining_width; /* Amount of space remaining on line; < 0 is infinite */ - - int hyphen_width; /* How much space a hyphen will take */ - - GList *baseline_shifts; - - LastTabState last_tab; -}; - -static gboolean -should_ellipsize_current_line (PangoLayout *layout, - ParaBreakState *state); - -static void -get_decimal_prefix_width (PangoItem *item, - PangoGlyphString *glyphs, - const char *text, - gunichar decimal, - int *width, - gboolean *found) -{ - PangoGlyphItem glyph_item = { item, glyphs, 0, 0, 0 }; - int *log_widths; - int i; - const char *p; - - log_widths = g_new (int, item->num_chars); - - pango_glyph_item_get_logical_widths (&glyph_item, text, log_widths); - - *width = 0; - *found = FALSE; - - for (i = 0, p = text + item->offset; i < item->num_chars; i++, p = g_utf8_next_char (p)) - { - if (g_utf8_get_char (p) == decimal) - { - *width += log_widths[i] / 2; - *found = TRUE; - break; - } - - *width += log_widths[i]; - } - - g_free (log_widths); -} - -static int -line_width (ParaBreakState *state, - PangoLayoutLine *line) -{ - GSList *l; - int i; - int width = 0; - - if (state->remaining_width > -1) - return state->line_width - state->remaining_width; - - /* Compute the width of the line currently - inefficient, but easier - * than keeping the current width of the line up to date everywhere - */ - for (l = line->runs; l; l = l->next) - { - PangoLayoutRun *run = l->data; - - for (i = 0; i < run->glyphs->num_glyphs; i++) - width += run->glyphs->glyphs[i].geometry.width; - } - - return width; -} - -static PangoGlyphString * -shape_run (PangoLayoutLine *line, - ParaBreakState *state, - PangoItem *item) -{ - PangoLayout *layout = line->layout; - PangoGlyphString *glyphs = pango_glyph_string_new (); - - if (layout->text[item->offset] == '\t') - shape_tab (line, &state->last_tab, &state->properties, line_width (state, line), item, glyphs); - else - { - PangoShapeFlags shape_flags = PANGO_SHAPE_NONE; - - if (pango_context_get_round_glyph_positions (layout->context)) - shape_flags |= PANGO_SHAPE_ROUND_POSITIONS; - - if (state->properties.shape_set) - _pango_shape_shape (layout->text + item->offset, item->num_chars, - state->properties.shape_ink_rect, state->properties.shape_logical_rect, - glyphs); - else - pango_shape_item (item, - layout->text, layout->length, - layout->log_attrs + state->start_offset, - glyphs, - shape_flags); - - if (state->properties.letter_spacing) - { - PangoGlyphItem glyph_item; - int space_left, space_right; - - glyph_item.item = item; - glyph_item.glyphs = glyphs; - - pango_glyph_item_letter_space (&glyph_item, - layout->text, - layout->log_attrs + state->start_offset, - state->properties.letter_spacing); - - distribute_letter_spacing (state->properties.letter_spacing, &space_left, &space_right); - - glyphs->glyphs[0].geometry.width += space_left; - glyphs->glyphs[0].geometry.x_offset += space_left; - glyphs->glyphs[glyphs->num_glyphs - 1].geometry.width += space_right; - } - - if (state->last_tab.glyphs != NULL) - { - int w; - - g_assert (state->last_tab.glyphs->num_glyphs == 1); - - /* Update the width of the current tab to position this run properly */ - - w = state->last_tab.pos - state->last_tab.width; - - if (state->last_tab.align == PANGO_TAB_RIGHT) - w -= pango_glyph_string_get_width (glyphs); - else if (state->last_tab.align == PANGO_TAB_CENTER) - w -= pango_glyph_string_get_width (glyphs) / 2; - else if (state->last_tab.align == PANGO_TAB_DECIMAL) - { - int width; - gboolean found; - - get_decimal_prefix_width (item, glyphs, layout->text, state->last_tab.decimal, &width, &found); - - w -= width; - } - - state->last_tab.glyphs->glyphs[0].geometry.width = MAX (w, 0); - } - } - - return glyphs; -} - -static void -insert_run (PangoLayoutLine *line, - ParaBreakState *state, - PangoItem *run_item, - PangoGlyphString *glyphs, - gboolean last_run) -{ - PangoLayoutRun *run = g_slice_new (PangoLayoutRun); - - run->item = run_item; - - if (glyphs) - run->glyphs = glyphs; - else if (last_run && state->log_widths_offset == 0 && - !(run_item->analysis.flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN)) - { - run->glyphs = state->glyphs; - state->glyphs = NULL; - } - else - run->glyphs = shape_run (line, state, run_item); - - if (last_run && state->glyphs) - { - pango_glyph_string_free (state->glyphs); - state->glyphs = NULL; - } - - line->runs = g_slist_prepend (line->runs, run); - line->length += run_item->length; - - if (state->last_tab.glyphs && run->glyphs != state->last_tab.glyphs) - { - gboolean found_decimal = FALSE; - int width; - - /* Adjust the tab position so placing further runs will continue to - * maintain the tab placement. In the case of decimal tabs, we are - * done once we've placed the run with the decimal point. - */ - - if (state->last_tab.align == PANGO_TAB_RIGHT) - state->last_tab.width += pango_glyph_string_get_width (run->glyphs); - else if (state->last_tab.align == PANGO_TAB_CENTER) - state->last_tab.width += pango_glyph_string_get_width (run->glyphs) / 2; - else if (state->last_tab.align == PANGO_TAB_DECIMAL) - { - int width; - - get_decimal_prefix_width (run->item, run->glyphs, line->layout->text, state->last_tab.decimal, &width, &found_decimal); - - state->last_tab.width += width; - } - - width = MAX (state->last_tab.pos - state->last_tab.width, 0); - state->last_tab.glyphs->glyphs[0].geometry.width = width; - - if (found_decimal || width == 0) - state->last_tab.glyphs = NULL; - } -} - -static gboolean -break_needs_hyphen (PangoLayout *layout, - ParaBreakState *state, - int pos) -{ - return layout->log_attrs[state->start_offset + pos].break_inserts_hyphen || - layout->log_attrs[state->start_offset + pos].break_removes_preceding; -} - -static int -find_hyphen_width (PangoItem *item) -{ - hb_font_t *hb_font; - hb_codepoint_t glyph; - - if (!item->analysis.font) - return 0; - - /* This is not technically correct, since - * a) we may end up inserting a different hyphen - * b) we should reshape the entire run - * But it is close enough in practice - */ - hb_font = pango_font_get_hb_font (item->analysis.font); - if (hb_font_get_nominal_glyph (hb_font, 0x2010, &glyph) || - hb_font_get_nominal_glyph (hb_font, '-', &glyph)) - return hb_font_get_glyph_h_advance (hb_font, glyph); - - return 0; -} - -static inline void -ensure_hyphen_width (ParaBreakState *state) -{ - if (state->hyphen_width < 0) - { - PangoItem *item = state->items->data; - state->hyphen_width = find_hyphen_width (item); - } -} - -static int -find_break_extra_width (PangoLayout *layout, - ParaBreakState *state, - int pos) -{ - /* Check whether to insert a hyphen, - * or whether we are breaking after one of those - * characters that turn into a hyphen, - * or after a space. - */ - if (layout->log_attrs[state->start_offset + pos].break_inserts_hyphen) - { - ensure_hyphen_width (state); - - if (layout->log_attrs[state->start_offset + pos].break_removes_preceding && pos > 0) - return state->hyphen_width - state->log_widths[state->log_widths_offset + pos - 1]; - else - return state->hyphen_width; - } - else if (pos > 0 && - layout->log_attrs[state->start_offset + pos - 1].is_white) - { - return - state->log_widths[state->log_widths_offset + pos - 1]; - } - - return 0; -} - -#if 0 -# define DEBUG debug -static int pango_layout_line_get_width (PangoLayoutLine *line); -static void -debug (const char *where, PangoLayoutLine *line, ParaBreakState *state) -{ - int line_width = pango_layout_line_get_width (line); - - g_debug ("rem %d + line %d = %d %s", - state->remaining_width, - line_width, - state->remaining_width + line_width, - where); -} -# define DEBUG1(...) g_debug (__VA_ARGS__) -#else -# define DEBUG(where, line, state) do { } while (0) -# define DEBUG1(...) do { } while (0) -#endif - -static inline void -compute_log_widths (PangoLayout *layout, - ParaBreakState *state) -{ - PangoItem *item = state->items->data; - PangoGlyphItem glyph_item = { item, state->glyphs }; - - if (item->num_chars > state->num_log_widths) - { - state->log_widths = g_renew (int, state->log_widths, item->num_chars); - state->num_log_widths = item->num_chars; - } - - pango_glyph_item_get_logical_widths (&glyph_item, layout->text, state->log_widths); -} - -/* If last_tab is set, we've added a tab and remaining_width has been updated to - * account for its origin width, which is last_tab_pos - last_tab_width. shape_run - * updates the tab width, so we need to consider the delta when comparing - * against remaining_width. - */ -static int -tab_width_change (ParaBreakState *state) -{ - if (state->last_tab.glyphs) - return state->last_tab.glyphs->glyphs[0].geometry.width - (state->last_tab.pos - state->last_tab.width); - - return 0; + return layout->width; } -/* Tries to insert as much as possible of the item at the head of - * state->items onto @line. Five results are possible: - * - * %BREAK_NONE_FIT: Couldn't fit anything. - * %BREAK_SOME_FIT: The item was broken in the middle. - * %BREAK_ALL_FIT: Everything fit. - * %BREAK_EMPTY_FIT: Nothing fit, but that was ok, as we can break at the first char. - * %BREAK_LINE_SEPARATOR: Item begins with a line separator. - * - * If @force_fit is %TRUE, then %BREAK_NONE_FIT will never - * be returned, a run will be added even if inserting the minimum amount - * will cause the line to overflow. This is used at the start of a line - * and until we've found at least some place to break. - * - * If @no_break_at_end is %TRUE, then %BREAK_ALL_FIT will never be - * returned even everything fits; the run will be broken earlier, - * or %BREAK_NONE_FIT returned. This is used when the end of the - * run is not a break position. - * - * This function is the core of our line-breaking, and it is long and involved. - * Here is an outline of the algorithm, without all the bookkeeping: - * - * if item appears to fit entirely - * measure it - * if it actually fits - * return BREAK_ALL_FIT +/** + * pango_layout_set_height: + * @layout: a `PangoLayout`. + * @height: the desired height * - * retry_break: - * for each position p in the item - * if adding more is 'obviously' not going to help and we have a breakpoint - * exit the loop - * if p is a possible break position - * if p is 'obviously' going to fit - * bc = p - * else - * measure breaking at p (taking extra break width into account - * if we don't have a break candidate yet - * bc = p - * else - * if p is better than bc - * bc = p + * Sets the height to which the `PangoLayout` should be ellipsized at. * - * if bc does not fit and we can loosen break conditions - * loosen break conditions and retry break + * There are two different behaviors, based on whether @height is positive + * or negative. * - * return bc - */ -static BreakResult -process_item (PangoLayout *layout, - PangoLayoutLine *line, - ParaBreakState *state, - gboolean force_fit, - gboolean no_break_at_end, - gboolean is_last_item) -{ - PangoItem *item = state->items->data; - gboolean shape_set = FALSE; - int width; - int extra_width; - int orig_extra_width; - int length; - int i; - int processing_new_item; - int num_chars; - int orig_width; - PangoWrapMode wrap; - int break_num_chars; - int break_width; - int break_extra_width; - PangoGlyphString *break_glyphs; - PangoFontMetrics *metrics; - int safe_distance; - - DEBUG1 ("process item '%.*s'. Remaining width %d", - item->length, layout->text + item->offset, - state->remaining_width); - - /* We don't want to shape more than necessary, so we keep the results - * of shaping a new item in state->glyphs, state->log_widths. Once - * we break off initial parts of the item, we update state->log_widths_offset - * to take that into account. Note that the widths we calculate from the - * log_widths are an approximation, because a) log_widths are just - * evenly divided for clusters, and b) clusters may change as we - * break in the middle (think ff- i). - * - * We use state->log_widths_offset != 0 to detect if we are dealing - * with the original item, or one that has been chopped off. - */ - if (!state->glyphs) - { - pango_item_get_properties (item, &state->properties); - state->glyphs = shape_run (line, state, item); - state->log_widths_offset = 0; - processing_new_item = TRUE; - } - else - processing_new_item = FALSE; - - /* Only one character has type G_UNICODE_LINE_SEPARATOR in Unicode 5.0; - * update this if that changes. - */ -#define LINE_SEPARATOR 0x2028 - - if (!layout->single_paragraph && - g_utf8_get_char (layout->text + item->offset) == LINE_SEPARATOR && - !should_ellipsize_current_line (layout, state)) - { - insert_run (line, state, item, NULL, TRUE); - state->log_widths_offset += item->num_chars; - - return BREAK_LINE_SEPARATOR; - } - - if (state->remaining_width < 0 && !no_break_at_end) /* Wrapping off */ - { - insert_run (line, state, item, NULL, TRUE); - DEBUG1 ("no wrapping, all-fit"); - return BREAK_ALL_FIT; - } - - if (processing_new_item) - { - width = pango_glyph_string_get_width (state->glyphs); - } - else - { - width = 0; - for (i = 0; i < item->num_chars; i++) - width += state->log_widths[state->log_widths_offset + i]; - } - - if (layout->text[item->offset] == '\t') - { - insert_run (line, state, item, NULL, TRUE); - state->remaining_width -= width; - state->remaining_width = MAX (state->remaining_width, 0); - - DEBUG1 ("tab run, all-fit"); - return BREAK_ALL_FIT; - } - - wrap = layout->wrap; - - if (!no_break_at_end && - can_break_at (layout, state->start_offset + item->num_chars, wrap)) - { - if (processing_new_item) - { - compute_log_widths (layout, state); - processing_new_item = FALSE; - } - - extra_width = find_break_extra_width (layout, state, item->num_chars); - } - else - extra_width = 0; - - if ((width + extra_width <= state->remaining_width || (item->num_chars == 1 && !line->runs) || - (state->last_tab.glyphs && state->last_tab.align != PANGO_TAB_LEFT)) && - !no_break_at_end) - { - PangoGlyphString *glyphs; - - DEBUG1 ("%d + %d <= %d", width, extra_width, state->remaining_width); - glyphs = shape_run (line, state, item); - - width = pango_glyph_string_get_width (glyphs) + tab_width_change (state); - - if (width + extra_width <= state->remaining_width || (item->num_chars == 1 && !line->runs)) - { - insert_run (line, state, item, glyphs, TRUE); - - state->remaining_width -= width; - state->remaining_width = MAX (state->remaining_width, 0); - - DEBUG1 ("early accept '%.*s', all-fit, remaining %d", - item->length, layout->text + item->offset, - state->remaining_width); - return BREAK_ALL_FIT; - } - - /* if it doesn't fit after shaping, discard and proceed to break the item */ - pango_glyph_string_free (glyphs); - } - - /*** From here on, we look for a way to break item ***/ - - orig_width = width; - orig_extra_width = extra_width; - break_width = width; - break_extra_width = extra_width; - break_num_chars = item->num_chars; - wrap = layout->wrap; - break_glyphs = NULL; - - /* Add some safety margin here. If we are farther away from the end of the - * line than this, we don't look carefully at a break possibility. - */ - metrics = pango_font_get_metrics (item->analysis.font, item->analysis.language); - safe_distance = pango_font_metrics_get_approximate_char_width (metrics) * 3; - pango_font_metrics_unref (metrics); - - if (processing_new_item) - { - compute_log_widths (layout, state); - processing_new_item = FALSE; - } - -retry_break: - - for (num_chars = 0, width = 0; num_chars < (no_break_at_end ? item->num_chars : (item->num_chars + 1)); num_chars++) - { - extra_width = find_break_extra_width (layout, state, num_chars); - - /* We don't want to walk the entire item if we can help it, but - * we need to keep going at least until we've found a breakpoint - * that 'works' (as in, it doesn't overflow the budget we have, - * or there is no hope of finding a better one). - * - * We rely on the fact that MIN(width + extra_width, width) is - * monotonically increasing. - */ - - if (MIN (width + extra_width, width) > state->remaining_width + safe_distance && - break_num_chars < item->num_chars) - { - DEBUG1 ("at %d, MIN(%d, %d + %d) > %d + MARGIN, breaking at %d", - num_chars, width, extra_width, width, state->remaining_width, break_num_chars); - break; - } - - /* If there are no previous runs we have to take care to grab at least one char. */ - if (can_break_at (layout, state->start_offset + num_chars, wrap) && - (num_chars > 0 || line->runs)) - { - DEBUG1 ("possible breakpoint: %d, extra_width %d", num_chars, extra_width); - if (num_chars == 0 || - width + extra_width < state->remaining_width - safe_distance) - { - DEBUG1 ("trivial accept"); - break_num_chars = num_chars; - break_width = width; - break_extra_width = extra_width; - } - else - { - int length; - int new_break_width; - PangoItem *new_item; - PangoGlyphString *glyphs; - - length = g_utf8_offset_to_pointer (layout->text + item->offset, num_chars) - (layout->text + item->offset); - - if (num_chars < item->num_chars) - { - new_item = pango_item_split (item, length, num_chars); - - if (break_needs_hyphen (layout, state, num_chars)) - new_item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; - else - new_item->analysis.flags &= ~PANGO_ANALYSIS_FLAG_NEED_HYPHEN; - } - else - new_item = item; - - glyphs = shape_run (line, state, new_item); - - new_break_width = pango_glyph_string_get_width (glyphs) + tab_width_change (state); - - if (num_chars > 0 && - (item != new_item || !is_last_item) && /* We don't collapse space at the very end */ - layout->log_attrs[state->start_offset + num_chars - 1].is_white) - extra_width = - state->log_widths[state->log_widths_offset + num_chars - 1]; - else if (item == new_item && !is_last_item && - break_needs_hyphen (layout, state, num_chars)) - extra_width = state->hyphen_width; - else - extra_width = 0; - - DEBUG1 ("measured breakpoint %d: %d, extra %d", num_chars, new_break_width, extra_width); - - if (new_item != item) - { - pango_item_free (new_item); - pango_item_unsplit (item, length, num_chars); - } - - if (break_num_chars == item->num_chars || - new_break_width + extra_width <= state->remaining_width || - new_break_width + extra_width < break_width + break_extra_width) - { - DEBUG1 ("accept breakpoint %d: %d + %d <= %d + %d", - num_chars, new_break_width, extra_width, break_width, break_extra_width); - DEBUG1 ("replace bp %d by %d", break_num_chars, num_chars); - break_num_chars = num_chars; - break_width = new_break_width; - break_extra_width = extra_width; - - if (break_glyphs) - pango_glyph_string_free (break_glyphs); - break_glyphs = glyphs; - } - else - { - DEBUG1 ("ignore breakpoint %d", num_chars); - pango_glyph_string_free (glyphs); - } - } - } - - DEBUG1 ("bp now %d", break_num_chars); - if (num_chars < item->num_chars) - width += state->log_widths[state->log_widths_offset + num_chars]; - } - - if (wrap == PANGO_WRAP_WORD_CHAR && force_fit && break_width + break_extra_width > state->remaining_width) - { - /* Try again, with looser conditions */ - DEBUG1 ("does not fit, try again with wrap-char"); - wrap = PANGO_WRAP_CHAR; - break_num_chars = item->num_chars; - break_width = orig_width; - break_extra_width = orig_extra_width; - if (break_glyphs) - pango_glyph_string_free (break_glyphs); - break_glyphs = NULL; - goto retry_break; - } - - if (force_fit || break_width + break_extra_width <= state->remaining_width) /* Successfully broke the item */ - { - if (state->remaining_width >= 0) - { - state->remaining_width -= break_width + break_extra_width; - state->remaining_width = MAX (state->remaining_width, 0); - } - - if (break_num_chars == item->num_chars) - { - if (can_break_at (layout, state->start_offset + break_num_chars, wrap) && - break_needs_hyphen (layout, state, break_num_chars)) - item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; - - insert_run (line, state, item, NULL, TRUE); - - if (break_glyphs) - pango_glyph_string_free (break_glyphs); - - DEBUG1 ("all-fit '%.*s', remaining %d", - item->length, layout->text + item->offset, - state->remaining_width); - return BREAK_ALL_FIT; - } - else if (break_num_chars == 0) - { - if (break_glyphs) - pango_glyph_string_free (break_glyphs); - - DEBUG1 ("empty-fit, remaining %d", state->remaining_width); - return BREAK_EMPTY_FIT; - } - else - { - PangoItem *new_item; - - length = g_utf8_offset_to_pointer (layout->text + item->offset, break_num_chars) - (layout->text + item->offset); - - new_item = pango_item_split (item, length, break_num_chars); - - insert_run (line, state, new_item, break_glyphs, FALSE); - - state->log_widths_offset += break_num_chars; - - /* Shaped items should never be broken */ - g_assert (!shape_set); - - DEBUG1 ("some-fit '%.*s', remaining %d", - new_item->length, layout->text + new_item->offset, - state->remaining_width); - return BREAK_SOME_FIT; - } - } - else - { - pango_glyph_string_free (state->glyphs); - state->glyphs = NULL; - - if (break_glyphs) - pango_glyph_string_free (break_glyphs); - - DEBUG1 ("none-fit, remaining %d", state->remaining_width); - return BREAK_NONE_FIT; - } -} - -/* The resolved direction for the line is always one - * of LTR/RTL; not a week or neutral directions + * See [property@Pango.Layout:height] for details. */ -static void -line_set_resolved_dir (PangoLayoutLine *line, - PangoDirection direction) -{ - switch (direction) - { - default: - case PANGO_DIRECTION_LTR: - case PANGO_DIRECTION_TTB_RTL: - case PANGO_DIRECTION_WEAK_LTR: - case PANGO_DIRECTION_NEUTRAL: - line->resolved_dir = PANGO_DIRECTION_LTR; - break; - case PANGO_DIRECTION_RTL: - case PANGO_DIRECTION_WEAK_RTL: - case PANGO_DIRECTION_TTB_LTR: - line->resolved_dir = PANGO_DIRECTION_RTL; - break; - } - - /* The direction vs. gravity dance: - * - If gravity is SOUTH, leave direction untouched. - * - If gravity is NORTH, switch direction. - * - If gravity is EAST, set to LTR, as - * it's a clockwise-rotated layout, so the rotated - * top is unrotated left. - * - If gravity is WEST, set to RTL, as - * it's a counter-clockwise-rotated layout, so the rotated - * top is unrotated right. - * - * A similar dance is performed in pango-context.c: - * itemize_state_add_character(). Keep in synch. - */ - switch (pango_context_get_gravity (line->layout->context)) - { - default: - case PANGO_GRAVITY_AUTO: - case PANGO_GRAVITY_SOUTH: - break; - case PANGO_GRAVITY_NORTH: - line->resolved_dir = PANGO_DIRECTION_LTR - + PANGO_DIRECTION_RTL - - line->resolved_dir; - break; - case PANGO_GRAVITY_EAST: - /* This is in fact why deprecated TTB_RTL is LTR */ - line->resolved_dir = PANGO_DIRECTION_LTR; - break; - case PANGO_GRAVITY_WEST: - /* This is in fact why deprecated TTB_LTR is RTL */ - line->resolved_dir = PANGO_DIRECTION_RTL; - break; - } -} - -static gboolean -should_ellipsize_current_line (PangoLayout *layout, - ParaBreakState *state) -{ - if (G_LIKELY (layout->ellipsize == PANGO_ELLIPSIZE_NONE || layout->width < 0)) - return FALSE; - - if (layout->height >= 0) - { - /* state->remaining_height is height of layout left */ - - /* if we can't stuff two more lines at the current guess of line height, - * the line we are going to produce is going to be the last line - */ - return state->line_height * 2 > state->remaining_height; - } - else - { - /* -layout->height is number of lines per paragraph to show */ - return state->line_of_par == - layout->height; - } -} - -static void -add_line (PangoLayoutLine *line, - ParaBreakState *state) -{ - PangoLayout *layout = line->layout; - - /* we prepend, then reverse the list later */ - layout->lines = g_slist_prepend (layout->lines, line); - layout->line_count++; - - if (layout->height >= 0) - { - PangoRectangle logical_rect; - pango_layout_line_get_extents (line, NULL, &logical_rect); - state->remaining_height -= logical_rect.height; - state->remaining_height -= layout->spacing; - state->line_height = logical_rect.height; - } -} - -static void -process_line (PangoLayout *layout, - ParaBreakState *state) -{ - PangoLayoutLine *line; - - gboolean have_break = FALSE; /* If we've seen a possible break yet */ - int break_remaining_width = 0; /* Remaining width before adding run with break */ - int break_start_offset = 0; /* Start offset before adding run with break */ - GSList *break_link = NULL; /* Link holding run before break */ - gboolean wrapped = FALSE; /* If we had to wrap the line */ - - line = pango_layout_line_new (layout); - line->start_index = state->line_start_index; - line->is_paragraph_start = state->line_of_par == 1; - line_set_resolved_dir (line, state->base_dir); - - state->line_width = layout->width; - if (state->line_width >= 0 && layout->alignment != PANGO_ALIGN_CENTER) - { - if (line->is_paragraph_start && layout->indent >= 0) - state->line_width -= layout->indent; - else if (!line->is_paragraph_start && layout->indent < 0) - state->line_width += layout->indent; - - if (state->line_width < 0) - state->line_width = 0; - } - - if (G_UNLIKELY (should_ellipsize_current_line (layout, state))) - state->remaining_width = -1; - else - state->remaining_width = state->line_width; - - state->last_tab.glyphs = NULL; - state->last_tab.index = 0; - state->last_tab.align = PANGO_TAB_LEFT; - - DEBUG ("starting to fill line", line, state); - - while (state->items) - { - PangoItem *item = state->items->data; - BreakResult result; - int old_num_chars; - int old_remaining_width; - gboolean first_item_in_line; - gboolean last_item_in_line; - - old_num_chars = item->num_chars; - old_remaining_width = state->remaining_width; - first_item_in_line = line->runs == NULL; - last_item_in_line = state->items->next == NULL; - - result = process_item (layout, line, state, !have_break, FALSE, last_item_in_line); - - switch (result) - { - case BREAK_ALL_FIT: - if (layout->text[item->offset] != '\t' && - can_break_in (layout, state->start_offset, old_num_chars, !first_item_in_line)) - { - have_break = TRUE; - break_remaining_width = old_remaining_width; - break_start_offset = state->start_offset; - break_link = line->runs->next; - DEBUG1 ("all-fit, have break"); - } - - state->items = g_list_delete_link (state->items, state->items); - state->start_offset += old_num_chars; - - break; - - case BREAK_EMPTY_FIT: - wrapped = TRUE; - goto done; - - case BREAK_SOME_FIT: - state->start_offset += old_num_chars - item->num_chars; - wrapped = TRUE; - goto done; - - case BREAK_NONE_FIT: - /* Back up over unused runs to run where there is a break */ - while (line->runs && line->runs != break_link) - { - PangoLayoutRun *run = line->runs->data; - - /* If we uninsert the current tab run, - * we need to reset the tab state - */ - if (run->glyphs == state->last_tab.glyphs) - { - state->last_tab.glyphs = NULL; - state->last_tab.index = 0; - state->last_tab.align = PANGO_TAB_LEFT; - } - - state->items = g_list_prepend (state->items, uninsert_run (line)); - } - - state->start_offset = break_start_offset; - state->remaining_width = break_remaining_width; - last_item_in_line = state->items->next == NULL; - - /* Reshape run to break */ - item = state->items->data; - - old_num_chars = item->num_chars; - result = process_item (layout, line, state, TRUE, TRUE, last_item_in_line); - g_assert (result == BREAK_SOME_FIT || result == BREAK_EMPTY_FIT); - - state->start_offset += old_num_chars - item->num_chars; - - wrapped = TRUE; - goto done; - - case BREAK_LINE_SEPARATOR: - state->items = g_list_delete_link (state->items, state->items); - state->start_offset += old_num_chars; - /* A line-separate is just a forced break. Set wrapped, so we do justification */ - wrapped = TRUE; - goto done; - - default: - break; - } - } - - done: - pango_layout_line_postprocess (line, state, wrapped); - DEBUG1 ("line %d done. remaining %d", state->line_of_par, state->remaining_width); - add_line (line, state); - state->line_of_par++; - state->line_start_index += line->length; - state->line_start_offset = state->start_offset; -} - -static void -get_items_log_attrs (const char *text, - int start, - int length, - GList *items, - PangoAttrList *attrs, - PangoLogAttr *log_attrs, - int log_attrs_len) -{ - int offset = 0; - GList *l; - - pango_default_break (text + start, length, NULL, log_attrs, log_attrs_len); - - for (l = items; l; l = l->next) - { - PangoItem *item = l->data; - g_assert (item->offset <= start + length); - g_assert (item->length <= (start + length) - item->offset); - - pango_tailor_break (text + item->offset, - item->length, - &item->analysis, - -1, - log_attrs + offset, - item->num_chars + 1); - - offset += item->num_chars; - } - - if (attrs && items) - { - PangoItem *item = items->data; - pango_attr_break (text + start, length, attrs, item->offset, log_attrs, log_attrs_len); - } -} - -static PangoAttrList * -pango_layout_get_effective_attributes (PangoLayout *layout) -{ - PangoAttrList *attrs; - - if (layout->attrs) - attrs = pango_attr_list_copy (layout->attrs); - else - attrs = NULL; - - if (layout->font_desc) - { - PangoAttribute *attr = pango_attr_font_desc_new (layout->font_desc); - - if (!attrs) - attrs = pango_attr_list_new (); - - pango_attr_list_insert_before (attrs, attr); - } - - if (layout->single_paragraph) - { - PangoAttribute *attr = pango_attr_show_new (PANGO_SHOW_LINE_BREAKS); - - if (!attrs) - attrs = pango_attr_list_new (); - - pango_attr_list_insert_before (attrs, attr); - } - - return attrs; -} - -static gboolean -affects_itemization (PangoAttribute *attr, - gpointer data) -{ - switch ((int)attr->klass->type) - { - /* These affect font selection */ - case PANGO_ATTR_LANGUAGE: - case PANGO_ATTR_FAMILY: - case PANGO_ATTR_STYLE: - case PANGO_ATTR_WEIGHT: - case PANGO_ATTR_VARIANT: - case PANGO_ATTR_STRETCH: - case PANGO_ATTR_SIZE: - case PANGO_ATTR_FONT_DESC: - case PANGO_ATTR_SCALE: - case PANGO_ATTR_FALLBACK: - case PANGO_ATTR_ABSOLUTE_SIZE: - case PANGO_ATTR_GRAVITY: - case PANGO_ATTR_GRAVITY_HINT: - case PANGO_ATTR_FONT_SCALE: - /* These need to be constant across runs */ - case PANGO_ATTR_LETTER_SPACING: - case PANGO_ATTR_SHAPE: - case PANGO_ATTR_RISE: - case PANGO_ATTR_BASELINE_SHIFT: - case PANGO_ATTR_LINE_HEIGHT: - case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: - case PANGO_ATTR_TEXT_TRANSFORM: - return TRUE; - default: - return FALSE; - } -} - -static gboolean -affects_break_or_shape (PangoAttribute *attr, - gpointer data) -{ - switch ((int)attr->klass->type) - { - /* Affects breaks */ - case PANGO_ATTR_ALLOW_BREAKS: - case PANGO_ATTR_WORD: - case PANGO_ATTR_SENTENCE: - /* Affects shaping */ - case PANGO_ATTR_INSERT_HYPHENS: - case PANGO_ATTR_FONT_FEATURES: - case PANGO_ATTR_SHOW: - return TRUE; - default: - return FALSE; - } -} - -static void -apply_attributes_to_items (GList *items, - PangoAttrList *attrs) -{ - GList *l; - PangoAttrIterator iter; - - if (!attrs) - return; - - _pango_attr_list_get_iterator (attrs, &iter); - - for (l = items; l; l = l->next) - { - PangoItem *item = l->data; - pango_item_apply_attrs (item, &iter); - } - - _pango_attr_iterator_destroy (&iter); -} - -static void -apply_attributes_to_runs (PangoLayout *layout, - PangoAttrList *attrs) -{ - GSList *ll; - - if (!attrs) - return; - - for (ll = layout->lines; ll; ll = ll->next) - { - PangoLayoutLine *line = ll->data; - GSList *old_runs = g_slist_reverse (line->runs); - GSList *rl; - - line->runs = NULL; - for (rl = old_runs; rl; rl = rl->next) - { - PangoGlyphItem *glyph_item = rl->data; - GSList *new_runs; - - new_runs = pango_glyph_item_apply_attrs (glyph_item, - layout->text, - attrs); - - line->runs = g_slist_concat (new_runs, line->runs); - } - - g_slist_free (old_runs); - } -} - -static int -compute_n_chars (PangoLayoutLine *line) -{ - int n_chars = 0; - - for (GSList *l = line->runs; l; l = l->next) - { - PangoGlyphItem *run = l->data; - n_chars += run->item->num_chars; - } - - return n_chars; -} - -static void -pango_layout_line_check_invariants (PangoLayoutLine *line, - const char *text) -{ - int n_chars; - - n_chars = compute_n_chars (line); - - /* Check that byte and char positions agree */ - g_assert (g_utf8_strlen (text + line->start_index, line->length) == n_chars); - g_assert (g_utf8_offset_to_pointer (text + line->start_index, n_chars) == text + line->start_index + line->length); - - /* Check that runs are sane */ - if (line->runs) - { - int run_min, run_max; - - run_min = G_MAXINT; - run_max = 0; - for (GSList *l = line->runs; l; l = l->next) - { - PangoGlyphItem *run = l->data; - - run_min = MIN (run_min, run->item->offset); - run_max = MAX (run_max, run->item->offset + run->item->length); - } - - g_assert (run_min == line->start_index); - g_assert (run_max == line->start_index + line->length); - } -} - - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -static void -pango_layout_check_lines (PangoLayout *layout) +void +pango_layout_set_height (PangoLayout *layout, + int height) { - const char *start; - gboolean done = FALSE; - int start_offset; - PangoAttrList *attrs; - PangoAttrList *itemize_attrs; - PangoAttrList *shape_attrs; - PangoAttrIterator iter; - PangoDirection prev_base_dir = PANGO_DIRECTION_NEUTRAL; - PangoDirection base_dir = PANGO_DIRECTION_NEUTRAL; - ParaBreakState state; - gboolean need_log_attrs; - - check_context_changed (layout); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (G_LIKELY (layout->lines)) + if (layout->height == height) return; - /* For simplicity, we make sure at this point that layout->text - * is non-NULL even if it is zero length - */ - if (G_UNLIKELY (!layout->text)) - pango_layout_set_text (layout, NULL, 0); - - attrs = pango_layout_get_effective_attributes (layout); - if (attrs) - { - shape_attrs = pango_attr_list_filter (attrs, affects_break_or_shape, NULL); - itemize_attrs = pango_attr_list_filter (attrs, affects_itemization, NULL); - - if (itemize_attrs) - _pango_attr_list_get_iterator (itemize_attrs, &iter); - } - else - { - shape_attrs = NULL; - itemize_attrs = NULL; - } - - if (!layout->log_attrs) - { - layout->log_attrs = g_new0 (PangoLogAttr, layout->n_chars + 1); - need_log_attrs = TRUE; - } - else - { - need_log_attrs = FALSE; - } - - start_offset = 0; - start = layout->text; - - /* Find the first strong direction of the text */ - if (layout->auto_dir) - { - prev_base_dir = pango_find_base_dir (layout->text, layout->length); - if (prev_base_dir == PANGO_DIRECTION_NEUTRAL) - prev_base_dir = pango_context_get_base_dir (layout->context); - } - else - base_dir = pango_context_get_base_dir (layout->context); - - /* these are only used if layout->height >= 0 */ - state.remaining_height = layout->height; - state.line_height = -1; - if (layout->height >= 0) - { - PangoRectangle logical = { 0, }; - int height = 0; - pango_layout_get_empty_extents_and_height_at_index (layout, 0, &logical, TRUE, &height); - state.line_height = layout->line_spacing == 0.0 ? logical.height : layout->line_spacing * height; - } - - state.log_widths = NULL; - state.num_log_widths = 0; - state.baseline_shifts = NULL; + layout->height = height; - DEBUG1 ("START layout"); - do - { - int delim_len; - const char *end; - int delimiter_index, next_para_index; - - if (layout->single_paragraph) - { - delimiter_index = layout->length; - next_para_index = layout->length; - } - else - { - pango_find_paragraph_boundary (start, - (layout->text + layout->length) - start, - &delimiter_index, - &next_para_index); - } - - g_assert (next_para_index >= delimiter_index); - - if (layout->auto_dir) - { - base_dir = pango_find_base_dir (start, delimiter_index); - - /* Propagate the base direction for neutral paragraphs */ - if (base_dir == PANGO_DIRECTION_NEUTRAL) - base_dir = prev_base_dir; - else - prev_base_dir = base_dir; - } - - end = start + delimiter_index; - - delim_len = next_para_index - delimiter_index; - - if (end == (layout->text + layout->length)) - done = TRUE; - - g_assert (end <= (layout->text + layout->length)); - g_assert (start <= (layout->text + layout->length)); - g_assert (delim_len < 4); /* PS is 3 bytes */ - g_assert (delim_len >= 0); - - state.attrs = itemize_attrs; - state.items = pango_itemize_with_font (layout->context, - base_dir, - layout->text, - start - layout->text, - end - start, - itemize_attrs, - itemize_attrs ? &iter : NULL, - NULL); - - apply_attributes_to_items (state.items, shape_attrs); - - if (need_log_attrs) - get_items_log_attrs (layout->text, - start - layout->text, - delimiter_index + delim_len, - state.items, - shape_attrs, - layout->log_attrs + start_offset, - layout->n_chars + 1 - start_offset); - - state.items = pango_itemize_post_process_items (layout->context, - layout->text, - layout->log_attrs + start_offset, - state.items); - - state.base_dir = base_dir; - state.line_of_par = 1; - state.start_offset = start_offset; - state.line_start_offset = start_offset; - state.line_start_index = start - layout->text; - - state.glyphs = NULL; - - /* for deterministic bug hunting's sake set everything! */ - state.line_width = -1; - state.remaining_width = -1; - state.log_widths_offset = 0; - - state.hyphen_width = -1; - - if (state.items) - { - while (state.items) - process_line (layout, &state); - } - else - { - PangoLayoutLine *empty_line; - - empty_line = pango_layout_line_new (layout); - empty_line->start_index = state.line_start_index; - empty_line->is_paragraph_start = TRUE; - line_set_resolved_dir (empty_line, base_dir); - - add_line (empty_line, &state); - } - - if (layout->height >= 0 && state.remaining_height < state.line_height) - done = TRUE; - - if (!done) - start_offset += pango_utf8_strlen (start, (end - start) + delim_len); - - start = end + delim_len; - } - while (!done); - - g_free (state.log_widths); - g_list_free_full (state.baseline_shifts, g_free); - - apply_attributes_to_runs (layout, attrs); - layout->lines = g_slist_reverse (layout->lines); - - if (itemize_attrs) - { - pango_attr_list_unref (itemize_attrs); - _pango_attr_iterator_destroy (&iter); - } - - pango_attr_list_unref (shape_attrs); - pango_attr_list_unref (attrs); - - for (GSList *l = layout->lines; l; l = l->next) - { - PangoLayoutLine *line = l->data; - pango_layout_line_check_invariants (line, layout->text); - } - - int w, h; - pango_layout_get_size (layout, &w, &h); - DEBUG1 ("DONE %d %d", w, h); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_HEIGHT]); + layout_changed (layout); } -#pragma GCC diagnostic pop - /** - * pango_layout_line_ref: - * @line: (nullable): a `PangoLayoutLine` + * pango_layout_get_height: + * @layout: a `PangoLayout` * - * Increase the reference count of a `PangoLayoutLine` by one. + * Gets the height to which the lines of the layout should ellipsize. * - * Return value: the line passed in. + * See [property@Pango.Layout:height] for details. * - * Since: 1.10 + * Return value: the height */ -PangoLayoutLine * -pango_layout_line_ref (PangoLayoutLine *line) +int +pango_layout_get_height (PangoLayout *layout) { - PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), -1); - if (line == NULL) - return NULL; - - g_atomic_int_inc ((int *) &private->ref_count); - - return line; + return layout->height; } /** - * pango_layout_line_unref: - * @line: a `PangoLayoutLine` + * pango_layout_set_tabs: + * @layout: a `PangoLayout` + * @tabs: (nullable): a `PangoTabArray` * - * Decrease the reference count of a `PangoLayoutLine` by one. + * Sets the tabs to use for @layout, overriding the default tabs. * - * If the result is zero, the line and all associated memory - * will be freed. + * See [method@Pango.LineBreaker.set_tabs] for details. */ void -pango_layout_line_unref (PangoLayoutLine *line) +pango_layout_set_tabs (PangoLayout *layout, + PangoTabArray *tabs) { - PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line; + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (line == NULL) + if (layout->tabs == tabs) return; - g_return_if_fail (private->ref_count > 0); - - if (g_atomic_int_dec_and_test ((int *) &private->ref_count)) - { - g_slist_foreach (line->runs, (GFunc)free_run, GINT_TO_POINTER (1)); - g_slist_free (line->runs); - g_slice_free (PangoLayoutLinePrivate, private); - } -} - -G_DEFINE_BOXED_TYPE (PangoLayoutLine, pango_layout_line, - pango_layout_line_ref, - pango_layout_line_unref); + g_clear_pointer (&layout->tabs, pango_tab_array_free); + layout->tabs = pango_tab_array_copy (tabs); -/** - * pango_layout_line_get_start_index: - * @line: a `PangoLayoutLine` - * - * Returns the start index of the line, as byte index - * into the text of the layout. - * - * Returns: the start index of the line - * - * Since: 1.50 - */ -int -pango_layout_line_get_start_index (PangoLayoutLine *line) -{ - return line->start_index; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TABS]); + layout_changed (layout); } /** - * pango_layout_line_get_length: - * @line: a `PangoLayoutLine` + * pango_layout_get_tabs: + * @layout: a `PangoLayout` * - * Returns the length of the line, in bytes. + * Gets the current `PangoTabArray` used by this layout. * - * Returns: the length of the line + * If no `PangoTabArray` has been set, then the default tabs are + * in use and %NULL is returned. Default tabs are every 8 spaces. * - * Since: 1.50 + * Return value: (transfer none) (nullable): the tabs for this layout */ -int -pango_layout_line_get_length (PangoLayoutLine *line) +PangoTabArray * +pango_layout_get_tabs (PangoLayout *layout) { - return line->length; -} + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); -/** - * pango_layout_line_is_paragraph_start: - * @line: a `PangoLayoutLine` - * - * Returns whether this is the first line of the paragraph. - * - * Returns: %TRUE if this is the first line - * - * Since: 1.50 - */ -gboolean -pango_layout_line_is_paragraph_start (PangoLayoutLine *line) -{ - return line->is_paragraph_start; + return layout->tabs; } /** - * pango_layout_line_get_resolved_direction: - * @line: a `PangoLayoutLine` - * - * Returns the resolved direction of the line. - * - * Returns: the resolved direction of the line - * - * Since: 1.50 - */ -PangoDirection -pango_layout_line_get_resolved_direction (PangoLayoutLine *line) -{ - return (PangoDirection) line->resolved_dir; -} - -/** - * pango_layout_line_x_to_index: - * @line: a `PangoLayoutLine` - * @x_pos: the X offset (in Pango units) from the left edge of the line. - * @index_: (out): location to store calculated byte index for the grapheme - * in which the user clicked - * @trailing: (out): location to store an 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 leading edge of the grapheme. + * pango_layout_set_single_paragraph: + * @layout: a `PangoLayout` + * @single_paragraph: the new setting * - * Converts from x offset to the byte index of the corresponding character - * within the text of the layout. + * Sets the single paragraph mode of @layout. * - * If @x_pos is outside the line, @index_ and @trailing will point to the very - * first or very last position in the line. This determination is based on the - * resolved direction of the paragraph; for example, if the resolved direction - * is right-to-left, then an X position to the right of the line (after it) - * results in 0 being stored in @index_ and @trailing. An X position to the - * left of the line results in @index_ pointing to the (logical) last grapheme - * in the line and @trailing being set to the number of characters in that - * grapheme. The reverse is true for a left-to-right line. + * If @single_paragraph is `TRUE`, do not treat newlines and similar + * characters as paragraph separators; instead, keep all text in a + * single paragraph, and display a glyph for paragraph separator + * characters. * - * Return value: %FALSE if @x_pos was outside the line, %TRUE if inside - */ -gboolean -pango_layout_line_x_to_index (PangoLayoutLine *line, - int x_pos, - int *index, - int *trailing) -{ - GSList *tmp_list; - gint start_pos = 0; - gint first_index = 0; /* line->start_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 */ - PangoLayout *layout; - gint last_trailing; - gboolean suppress_last_trailing; - - g_return_val_if_fail (LINE_IS_VALID (line), FALSE); - - layout = line->layout; - - /* Find the last index in the line - */ - first_index = line->start_index; - - if (line->length == 0) - { - if (index) - *index = first_index; - if (trailing) - *trailing = 0; - - return FALSE; - } - - 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; - 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 of cursor (etc) - * indices and not the trailing flag, then the trailing index of the - * last character on a wrapped line is identical to the leading - * index of the next line. So, we fake it and set the trailing flag - * to zero. - * - * That is, if the text is "now is the time", and is broken between - * 'now' and 'is' - * - * Then when the cursor is actually at: - * - * n|o|w| |i|s| - * ^ - * we lie and say it is at: - * - * n|o|w| |i|s| - * ^ - * - * So the cursor won't appear on the next line before 'the'. - * - * Actually, any program keeping cursor - * positions with wrapped lines should distinguish leading and - * trailing cursors. - */ - tmp_list = layout->lines; - while (tmp_list->data != line) - tmp_list = tmp_list->next; - - if (tmp_list->next && - line->start_index + line->length == ((PangoLayoutLine *)tmp_list->next->data)->start_index) - suppress_last_trailing = TRUE; - else - suppress_last_trailing = FALSE; - - if (x_pos < 0) - { - /* pick the leftmost char */ - if (index) - *index = (line->resolved_dir == PANGO_DIRECTION_LTR) ? first_index : last_index; - /* and its leftmost edge */ - if (trailing) - *trailing = (line->resolved_dir == PANGO_DIRECTION_LTR || suppress_last_trailing) ? 0 : last_trailing; - - return FALSE; - } - - tmp_list = line->runs; - while (tmp_list) - { - PangoLayoutRun *run = tmp_list->data; - int logical_width; - - logical_width = pango_glyph_string_get_width (run->glyphs); - - if (x_pos >= start_pos && x_pos < start_pos + logical_width) - { - int offset; - gboolean char_trailing; - int grapheme_start_index; - int grapheme_start_offset; - int grapheme_end_offset; - int pos; - int char_index; - - pango_glyph_string_x_to_index (run->glyphs, - layout->text + run->item->offset, run->item->length, - &run->item->analysis, - x_pos - start_pos, - &pos, &char_trailing); - - char_index = run->item->offset + pos; - - /* Convert from characters to graphemes */ - - offset = g_utf8_pointer_to_offset (layout->text, layout->text + char_index); - - grapheme_start_offset = offset; - grapheme_start_index = char_index; - while (grapheme_start_offset > first_offset && - !layout->log_attrs[grapheme_start_offset].is_cursor_position) - { - grapheme_start_index = g_utf8_prev_char (layout->text + grapheme_start_index) - layout->text; - grapheme_start_offset--; - } - - grapheme_end_offset = offset; - do - { - grapheme_end_offset++; - } - while (grapheme_end_offset < end_offset && - !layout->log_attrs[grapheme_end_offset].is_cursor_position); - - if (index) - *index = grapheme_start_index; - - if (trailing) - { - if ((grapheme_end_offset == end_offset && suppress_last_trailing) || - offset + char_trailing <= (grapheme_start_offset + grapheme_end_offset) / 2) - *trailing = 0; - else - *trailing = grapheme_end_offset - grapheme_start_offset; - } - - return TRUE; - } - - start_pos += logical_width; - tmp_list = tmp_list->next; - } - - /* pick the rightmost char */ - if (index) - *index = (line->resolved_dir == PANGO_DIRECTION_LTR) ? last_index : first_index; - - /* and its rightmost edge */ - if (trailing) - *trailing = (line->resolved_dir == PANGO_DIRECTION_LTR && !suppress_last_trailing) ? last_trailing : 0; - - return FALSE; -} - -static int -pango_layout_line_get_width (PangoLayoutLine *line) -{ - int width = 0; - GSList *tmp_list = line->runs; - - while (tmp_list) - { - PangoLayoutRun *run = tmp_list->data; - - width += pango_glyph_string_get_width (run->glyphs); - - tmp_list = tmp_list->next; - } - - return width; -} - -/** - * pango_layout_line_get_x_ranges: - * @line: a `PangoLayoutLine` - * @start_index: Start byte index of the logical range. If this value - * is less than the start index for the line, then the first range - * will extend all the way to the leading edge of the layout. Otherwise, - * it will start at the leading edge of the first character. - * @end_index: Ending byte index of the logical range. If this value is - * greater than the end index for the line, then the last range will - * extend all the way to the trailing edge of the layout. Otherwise, - * it will end at the trailing edge of the last character. - * @ranges: (out) (array length=n_ranges) (transfer full): location to - * store a pointer to an array of ranges. The array will be of length - * `2*n_ranges`, with each range starting at `(*ranges)[2*n]` and of - * width `(*ranges)[2*n + 1] - (*ranges)[2*n]`. This array must be freed - * with g_free(). The coordinates are relative to the layout and are in - * Pango units. - * @n_ranges: The number of ranges stored in @ranges + * Used when you want to allow editing of newlines on a single text line. * - * Gets a list of visual ranges corresponding to a given logical range. - * - * This list is not necessarily minimal - there may be consecutive - * ranges which are adjacent. The ranges will be sorted from left to - * right. The ranges are with respect to the left edge of the entire - * layout, not with respect to the line. + * The default value is %FALSE. */ void -pango_layout_line_get_x_ranges (PangoLayoutLine *line, - int start_index, - int end_index, - int **ranges, - int *n_ranges) -{ - gint line_start_index = 0; - GSList *tmp_list; - int range_count = 0; - int accumulated_width = 0; - int x_offset; - int width, line_width; - PangoAlignment alignment; - - g_return_if_fail (line != NULL); - g_return_if_fail (line->layout != NULL); - g_return_if_fail (start_index <= end_index); - - alignment = get_alignment (line->layout, line); - - width = line->layout->width; - if (width == -1 && alignment != PANGO_ALIGN_LEFT) - { - PangoRectangle logical_rect; - pango_layout_get_extents (line->layout, NULL, &logical_rect); - width = logical_rect.width; - } - - /* FIXME: The computations here could be optimized, by moving the - * computations of the x_offset after we go through and figure - * out where each range is. - */ - - { - PangoRectangle logical_rect; - pango_layout_line_get_extents (line, NULL, &logical_rect); - line_width = logical_rect.width; - } - - get_x_offset (line->layout, line, width, line_width, &x_offset); - - line_start_index = line->start_index; - - /* Allocate the maximum possible size */ - if (ranges) - *ranges = g_new (int, 2 * (2 + g_slist_length (line->runs))); - - if (x_offset > 0 && - ((line->resolved_dir == PANGO_DIRECTION_LTR && start_index < line_start_index) || - (line->resolved_dir == PANGO_DIRECTION_RTL && end_index > line_start_index + line->length))) - { - if (ranges) - { - (*ranges)[2*range_count] = 0; - (*ranges)[2*range_count + 1] = x_offset; - } - - range_count ++; - } - - tmp_list = line->runs; - while (tmp_list) - { - PangoLayoutRun *run = (PangoLayoutRun *)tmp_list->data; - - if ((start_index < run->item->offset + run->item->length && - end_index > run->item->offset)) - { - if (ranges) - { - 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); - - /* Back the end_index off one since we want to find the trailing edge of the preceding character */ - - run_end_index = g_utf8_prev_char (line->layout->text + run_end_index) - line->layout->text; - - /* 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); - } - - range_count++; - } - - if (tmp_list->next) - accumulated_width += pango_glyph_string_get_width (run->glyphs); - - tmp_list = tmp_list->next; - } - - if (x_offset + line_width < line->layout->width && - ((line->resolved_dir == PANGO_DIRECTION_LTR && end_index > line_start_index + line->length) || - (line->resolved_dir == PANGO_DIRECTION_RTL && start_index < line_start_index))) - { - if (ranges) - { - (*ranges)[2*range_count] = x_offset + line_width; - (*ranges)[2*range_count + 1] = line->layout->width; - } - - range_count ++; - } - - if (n_ranges) - *n_ranges = range_count; -} - -static void -pango_layout_get_empty_extents_and_height_at_index (PangoLayout *layout, - int index, - PangoRectangle *logical_rect, - gboolean apply_line_height, - int *height) -{ - if (logical_rect) - { - PangoFont *font; - PangoFontDescription *font_desc = NULL; - gboolean free_font_desc = FALSE; - double line_height_factor = 0.0; - int absolute_line_height = 0; - - font_desc = pango_context_get_font_description (layout->context); - - if (layout->font_desc) - { - font_desc = pango_font_description_copy_static (font_desc); - pango_font_description_merge (font_desc, layout->font_desc, TRUE); - free_font_desc = TRUE; - } - - /* Find the font description for this line - */ - if (layout->attrs) - { - PangoAttrIterator iter; - int start, end; - - _pango_attr_list_get_iterator (layout->attrs, &iter); - - do - { - pango_attr_iterator_range (&iter, &start, &end); - - if (start <= index && index < end) - { - PangoAttribute *attr; - - if (!free_font_desc) - { - font_desc = pango_font_description_copy_static (font_desc); - free_font_desc = TRUE; - } - - pango_attr_iterator_get_font (&iter, font_desc, NULL, NULL); - - attr = pango_attr_iterator_get (&iter, PANGO_ATTR_LINE_HEIGHT); - if (attr) - line_height_factor = ((PangoAttrFloat *)attr)->value; - - attr = pango_attr_iterator_get (&iter, PANGO_ATTR_ABSOLUTE_LINE_HEIGHT); - if (attr) - absolute_line_height = ((PangoAttrInt *)attr)->value; - - break; - } - - } - while (pango_attr_iterator_next (&iter)); - - _pango_attr_iterator_destroy (&iter); - } - - font = pango_context_load_font (layout->context, font_desc); - if (font) - { - PangoFontMetrics *metrics; - - metrics = pango_font_get_metrics (font, - pango_context_get_language (layout->context)); - - if (metrics) - { - logical_rect->y = - pango_font_metrics_get_ascent (metrics); - logical_rect->height = - logical_rect->y + pango_font_metrics_get_descent (metrics); - if (height) - *height = pango_font_metrics_get_height (metrics); - - pango_font_metrics_unref (metrics); - - if (apply_line_height && - (absolute_line_height != 0 || line_height_factor != 0.0)) - { - int line_height, leading; - - line_height = MAX (absolute_line_height, ceilf (line_height_factor * logical_rect->height)); - - leading = line_height - logical_rect->height; - logical_rect->y -= leading / 2; - logical_rect->height += leading; - } - } - else - { - logical_rect->y = 0; - logical_rect->height = 0; - } - g_object_unref (font); - } - else - { - logical_rect->y = 0; - logical_rect->height = 0; - } - - if (free_font_desc) - pango_font_description_free (font_desc); - - logical_rect->x = 0; - logical_rect->width = 0; - } -} - -void pango_layout_run_get_extents_and_height (PangoLayoutRun *run, - PangoRectangle *run_ink, - PangoRectangle *run_logical, - PangoRectangle *line_logical, - int *height); - -void -pango_layout_run_get_extents_and_height (PangoLayoutRun *run, - PangoRectangle *run_ink, - PangoRectangle *run_logical, - PangoRectangle *line_logical, - int *height) +pango_layout_set_single_paragraph (PangoLayout *layout, + gboolean single_paragraph) { - PangoRectangle logical; - ItemProperties properties; - PangoFontMetrics *metrics = NULL; - gboolean has_underline; - gboolean has_overline; - int y_offset; - - if (G_UNLIKELY (!run_ink && !run_logical && !line_logical && !height)) - return; - - pango_item_get_properties (run->item, &properties); - - has_underline = properties.uline_single || properties.uline_double || - properties.uline_low || properties.uline_error; - has_overline = properties.oline_single; - - if (!run_logical && (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)) - run_logical = &logical; - - if (!run_logical && (has_underline || has_overline || properties.strikethrough)) - run_logical = &logical; - - if (!run_logical && line_logical) - run_logical = &logical; - - if (properties.shape_set) - _pango_shape_get_extents (run->item->num_chars, - properties.shape_ink_rect, - properties.shape_logical_rect, - run_ink, run_logical); - else - pango_glyph_string_extents (run->glyphs, run->item->analysis.font, - run_ink, run_logical); - - if (run_ink && (has_underline || has_overline || properties.strikethrough)) - { - int underline_thickness; - int underline_position; - int strikethrough_thickness; - int strikethrough_position; - int new_pos; - - if (!metrics) - metrics = pango_font_get_metrics (run->item->analysis.font, - run->item->analysis.language); - - underline_thickness = pango_font_metrics_get_underline_thickness (metrics); - underline_position = pango_font_metrics_get_underline_position (metrics); - strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics); - strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics); - - /* the underline/strikethrough takes x,width of logical_rect. reflect - * that into ink_rect. - */ - new_pos = MIN (run_ink->x, run_logical->x); - run_ink->width = MAX (run_ink->x + run_ink->width, run_logical->x + run_logical->width) - new_pos; - run_ink->x = new_pos; - - /* We should better handle the case of height==0 in the following cases. - * If run_ink->height == 0, we should adjust run_ink->y appropriately. - */ - - if (properties.strikethrough) - { - if (run_ink->height == 0) - { - run_ink->height = strikethrough_thickness; - run_ink->y = -strikethrough_position; - } - } - - if (properties.oline_single) - { - run_ink->y -= underline_thickness; - run_ink->height += underline_thickness; - } - - if (properties.uline_low) - run_ink->height += 2 * underline_thickness; - if (properties.uline_single) - run_ink->height = MAX (run_ink->height, - underline_thickness - underline_position - run_ink->y); - if (properties.uline_double) - run_ink->height = MAX (run_ink->height, - 3 * underline_thickness - underline_position - run_ink->y); - if (properties.uline_error) - run_ink->height = MAX (run_ink->height, - 3 * underline_thickness - underline_position - run_ink->y); - } - - if (height) - { - if (pango_analysis_get_size_font (&run->item->analysis)) - { - PangoFontMetrics *height_metrics; - - height_metrics = pango_font_get_metrics (pango_analysis_get_size_font (&run->item->analysis), - run->item->analysis.language); - - *height = pango_font_metrics_get_height (height_metrics); - - pango_font_metrics_unref (height_metrics); - } - else - { - if (!metrics) - metrics = pango_font_get_metrics (run->item->analysis.font, - run->item->analysis.language); - - *height = pango_font_metrics_get_height (metrics); - } - } - - y_offset = run->y_offset; - - if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE) - { - gboolean is_hinted = (run_logical->y & run_logical->height & (PANGO_SCALE - 1)) == 0; - int adjustment = run_logical->y + run_logical->height / 2; - - if (is_hinted) - adjustment = PANGO_UNITS_ROUND (adjustment); - - y_offset += adjustment; - } - - if (run_ink) - run_ink->y -= y_offset; - - if (run_logical) - run_logical->y -= y_offset; - - if (line_logical) - { - *line_logical = *run_logical; - - if (properties.absolute_line_height != 0 || properties.line_height != 0.0) - { - int line_height, leading; - - line_height = MAX (properties.absolute_line_height, ceilf (properties.line_height * line_logical->height)); - - leading = line_height - line_logical->height; - line_logical->y -= leading / 2; - line_logical->height += leading; - } - } - - if (metrics) - pango_font_metrics_unref (metrics); -} - -static void -pango_layout_line_get_extents_and_height (PangoLayoutLine *line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect, - int *height) -{ - PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line; - GSList *tmp_list; - int x_pos = 0; - gboolean caching = FALSE; - - g_return_if_fail (LINE_IS_VALID (line)); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (G_UNLIKELY (!ink_rect && !logical_rect && !height)) + if (layout->single_paragraph == single_paragraph) return; - switch (private->cache_status) - { - case CACHED: - if (ink_rect) - *ink_rect = private->ink_rect; - if (logical_rect) - *logical_rect = private->logical_rect; - if (height) - *height = private->height; - return; - - case NOT_CACHED: - caching = TRUE; - if (!ink_rect) - ink_rect = &private->ink_rect; - if (!logical_rect) - logical_rect = &private->logical_rect; - if (!height) - height = &private->height; - break; - - case LEAKED: - default: - break; - } - - if (ink_rect) - { - ink_rect->x = 0; - ink_rect->y = 0; - ink_rect->width = 0; - ink_rect->height = 0; - } - - if (logical_rect) - { - logical_rect->x = 0; - logical_rect->y = 0; - logical_rect->width = 0; - logical_rect->height = 0; - } + layout->single_paragraph = single_paragraph; - if (height) - *height = 0; - - tmp_list = line->runs; - while (tmp_list) - { - PangoLayoutRun *run = tmp_list->data; - int new_pos; - PangoRectangle run_ink; - PangoRectangle run_logical; - int run_height; - - pango_layout_run_get_extents_and_height (run, - ink_rect ? &run_ink : NULL, - NULL, - &run_logical, - height ? &run_height : NULL); - - if (ink_rect) - { - if (ink_rect->width == 0 || ink_rect->height == 0) - { - *ink_rect = run_ink; - ink_rect->x += x_pos; - } - else if (run_ink.width != 0 && run_ink.height != 0) - { - new_pos = MIN (ink_rect->x, x_pos + run_ink.x); - ink_rect->width = MAX (ink_rect->x + ink_rect->width, - x_pos + run_ink.x + run_ink.width) - new_pos; - ink_rect->x = new_pos; - - new_pos = MIN (ink_rect->y, run_ink.y); - ink_rect->height = MAX (ink_rect->y + ink_rect->height, - run_ink.y + run_ink.height) - new_pos; - ink_rect->y = new_pos; - } - } - - if (logical_rect) - { - new_pos = MIN (logical_rect->x, x_pos + run_logical.x); - logical_rect->width = MAX (logical_rect->x + logical_rect->width, - x_pos + run_logical.x + run_logical.width) - new_pos; - logical_rect->x = new_pos; - - new_pos = MIN (logical_rect->y, run_logical.y); - logical_rect->height = MAX (logical_rect->y + logical_rect->height, - run_logical.y + run_logical.height) - new_pos; - logical_rect->y = new_pos; - } - - if (height) - *height = MAX (*height, abs (run_height)); - - x_pos += run_logical.width; - tmp_list = tmp_list->next; - } - - if (!line->runs) - { - PangoRectangle r, *rect; - - rect = logical_rect ? logical_rect : &r; - pango_layout_get_empty_extents_and_height_at_index (line->layout, line->start_index, rect, TRUE, height); - } - - if (caching) - { - if (&private->ink_rect != ink_rect) - private->ink_rect = *ink_rect; - if (&private->logical_rect != logical_rect) - private->logical_rect = *logical_rect; - if (&private->height != height) - private->height = *height; - private->cache_status = CACHED; - } -} - -/** - * pango_layout_line_get_extents: - * @line: a `PangoLayoutLine` - * @ink_rect: (out) (optional): rectangle used to store the extents of - * the glyph string as drawn - * @logical_rect: (out) (optional): rectangle used to store the logical - * extents of the glyph string - * - * Computes the logical and ink extents of a layout line. - * - * See [method@Pango.Font.get_glyph_extents] for details - * about the interpretation of the rectangles. - */ -void -pango_layout_line_get_extents (PangoLayoutLine *line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) -{ - pango_layout_line_get_extents_and_height (line, ink_rect, logical_rect, NULL); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_SINGLE_PARAGRAPH]); + layout_changed (layout); } /** - * pango_layout_line_get_height: - * @line: a `PangoLayoutLine` - * @height: (out) (optional): return location for the line height + * pango_layout_get_single_paragraph: + * @layout: a `PangoLayout` * - * Computes the height of the line, as the maximum of the heights - * of fonts used in this line. + * Obtains whether @layout is in single paragraph mode. * - * Note that the actual baseline-to-baseline distance between lines - * of text is influenced by other factors, such as - * [method@Pango.Layout.set_spacing] and - * [method@Pango.Layout.set_line_spacing]. + * See [method@Pango.Layout.set_single_paragraph]. * - * Since: 1.44 + * Return value: `TRUE` if the layout does not break paragraphs + * at paragraph separator characters, %FALSE otherwise */ -void -pango_layout_line_get_height (PangoLayoutLine *line, - int *height) -{ - pango_layout_line_get_extents_and_height (line, NULL, NULL, height); -} - -static PangoLayoutLine * -pango_layout_line_new (PangoLayout *layout) +gboolean +pango_layout_get_single_paragraph (PangoLayout *layout) { - PangoLayoutLinePrivate *private = g_slice_new (PangoLayoutLinePrivate); - - private->ref_count = 1; - private->line.layout = layout; - private->line.runs = NULL; - private->line.length = 0; - private->cache_status = NOT_CACHED; - - /* Note that we leave start_index, resolved_dir, and is_paragraph_start - * uninitialized */ + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE); - return (PangoLayoutLine *) private; + return layout->single_paragraph; } /** - * pango_layout_line_get_pixel_extents: - * @layout_line: a `PangoLayoutLine` - * @ink_rect: (out) (optional): rectangle used to store the extents of - * the glyph string as drawn - * @logical_rect: (out) (optional): rectangle used to store the logical - * extents of the glyph string + * pango_layout_set_wrap: + * @layout: a `PangoLayout` + * @wrap: the wrap mode * - * Computes the logical and ink extents of @layout_line in device units. + * Sets the wrap mode. * - * This function just calls [method@Pango.LayoutLine.get_extents] followed by - * two [func@extents_to_pixels] calls, rounding @ink_rect and @logical_rect - * such that the rounded rectangles fully contain the unrounded one (that is, - * passes them as first argument to [func@extents_to_pixels]). - */ -void -pango_layout_line_get_pixel_extents (PangoLayoutLine *layout_line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) -{ - g_return_if_fail (LINE_IS_VALID (layout_line)); - - pango_layout_line_get_extents (layout_line, ink_rect, logical_rect); - pango_extents_to_pixels (ink_rect, NULL); - pango_extents_to_pixels (logical_rect, NULL); -} - -/* - * NB: This implement the exact same algorithm as - * reorder-items.c:pango_reorder_items(). - */ -static GSList * -reorder_runs_recurse (GSList *items, - int n_items) -{ - GSList *tmp_list, *level_start_node; - int i, level_start_i; - int min_level = G_MAXINT; - GSList *result = NULL; - - if (n_items == 0) - return NULL; - - tmp_list = items; - for (i=0; i<n_items; i++) - { - PangoLayoutRun *run = tmp_list->data; - - min_level = MIN (min_level, run->item->analysis.level); - - tmp_list = tmp_list->next; - } - - level_start_i = 0; - level_start_node = items; - tmp_list = items; - for (i=0; i<n_items; i++) - { - PangoLayoutRun *run = tmp_list->data; - - if (run->item->analysis.level == min_level) - { - if (min_level % 2) - { - if (i > level_start_i) - result = g_slist_concat (reorder_runs_recurse (level_start_node, i - level_start_i), result); - result = g_slist_prepend (result, run); - } - else - { - if (i > level_start_i) - result = g_slist_concat (result, reorder_runs_recurse (level_start_node, i - level_start_i)); - result = g_slist_append (result, run); - } - - level_start_i = i + 1; - level_start_node = tmp_list->next; - } - - tmp_list = tmp_list->next; - } - - if (min_level % 2) - { - if (i > level_start_i) - result = g_slist_concat (reorder_runs_recurse (level_start_node, i - level_start_i), result); - } - else - { - if (i > level_start_i) - result = g_slist_concat (result, reorder_runs_recurse (level_start_node, i - level_start_i)); - } - - return result; -} - -static void -pango_layout_line_reorder (PangoLayoutLine *line) -{ - GSList *logical_runs = line->runs; - GSList *tmp_list; - gboolean all_even, all_odd; - guint8 level_or = 0, level_and = 1; - int length = 0; - - /* Check if all items are in the same direction, in that case, the - * line does not need modification and we can avoid the expensive - * reorder runs recurse procedure. - */ - for (tmp_list = logical_runs; tmp_list != NULL; tmp_list = tmp_list->next) - { - PangoLayoutRun *run = tmp_list->data; - - level_or |= run->item->analysis.level; - level_and &= run->item->analysis.level; - - length++; - } - - /* If none of the levels had the LSB set, all numbers were even. */ - all_even = (level_or & 0x1) == 0; - - /* If all of the levels had the LSB set, all numbers were odd. */ - all_odd = (level_and & 0x1) == 1; - - if (!all_even && !all_odd) - { - line->runs = reorder_runs_recurse (logical_runs, length); - g_slist_free (logical_runs); - } - else if (all_odd) - line->runs = g_slist_reverse (logical_runs); -} - -static int -get_item_letter_spacing (PangoItem *item) -{ - ItemProperties properties; - - pango_item_get_properties (item, &properties); - - return properties.letter_spacing; -} - -static void -pad_glyphstring_right (PangoGlyphString *glyphs, - ParaBreakState *state, - int adjustment) -{ - int glyph = glyphs->num_glyphs - 1; - - while (glyph >= 0 && glyphs->glyphs[glyph].geometry.width == 0) - glyph--; - - if (glyph < 0) - return; - - state->remaining_width -= adjustment; - glyphs->glyphs[glyph].geometry.width += adjustment; - if (glyphs->glyphs[glyph].geometry.width < 0) - { - state->remaining_width += glyphs->glyphs[glyph].geometry.width; - glyphs->glyphs[glyph].geometry.width = 0; - } -} - -static void -pad_glyphstring_left (PangoGlyphString *glyphs, - ParaBreakState *state, - int adjustment) -{ - int glyph = 0; - - while (glyph < glyphs->num_glyphs && glyphs->glyphs[glyph].geometry.width == 0) - glyph++; - - if (glyph == glyphs->num_glyphs) - return; - - state->remaining_width -= adjustment; - glyphs->glyphs[glyph].geometry.width += adjustment; - glyphs->glyphs[glyph].geometry.x_offset += adjustment; -} - -static gboolean -is_tab_run (PangoLayout *layout, - PangoLayoutRun *run) -{ - return (layout->text[run->item->offset] == '\t'); -} - -static void -add_missing_hyphen (PangoLayoutLine *line, - ParaBreakState *state, - PangoLayoutRun *run) -{ - PangoLayout *layout = line->layout; - PangoItem *item = run->item; - int line_chars; - - line_chars = 0; - for (GSList *l = line->runs; l; l = l->next) - { - PangoLayoutRun *r = l->data; - - if (r) - line_chars += r->item->num_chars; - } - - if (layout->log_attrs[state->line_start_offset + line_chars].break_inserts_hyphen && - !(item->analysis.flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN)) - { - int width; - int start_offset; - - DEBUG1("add a missing hyphen"); - /* The last run fit onto the line without breaking it, but it still needs a hyphen */ - - width = pango_glyph_string_get_width (run->glyphs); - - /* Ugly, shape_run uses state->start_offset, so temporarily rewind things - * to the state before the run was inserted. Otherwise, we end up passing - * the wrong log attrs to the shaping machinery. - */ - start_offset = state->start_offset; - state->start_offset = state->line_start_offset + line_chars - item->num_chars; - - pango_glyph_string_free (run->glyphs); - item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; - run->glyphs = shape_run (line, state, item); - - state->start_offset = start_offset; - - state->remaining_width += pango_glyph_string_get_width (run->glyphs) - width; - } -} - -static void -zero_line_final_space (PangoLayoutLine *line, - ParaBreakState *state, - PangoLayoutRun *run) -{ - PangoLayout *layout = line->layout; - PangoItem *item = run->item; - PangoGlyphString *glyphs; - int glyph; - - glyphs = run->glyphs; - glyph = item->analysis.level % 2 ? 0 : glyphs->num_glyphs - 1; - - if (glyphs->glyphs[glyph].glyph == PANGO_GET_UNKNOWN_GLYPH (0x2028)) - { - DEBUG1 ("zero final space: visible space"); - return; /* this LS is visible */ - } - - /* if the final char of line forms a cluster, and it's - * a whitespace char, zero its glyph's width as it's been wrapped - */ - if (glyphs->num_glyphs < 1 || state->start_offset == 0 || - !layout->log_attrs[state->start_offset - 1].is_white) - { - DEBUG1 ("zero final space: not whitespace"); - return; - } - - if (glyphs->num_glyphs >= 2 && - glyphs->log_clusters[glyph] == glyphs->log_clusters[glyph + (item->analysis.level % 2 ? 1 : -1)]) - { - - DEBUG1 ("zero final space: its a cluster"); - return; - } - - DEBUG1 ("zero line final space: collapsing the space"); - glyphs->glyphs[glyph].geometry.width = 0; - glyphs->glyphs[glyph].glyph = PANGO_GLYPH_EMPTY; -} - -/* When doing shaping, we add the letter spacing value for a - * run after every grapheme in the run. This produces ugly - * asymmetrical results, so what this routine is redistributes - * that space to the beginning and the end of the run. + * The wrap mode only has effect if a width is set on the layout + * with [method@Pango.Layout.set_width]. To turn off wrapping, + * set the width to -1. * - * We also trim the letter spacing from runs adjacent to - * tabs and from the outside runs of the lines so that things - * line up properly. The line breaking and tab positioning - * were computed without this trimming so they are no longer - * exactly correct, but this won't be very noticeable in most - * cases. + * The default value is %PANGO_WRAP_WORD. */ -static void -adjust_line_letter_spacing (PangoLayoutLine *line, - ParaBreakState *state) -{ - PangoLayout *layout = line->layout; - gboolean reversed; - PangoLayoutRun *last_run; - int tab_adjustment; - GSList *l; - - /* If we have tab stops and the resolved direction of the - * line is RTL, then we need to walk through the line - * in reverse direction to figure out the corrections for - * tab stops. - */ - reversed = FALSE; - if (line->resolved_dir == PANGO_DIRECTION_RTL) - { - for (l = line->runs; l; l = l->next) - if (is_tab_run (layout, l->data)) - { - line->runs = g_slist_reverse (line->runs); - reversed = TRUE; - break; - } - } - - /* Walk over the runs in the line, redistributing letter - * spacing from the end of the run to the start of the - * run and trimming letter spacing from the ends of the - * runs adjacent to the ends of the line or tab stops. - * - * We accumulate a correction factor from this trimming - * which we add onto the next tab stop space to keep the - * things properly aligned. - */ - last_run = NULL; - tab_adjustment = 0; - for (l = line->runs; l; l = l->next) - { - PangoLayoutRun *run = l->data; - PangoLayoutRun *next_run = l->next ? l->next->data : NULL; - - if (is_tab_run (layout, run)) - { - pad_glyphstring_right (run->glyphs, state, tab_adjustment); - tab_adjustment = 0; - } - else - { - PangoLayoutRun *visual_next_run = reversed ? last_run : next_run; - PangoLayoutRun *visual_last_run = reversed ? next_run : last_run; - int run_spacing = get_item_letter_spacing (run->item); - int space_left, space_right; - - distribute_letter_spacing (run_spacing, &space_left, &space_right); - - if (run->glyphs->glyphs[0].geometry.width == 0) - { - /* we've zeroed this space glyph at the end of line, now remove - * the letter spacing added to its adjacent glyph */ - pad_glyphstring_left (run->glyphs, state, - space_left); - } - else if (!visual_last_run || is_tab_run (layout, visual_last_run)) - { - pad_glyphstring_left (run->glyphs, state, - space_left); - tab_adjustment += space_left; - } - - if (run->glyphs->glyphs[run->glyphs->num_glyphs - 1].geometry.width == 0) - { - /* we've zeroed this space glyph at the end of line, now remove - * the letter spacing added to its adjacent glyph */ - pad_glyphstring_right (run->glyphs, state, - space_right); - } - else if (!visual_next_run || is_tab_run (layout, visual_next_run)) - { - pad_glyphstring_right (run->glyphs, state, - space_right); - tab_adjustment += space_right; - } - } - - last_run = run; - } - - if (reversed) - line->runs = g_slist_reverse (line->runs); -} - -static void -justify_clusters (PangoLayoutLine *line, - ParaBreakState *state) +void +pango_layout_set_wrap (PangoLayout *layout, + PangoWrapMode wrap) { - const gchar *text = line->layout->text; - const PangoLogAttr *log_attrs = line->layout->log_attrs; - - int total_remaining_width, total_gaps = 0; - int added_so_far, gaps_so_far; - gboolean is_hinted; - GSList *run_iter; - enum { - MEASURE, - ADJUST - } mode; - - total_remaining_width = state->remaining_width; - if (total_remaining_width <= 0) - return; - - /* hint to full pixel if total remaining width was so */ - is_hinted = (total_remaining_width & (PANGO_SCALE - 1)) == 0; - - for (mode = MEASURE; mode <= ADJUST; mode++) - { - gboolean leftedge = TRUE; - PangoGlyphString *rightmost_glyphs = NULL; - int rightmost_space = 0; - int residual = 0; - - added_so_far = 0; - gaps_so_far = 0; - - for (run_iter = line->runs; run_iter; run_iter = run_iter->next) - { - PangoLayoutRun *run = run_iter->data; - PangoGlyphString *glyphs = run->glyphs; - PangoGlyphItemIter cluster_iter; - gboolean have_cluster; - int dir; - int offset; - - dir = run->item->analysis.level % 2 == 0 ? +1 : -1; - - /* 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); - offset = ((PangoItemPrivate *)run->item)->char_offset; - - for (have_cluster = dir > 0 ? - pango_glyph_item_iter_init_start (&cluster_iter, run, text) : - pango_glyph_item_iter_init_end (&cluster_iter, run, text); - have_cluster; - have_cluster = dir > 0 ? - pango_glyph_item_iter_next_cluster (&cluster_iter) : - pango_glyph_item_iter_prev_cluster (&cluster_iter)) - { - int i; - int width = 0; - - /* don't expand in the middle of graphemes */ - if (!log_attrs[offset + cluster_iter.start_char].is_cursor_position) - continue; - - for (i = cluster_iter.start_glyph; i != cluster_iter.end_glyph; i += dir) - width += glyphs->glyphs[i].geometry.width; - - /* also don't expand zero-width clusters. */ - if (width == 0) - continue; - - gaps_so_far++; - - if (mode == ADJUST) - { - int leftmost, rightmost; - int adjustment, space_left, space_right; - - adjustment = total_remaining_width / total_gaps + residual; - if (is_hinted) - { - int old_adjustment = adjustment; - adjustment = PANGO_UNITS_ROUND (adjustment); - residual = old_adjustment - adjustment; - } - /* distribute to before/after */ - distribute_letter_spacing (adjustment, &space_left, &space_right); - - if (cluster_iter.start_glyph < cluster_iter.end_glyph) - { - /* LTR */ - leftmost = cluster_iter.start_glyph; - rightmost = cluster_iter.end_glyph - 1; - } - else - { - /* RTL */ - leftmost = cluster_iter.end_glyph + 1; - rightmost = cluster_iter.start_glyph; - } - /* Don't add to left-side of left-most glyph of left-most non-zero run. */ - if (leftedge) - leftedge = FALSE; - else - { - glyphs->glyphs[leftmost].geometry.width += space_left ; - glyphs->glyphs[leftmost].geometry.x_offset += space_left ; - added_so_far += space_left; - } - /* Don't add to right-side of right-most glyph of right-most non-zero run. */ - { - /* Save so we can undo later. */ - rightmost_glyphs = glyphs; - rightmost_space = space_right; - - glyphs->glyphs[rightmost].geometry.width += space_right; - added_so_far += space_right; - } - } - } - } - - if (mode == MEASURE) - { - total_gaps = gaps_so_far - 1; - - if (total_gaps == 0) - { - /* a single cluster, can't really justify it */ - return; - } - } - else /* mode == ADJUST */ - { - if (rightmost_glyphs) - { - rightmost_glyphs->glyphs[rightmost_glyphs->num_glyphs - 1].geometry.width -= rightmost_space; - added_so_far -= rightmost_space; - } - } - } - - state->remaining_width -= added_so_far; -} + g_return_if_fail (PANGO_IS_LAYOUT (layout)); -static void -justify_words (PangoLayoutLine *line, - ParaBreakState *state) -{ - const gchar *text = line->layout->text; - const PangoLogAttr *log_attrs = line->layout->log_attrs; - - int total_remaining_width, total_space_width = 0; - int added_so_far, spaces_so_far; - gboolean is_hinted; - GSList *run_iter; - enum { - MEASURE, - ADJUST - } mode; - - total_remaining_width = state->remaining_width; - if (total_remaining_width <= 0) + if (layout->wrap == wrap) return; - /* hint to full pixel if total remaining width was so */ - is_hinted = (total_remaining_width & (PANGO_SCALE - 1)) == 0; - - for (mode = MEASURE; mode <= ADJUST; mode++) - { - added_so_far = 0; - spaces_so_far = 0; - - for (run_iter = line->runs; run_iter; run_iter = run_iter->next) - { - PangoLayoutRun *run = run_iter->data; - PangoGlyphString *glyphs = run->glyphs; - PangoGlyphItemIter cluster_iter; - gboolean have_cluster; - int offset; - - /* 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); - offset = ((PangoItemPrivate *)run->item)->char_offset; - - for (have_cluster = pango_glyph_item_iter_init_start (&cluster_iter, run, text); - have_cluster; - have_cluster = pango_glyph_item_iter_next_cluster (&cluster_iter)) - { - int i; - int dir; - - if (!log_attrs[offset + cluster_iter.start_char].is_expandable_space) - continue; - - dir = (cluster_iter.start_glyph < cluster_iter.end_glyph) ? 1 : -1; - for (i = cluster_iter.start_glyph; i != cluster_iter.end_glyph; i += dir) - { - int glyph_width = glyphs->glyphs[i].geometry.width; - - if (glyph_width == 0) - continue; - - spaces_so_far += glyph_width; - - if (mode == ADJUST) - { - int adjustment; - - adjustment = ((guint64) spaces_so_far * total_remaining_width) / total_space_width - added_so_far; - if (is_hinted) - adjustment = PANGO_UNITS_ROUND (adjustment); - - glyphs->glyphs[i].geometry.width += adjustment; - added_so_far += adjustment; - } - } - } - } - - if (mode == MEASURE) - { - total_space_width = spaces_so_far; - - if (total_space_width == 0) - { - justify_clusters (line, state); - return; - } - } - } - - state->remaining_width -= added_so_far; -} - -typedef struct { - PangoAttribute *attr; - int x_offset; - int y_offset; -} BaselineItem; - -static void -collect_baseline_shift (ParaBreakState *state, - PangoItem *item, - PangoItem *prev, - int *start_x_offset, - int *start_y_offset, - int *end_x_offset, - int *end_y_offset) -{ - *start_x_offset = 0; - *start_y_offset = 0; - *end_x_offset = 0; - *end_y_offset = 0; - - for (GSList *l = item->analysis.extra_attrs; l; l = l->next) - { - PangoAttribute *attr = l->data; - - if (attr->klass->type == PANGO_ATTR_RISE) - { - int value = ((PangoAttrInt *)attr)->value; - - *start_y_offset += value; - *end_y_offset -= value; - } - else if (attr->klass->type == PANGO_ATTR_BASELINE_SHIFT) - { - if (attr->start_index == item->offset) - { - BaselineItem *entry; - int value; - - entry = g_new0 (BaselineItem, 1); - entry->attr = attr; - state->baseline_shifts = g_list_prepend (state->baseline_shifts, entry); - - value = ((PangoAttrInt *)attr)->value; - - if (value > 1024 || value < -1024) - { - entry->y_offset = value; - /* FIXME: compute an x_offset from value to italic angle */ - } - else - { - int superscript_x_offset = 0; - int superscript_y_offset = 0; - int subscript_x_offset = 0; - int subscript_y_offset = 0; - - - if (prev) - { - hb_font_t *hb_font = pango_font_get_hb_font (prev->analysis.font); - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET, &superscript_y_offset); - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET, &superscript_x_offset); - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET, &subscript_y_offset); - hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET, &subscript_x_offset); - } - - if (superscript_y_offset == 0) - superscript_y_offset = 5000; - if (subscript_y_offset == 0) - subscript_y_offset = 5000; - - switch (value) - { - case PANGO_BASELINE_SHIFT_NONE: - entry->x_offset = 0; - entry->y_offset = 0; - break; - case PANGO_BASELINE_SHIFT_SUPERSCRIPT: - entry->x_offset = superscript_x_offset; - entry->y_offset = superscript_y_offset; - break; - case PANGO_BASELINE_SHIFT_SUBSCRIPT: - entry->x_offset = subscript_x_offset; - entry->y_offset = -subscript_y_offset; - break; - default: - g_assert_not_reached (); - } - } - - *start_x_offset += entry->x_offset; - *start_y_offset += entry->y_offset; - } - - if (attr->end_index == item->offset + item->length) - { - GList *t; - - for (t = state->baseline_shifts; t; t = t->next) - { - BaselineItem *entry = t->data; - - if (attr->start_index == entry->attr->start_index && - attr->end_index == entry->attr->end_index && - ((PangoAttrInt *)attr)->value == ((PangoAttrInt *)entry->attr)->value) - { - *end_x_offset -= entry->x_offset; - *end_y_offset -= entry->y_offset; - } - - state->baseline_shifts = g_list_remove (state->baseline_shifts, entry); - g_free (entry); - break; - } - if (t == NULL) - g_warning ("Baseline attributes mismatch\n"); - } - } - } -} - -static void -apply_baseline_shift (PangoLayoutLine *line, - ParaBreakState *state) -{ - int y_offset = 0; - PangoItem *prev = NULL; - - for (GSList *l = line->runs; l; l = l->next) - { - PangoLayoutRun *run = l->data; - PangoItem *item = run->item; - int start_x_offset, end_x_offset; - int start_y_offset, end_y_offset; - - collect_baseline_shift (state, item, prev, &start_x_offset, &start_y_offset, &end_x_offset, &end_y_offset); - - y_offset += start_y_offset; - - run->y_offset = y_offset; - run->start_x_offset = start_x_offset; - run->end_x_offset = end_x_offset; - - y_offset += end_y_offset; - - prev = item; - } -} - -static void -pango_layout_line_postprocess (PangoLayoutLine *line, - ParaBreakState *state, - gboolean wrapped) -{ - gboolean ellipsized = FALSE; - - DEBUG1 ("postprocessing line, %s", wrapped ? "wrapped" : "not wrapped"); - - add_missing_hyphen (line, state, line->runs->data); - DEBUG ("after hyphen addition", line, state); - - /* Truncate the logical-final whitespace in the line if we broke the line at it */ - if (wrapped) - zero_line_final_space (line, state, line->runs->data); - - DEBUG ("after removing final space", line, state); - - /* Reverse the runs */ - line->runs = g_slist_reverse (line->runs); - - apply_baseline_shift (line, state); - - /* Ellipsize the line if necessary */ - if (G_UNLIKELY (state->line_width >= 0 && - should_ellipsize_current_line (line->layout, state))) - { - PangoShapeFlags shape_flags = PANGO_SHAPE_NONE; - - if (pango_context_get_round_glyph_positions (line->layout->context)) - shape_flags |= PANGO_SHAPE_ROUND_POSITIONS; - - ellipsized = _pango_layout_line_ellipsize (line, state->attrs, shape_flags, state->line_width); - } - - /* Now convert logical to visual order */ - pango_layout_line_reorder (line); - - DEBUG ("after reordering", line, state); - - /* Fixup letter spacing between runs */ - adjust_line_letter_spacing (line, state); + layout->wrap = wrap; - DEBUG ("after letter spacing", line, state); - - /* Distribute extra space between words if justifying and line was wrapped */ - if (line->layout->justify && (wrapped || ellipsized || line->layout->justify_last_line)) - { - /* if we ellipsized, we don't have remaining_width set */ - if (state->remaining_width < 0) - state->remaining_width = state->line_width - pango_layout_line_get_width (line); - - justify_words (line, state); - } - - DEBUG ("after justification", line, state); - - line->layout->is_wrapped |= wrapped; - line->layout->is_ellipsized |= ellipsized; -} - -static int -next_cluster_start (PangoGlyphString *gs, - int cluster_start) -{ - int i; - - i = cluster_start + 1; - while (i < gs->num_glyphs) - { - if (gs->glyphs[i].attr.is_cluster_start) - return i; - - i++; - } - - return gs->num_glyphs; -} - -static int -cluster_width (PangoGlyphString *gs, - int cluster_start) -{ - int i; - int width; - - width = gs->glyphs[cluster_start].geometry.width; - i = cluster_start + 1; - while (i < gs->num_glyphs) - { - if (gs->glyphs[i].attr.is_cluster_start) - break; - - width += gs->glyphs[i].geometry.width; - i++; - } - - return width; -} - -static inline void -offset_y (PangoLayoutIter *iter, - int *y) -{ - *y += iter->line_extents[iter->line_index].baseline; -} - -/* Sets up the iter for the start of a new cluster. cluster_start_index - * is the byte index of the cluster start relative to the run. - */ -static void -update_cluster (PangoLayoutIter *iter, - int cluster_start_index) -{ - char *cluster_text; - PangoGlyphString *gs; - int cluster_length; - - iter->character_position = 0; - - gs = iter->run->glyphs; - iter->cluster_width = cluster_width (gs, iter->cluster_start); - iter->next_cluster_glyph = next_cluster_start (gs, iter->cluster_start); - - if (iter->ltr) - { - /* For LTR text, finding the length of the cluster is easy - * since logical and visual runs are in the same direction. - */ - if (iter->next_cluster_glyph < gs->num_glyphs) - cluster_length = gs->log_clusters[iter->next_cluster_glyph] - cluster_start_index; - else - cluster_length = iter->run->item->length - cluster_start_index; - } - else - { - /* For RTL text, we have to scan backwards to find the previous - * visual cluster which is the next logical cluster. - */ - int i = iter->cluster_start; - while (i > 0 && gs->log_clusters[i - 1] == cluster_start_index) - i--; - - if (i == 0) - cluster_length = iter->run->item->length - cluster_start_index; - else - cluster_length = gs->log_clusters[i - 1] - cluster_start_index; - } - - cluster_text = iter->layout->text + iter->run->item->offset + cluster_start_index; - iter->cluster_num_chars = pango_utf8_strlen (cluster_text, cluster_length); - - if (iter->ltr) - iter->index = cluster_text - iter->layout->text; - else - iter->index = g_utf8_prev_char (cluster_text + cluster_length) - iter->layout->text; -} - -static void -update_run (PangoLayoutIter *iter, - int run_start_index) -{ - const Extents *line_ext = &iter->line_extents[iter->line_index]; - - /* Note that in iter_new() the iter->run_width - * is garbage but we don't use it since we're on the first run of - * a line. - */ - if (iter->run_list_link == iter->line->runs) - iter->run_x = line_ext->logical_rect.x; - else - { - iter->run_x += iter->end_x_offset + iter->run_width; - if (iter->run) - iter->run_x += iter->run->start_x_offset; - } - - if (iter->run) - { - iter->run_width = pango_glyph_string_get_width (iter->run->glyphs); - iter->end_x_offset = iter->run->end_x_offset; - } - else - { - /* The empty run at the end of a line */ - iter->run_width = 0; - iter->end_x_offset = 0; - } - - if (iter->run) - iter->ltr = (iter->run->item->analysis.level % 2) == 0; - else - iter->ltr = TRUE; - - iter->cluster_start = 0; - iter->cluster_x = iter->run_x; - - if (iter->run) - { - update_cluster (iter, iter->run->glyphs->log_clusters[0]); - } - else - { - iter->cluster_width = 0; - iter->character_position = 0; - iter->cluster_num_chars = 0; - iter->index = run_start_index; - } + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_WRAP]); + layout_changed (layout); } /** - * pango_layout_iter_copy: - * @iter: (nullable): a `PangoLayoutIter` - * - * Copies a `PangoLayoutIter`. + * pango_layout_get_wrap: + * @layout: a `PangoLayout` * - * Return value: (nullable): the newly allocated `PangoLayoutIter` + * Gets the wrap mode for the layout. * - * Since: 1.20 + * Return value: active wrap mode. */ -PangoLayoutIter * -pango_layout_iter_copy (PangoLayoutIter *iter) +PangoWrapMode +pango_layout_get_wrap (PangoLayout *layout) { - PangoLayoutIter *new; - - if (iter == NULL) - return NULL; - - new = g_slice_new (PangoLayoutIter); - - new->layout = g_object_ref (iter->layout); - new->line_list_link = iter->line_list_link; - new->line = iter->line; - pango_layout_line_ref (new->line); - - new->run_list_link = iter->run_list_link; - new->run = iter->run; - new->index = iter->index; - - new->line_extents = NULL; - if (iter->line_extents != NULL) - { - new->line_extents = g_memdup2 (iter->line_extents, - iter->layout->line_count * sizeof (Extents)); - - } - new->line_index = iter->line_index; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), PANGO_WRAP_WORD); - new->run_x = iter->run_x; - new->run_width = iter->run_width; - new->ltr = iter->ltr; - - new->cluster_x = iter->cluster_x; - new->cluster_width = iter->cluster_width; - - new->cluster_start = iter->cluster_start; - new->next_cluster_glyph = iter->next_cluster_glyph; - - new->cluster_num_chars = iter->cluster_num_chars; - new->character_position = iter->character_position; - - new->layout_width = iter->layout_width; - - return new; + return layout->wrap; } -G_DEFINE_BOXED_TYPE (PangoLayoutIter, pango_layout_iter, - pango_layout_iter_copy, - pango_layout_iter_free); - /** - * pango_layout_get_iter: + * pango_layout_set_indent: * @layout: a `PangoLayout` + * @indent: the amount by which to indent * - * Returns an iterator to iterate over the visual extents of the layout. + * Sets the width in Pango units to indent each paragraph. * - * Return value: the new `PangoLayoutIter` + * A negative value of @indent will produce a hanging indentation. + * That is, the first line will have the full width, and subsequent + * lines will be indented by the absolute value of @indent. + * + * The default value is 0. */ -PangoLayoutIter* -pango_layout_get_iter (PangoLayout *layout) -{ - PangoLayoutIter *iter; - - g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - - iter = g_slice_new (PangoLayoutIter); - - _pango_layout_get_iter (layout, iter); - - return iter; -} - void -_pango_layout_get_iter (PangoLayout *layout, - PangoLayoutIter*iter) +pango_layout_set_indent (PangoLayout *layout, + int indent) { - int run_start_index; - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - iter->layout = g_object_ref (layout); - - pango_layout_check_lines (layout); - - iter->line_list_link = layout->lines; - iter->line = iter->line_list_link->data; - pango_layout_line_ref (iter->line); - - run_start_index = iter->line->start_index; - iter->run_list_link = iter->line->runs; - - if (iter->run_list_link) - { - iter->run = iter->run_list_link->data; - run_start_index = iter->run->item->offset; - } - else - iter->run = NULL; - - iter->line_extents = NULL; - - if (layout->width == -1) - { - PangoRectangle logical_rect; - - pango_layout_get_extents_internal (layout, - NULL, - &logical_rect, - &iter->line_extents); - iter->layout_width = logical_rect.width; - } - else - { - pango_layout_get_extents_internal (layout, - NULL, - NULL, - &iter->line_extents); - iter->layout_width = layout->width; - } - iter->line_index = 0; - - update_run (iter, run_start_index); -} - -void -_pango_layout_iter_destroy (PangoLayoutIter *iter) -{ - if (iter == NULL) + if (layout->indent == indent) return; - g_free (iter->line_extents); - pango_layout_line_unref (iter->line); - g_object_unref (iter->layout); -} + layout->indent = indent; -/** - * pango_layout_iter_free: - * @iter: (nullable): a `PangoLayoutIter`, may be %NULL - * - * Frees an iterator that's no longer in use. - **/ -void -pango_layout_iter_free (PangoLayoutIter *iter) -{ - if (iter == NULL) - return; - - _pango_layout_iter_destroy (iter); - g_slice_free (PangoLayoutIter, iter); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_INDENT]); + layout_changed (layout); } /** - * pango_layout_iter_get_index: - * @iter: a `PangoLayoutIter` + * pango_layout_get_indent: + * @layout: a `PangoLayout` * - * Gets the current byte index. + * Gets the paragraph indent width in Pango units. * - * Note that iterating forward by char moves in visual order, - * not logical order, so indexes may not be sequential. Also, - * the index may be equal to the length of the text in the - * layout, if on the %NULL run (see [method@Pango.LayoutIter.get_run]). + * A negative value indicates a hanging indentation. * - * Return value: current byte index + * Return value: the indent in Pango units */ int -pango_layout_iter_get_index (PangoLayoutIter *iter) -{ - if (ITER_IS_INVALID (iter)) - return 0; - - return iter->index; -} - -/** - * pango_layout_iter_get_run: - * @iter: a `PangoLayoutIter` - * - * Gets the current run. - * - * When iterating by run, at the end of each line, there's a position - * with a %NULL run, so this function can return %NULL. The %NULL run - * at the end of each line ensures that all lines have at least one run, - * even lines consisting of only a newline. - * - * Use the faster [method@Pango.LayoutIter.get_run_readonly] if you do not - * plan to modify the contents of the run (glyphs, glyph widths, etc.). - * - * Return value: (transfer none) (nullable): the current run - */ -PangoLayoutRun* -pango_layout_iter_get_run (PangoLayoutIter *iter) -{ - if (ITER_IS_INVALID (iter)) - return NULL; - - pango_layout_line_leaked (iter->line); - - return iter->run; -} - -/** - * pango_layout_iter_get_run_readonly: - * @iter: a `PangoLayoutIter` - * - * Gets the current run for read-only access. - * - * When iterating by run, at the end of each line, there's a position - * with a %NULL run, so this function can return %NULL. The %NULL run - * at the end of each line ensures that all lines have at least one run, - * even lines consisting of only a newline. - * - * This is a faster alternative to [method@Pango.LayoutIter.get_run], - * but the user is not expected to modify the contents of the run (glyphs, - * glyph widths, etc.). - * - * Return value: (transfer none) (nullable): the current run, that - * should not be modified - * - * Since: 1.16 - */ -PangoLayoutRun* -pango_layout_iter_get_run_readonly (PangoLayoutIter *iter) -{ - if (ITER_IS_INVALID (iter)) - return NULL; - - pango_layout_line_leaked (iter->line); - - return iter->run; -} - -/* an inline-able version for local use */ -static PangoLayoutLine* -_pango_layout_iter_get_line (PangoLayoutIter *iter) +pango_layout_get_indent (PangoLayout *layout) { - return iter->line; -} + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); -static PangoLayoutRun * -_pango_layout_iter_get_run (PangoLayoutIter *iter) -{ - return iter->run; + return layout->indent; } /** - * pango_layout_iter_get_line: - * @iter: a `PangoLayoutIter` - * - * Gets the current line. + * pango_layout_set_alignment: + * @layout: a `PangoLayout` + * @alignment: the alignment * - * Use the faster [method@Pango.LayoutIter.get_line_readonly] if - * you do not plan to modify the contents of the line (glyphs, - * glyph widths, etc.). + * Sets the alignment for the layout: how short lines are + * positioned within the horizontal space available. * - * Return value: (transfer none): the current line + * The default alignment is `PANGO_ALIGN_LEFT`. */ -PangoLayoutLine* -pango_layout_iter_get_line (PangoLayoutIter *iter) +void +pango_layout_set_alignment (PangoLayout *layout, + PangoAlignment alignment) { - if (ITER_IS_INVALID (iter)) - return NULL; - - pango_layout_line_leaked (iter->line); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - return iter->line; -} + if (layout->alignment == alignment) + return; -/** - * pango_layout_iter_get_line_readonly: - * @iter: a `PangoLayoutIter` - * - * Gets the current line for read-only access. - * - * This is a faster alternative to [method@Pango.LayoutIter.get_line], - * but the user is not expected to modify the contents of the line - * (glyphs, glyph widths, etc.). - * - * Return value: (transfer none): the current line, that should not be - * modified - * - * Since: 1.16 - */ -PangoLayoutLine* -pango_layout_iter_get_line_readonly (PangoLayoutIter *iter) -{ - if (ITER_IS_INVALID (iter)) - return NULL; + layout->alignment = alignment; - return iter->line; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ALIGNMENT]); + layout_changed (layout); } /** - * pango_layout_iter_at_last_line: - * @iter: a `PangoLayoutIter` + * pango_layout_get_alignment: + * @layout: a `PangoLayout` * - * Determines whether @iter is on the last line of the layout. + * Gets the alignment for the layout: how short lines are + * positioned within the horizontal space available. * - * Return value: %TRUE if @iter is on the last line + * Return value: the alignment */ -gboolean -pango_layout_iter_at_last_line (PangoLayoutIter *iter) +PangoAlignment +pango_layout_get_alignment (PangoLayout *layout) { - if (ITER_IS_INVALID (iter)) - return FALSE; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), PANGO_ALIGN_LEFT); - return iter->line_index == iter->layout->line_count - 1; + return layout->alignment; } /** - * pango_layout_iter_get_layout: - * @iter: a `PangoLayoutIter` + * pango_layout_set_ellipsize: + * @layout: a `PangoLayout` + * @ellipsize: the new ellipsization mode for @layout * - * Gets the layout associated with a `PangoLayoutIter`. + * Sets the type of ellipsization being performed for @layout. * - * Return value: (transfer none): the layout associated with @iter + * Depending on the ellipsization mode @ellipsize text is removed + * from the start, middle, or end of text so they fit within the + * width of layout set with [method@Pango.Layout.set_width]. * - * Since: 1.20 + * The default value is `PANGO_ELLIPSIZE_NONE`. */ -PangoLayout* -pango_layout_iter_get_layout (PangoLayoutIter *iter) -{ - /* check is redundant as it simply checks that iter->layout is not NULL */ - if (ITER_IS_INVALID (iter)) - return NULL; - - return iter->layout; -} - -static gboolean -line_is_terminated (PangoLayoutIter *iter) -{ - /* There is a real terminator at the end of each paragraph other - * than the last. - */ - if (iter->line_list_link->next) - { - PangoLayoutLine *next_line = iter->line_list_link->next->data; - if (next_line->is_paragraph_start) - return TRUE; - } - - return FALSE; -} - -/* Moves to the next non-empty line. If @include_terminators - * is set, a line with just an explicit paragraph separator - * is considered non-empty. - */ -static gboolean -next_nonempty_line (PangoLayoutIter *iter, - gboolean include_terminators) -{ - gboolean result; - - while (TRUE) - { - result = pango_layout_iter_next_line (iter); - if (!result) - break; - - if (iter->line->runs) - break; - - if (include_terminators && line_is_terminated (iter)) - break; - } - - return result; -} - -/* Moves to the next non-empty run. If @include_terminators - * is set, the trailing run at the end of a line with an explicit - * paragraph separator is considered non-empty. - */ -static gboolean -next_nonempty_run (PangoLayoutIter *iter, - gboolean include_terminators) -{ - gboolean result; - - while (TRUE) - { - result = pango_layout_iter_next_run (iter); - if (!result) - break; - - if (iter->run) - break; - - if (include_terminators && line_is_terminated (iter)) - break; - } - - return result; -} - -/* Like pango_layout_next_cluster(), but if @include_terminators - * is set, includes the fake runs/clusters for empty lines. - * (But not positions introduced by line wrapping). - */ -static gboolean -next_cluster_internal (PangoLayoutIter *iter, - gboolean include_terminators) +void +pango_layout_set_ellipsize (PangoLayout *layout, + PangoEllipsizeMode ellipsize) { - PangoGlyphString *gs; - int next_start; - - if (ITER_IS_INVALID (iter)) - return FALSE; - - if (iter->run == NULL) - return next_nonempty_line (iter, include_terminators); + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - gs = iter->run->glyphs; + if (layout->ellipsize == ellipsize) + return; - next_start = iter->next_cluster_glyph; - if (next_start == gs->num_glyphs) - { - return next_nonempty_run (iter, include_terminators); - } - else - { - iter->cluster_start = next_start; - iter->cluster_x += iter->cluster_width; - update_cluster(iter, gs->log_clusters[iter->cluster_start]); + layout->ellipsize = ellipsize; - return TRUE; - } + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ELLIPSIZE]); + layout_changed (layout); } /** - * pango_layout_iter_next_char: - * @iter: a `PangoLayoutIter` + * pango_layout_get_ellipsize: + * @layout: a `PangoLayout` * - * Moves @iter forward to the next character in visual order. + * Gets the type of ellipsization being performed for @layout. * - * If @iter was already at the end of the layout, returns %FALSE. + * See [method@Pango.Layout.set_ellipsize]. * - * Return value: whether motion was possible + * Return value: the current ellipsization mode for @layout */ -gboolean -pango_layout_iter_next_char (PangoLayoutIter *iter) +PangoEllipsizeMode +pango_layout_get_ellipsize (PangoLayout *layout) { - const char *text; - - if (ITER_IS_INVALID (iter)) - return FALSE; - - if (iter->run == NULL) - { - /* We need to fake an iterator position in the middle of a \r\n line terminator */ - if (line_is_terminated (iter) && - strncmp (iter->layout->text + iter->line->start_index + iter->line->length, "\r\n", 2) == 0 && - iter->character_position == 0) - { - iter->character_position++; - return TRUE; - } - - return next_nonempty_line (iter, TRUE); - } - - iter->character_position++; - if (iter->character_position >= iter->cluster_num_chars) - return next_cluster_internal (iter, TRUE); - - text = iter->layout->text; - if (iter->ltr) - iter->index = g_utf8_next_char (text + iter->index) - text; - else - iter->index = g_utf8_prev_char (text + iter->index) - text; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), PANGO_ELLIPSIZE_NONE); - return TRUE; + return layout->ellipsize; } /** - * pango_layout_iter_next_cluster: - * @iter: a `PangoLayoutIter` - * - * Moves @iter forward to the next cluster in visual order. - * - * If @iter was already at the end of the layout, returns %FALSE. + * pango_layout_set_auto_dir: + * @layout: a `PangoLayout` + * @auto_dir: if %TRUE, compute the bidirectional base direction + * from the layout's contents * - * Return value: whether motion was possible - */ -gboolean -pango_layout_iter_next_cluster (PangoLayoutIter *iter) -{ - return next_cluster_internal (iter, FALSE); -} - -/** - * pango_layout_iter_next_run: - * @iter: a `PangoLayoutIter` + * Sets whether to calculate the base direction + * for the layout according to its contents. * - * Moves @iter forward to the next run in visual order. + * When this flag is on (the default), then paragraphs in + * @layout that begin with strong right-to-left characters + * (Arabic and Hebrew principally), will have right-to-left + * layout, paragraphs with letters from other scripts will + * have left-to-right layout. Paragraphs with only neutral + * characters get their direction from the surrounding + * paragraphs. * - * If @iter was already at the end of the layout, returns %FALSE. + * When %FALSE, the choice between left-to-right and right-to-left + * layout is done according to the base direction of the layout's + * `PangoContext`. (See [method@Pango.Context.set_base_dir]). * - * Return value: whether motion was possible + * When the auto-computed direction of a paragraph differs + * from the base direction of the context, the interpretation + * of %PANGO_ALIGN_LEFT and %PANGO_ALIGN_RIGHT are swapped. */ -gboolean -pango_layout_iter_next_run (PangoLayoutIter *iter) +void +pango_layout_set_auto_dir (PangoLayout *layout, + gboolean auto_dir) { - int next_run_start; /* byte index */ - GSList *next_link; - - if (ITER_IS_INVALID (iter)) - return FALSE; - - if (iter->run == NULL) - return pango_layout_iter_next_line (iter); - - next_link = iter->run_list_link->next; + g_return_if_fail (PANGO_IS_LAYOUT (layout)); - if (next_link == NULL) - { - /* Moving on to the zero-width "virtual run" at the end of each - * line - */ - next_run_start = iter->run->item->offset + iter->run->item->length; - iter->run = NULL; - iter->run_list_link = NULL; - } - else - { - iter->run_list_link = next_link; - iter->run = iter->run_list_link->data; - next_run_start = iter->run->item->offset; - } + if (auto_dir == layout->auto_dir) + return; - update_run (iter, next_run_start); + layout->auto_dir = auto_dir; - return TRUE; + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_AUTO_DIR]); + layout_changed (layout); } /** - * pango_layout_iter_next_line: - * @iter: a `PangoLayoutIter` + * pango_layout_get_auto_dir: + * @layout: a `PangoLayout` * - * Moves @iter forward to the start of the next line. + * Gets whether to calculate the base direction for the layout + * according to its contents. * - * If @iter is already on the last line, returns %FALSE. + * See [method@Pango.Layout.set_auto_dir]. * - * Return value: whether motion was possible + * Return value: %TRUE if the bidirectional base direction + * is computed from the layout's contents, %FALSE otherwise */ gboolean -pango_layout_iter_next_line (PangoLayoutIter *iter) +pango_layout_get_auto_dir (PangoLayout *layout) { - GSList *next_link; - - if (ITER_IS_INVALID (iter)) - return FALSE; - - next_link = iter->line_list_link->next; - - if (next_link == NULL) - return FALSE; - - iter->line_list_link = next_link; - - pango_layout_line_unref (iter->line); - - iter->line = iter->line_list_link->data; - - pango_layout_line_ref (iter->line); - - iter->run_list_link = iter->line->runs; - - if (iter->run_list_link) - iter->run = iter->run_list_link->data; - else - iter->run = NULL; - - iter->line_index ++; - - update_run (iter, iter->line->start_index); + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), TRUE); - return TRUE; + return layout->auto_dir; } +/* }}} */ +/* {{{ Miscellaneous */ + /** - * pango_layout_iter_get_char_extents: - * @iter: a `PangoLayoutIter` - * @logical_rect: (out caller-allocates): rectangle to fill with - * logical extents + * pango_layout_set_markup: + * @layout: a `PangoLayout` + * @markup: marked-up text + * @length: length of @markup in bytes, or -1 if it is `NUL`-terminated * - * Gets the extents of the current character, in layout coordinates. + * Sets the layout text and attribute list from marked-up text. * - * Layout coordinates have the origin at the top left of the entire layout. + * See [Pango Markup](pango_markup.html)). * - * Only logical extents can sensibly be obtained for characters; - * ink extents make sense only down to the level of clusters. + * Replaces the current text and attribute list. */ void -pango_layout_iter_get_char_extents (PangoLayoutIter *iter, - PangoRectangle *logical_rect) +pango_layout_set_markup (PangoLayout *layout, + const char *markup, + int length) { - PangoRectangle cluster_rect; - int x0, x1; - - if (ITER_IS_INVALID (iter)) - return; - - if (logical_rect == NULL) - return; - - pango_layout_iter_get_cluster_extents (iter, NULL, &cluster_rect); - - if (iter->run == NULL) - { - /* When on the NULL run, cluster, char, and run all have the - * same extents - */ - *logical_rect = cluster_rect; - return; - } - - if (iter->cluster_num_chars) - { - x0 = (iter->character_position * cluster_rect.width) / iter->cluster_num_chars; - x1 = ((iter->character_position + 1) * cluster_rect.width) / iter->cluster_num_chars; - } - else - { - x0 = x1 = 0; - } - - logical_rect->width = x1 - x0; - logical_rect->height = cluster_rect.height; - logical_rect->y = cluster_rect.y; - logical_rect->x = cluster_rect.x + x0; -} + PangoAttrList *attrs; + char *text; + GError *error = NULL; -/** - * pango_layout_iter_get_cluster_extents: - * @iter: a `PangoLayoutIter` - * @ink_rect: (out) (optional): rectangle to fill with ink extents - * @logical_rect: (out) (optional): rectangle to fill with logical extents - * - * Gets the extents of the current cluster, in layout coordinates. - * - * Layout coordinates have the origin at the top left of the entire layout. - */ -void -pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) -{ - if (ITER_IS_INVALID (iter)) - return; + g_return_if_fail (PANGO_IS_LAYOUT (layout)); + g_return_if_fail (markup != NULL); - if (iter->run == NULL) + if (!pango_parse_markup (markup, length, 0, &attrs, &text, NULL, &error)) { - /* When on the NULL run, cluster, char, and run all have the - * same extents - */ - pango_layout_iter_get_run_extents (iter, ink_rect, logical_rect); + g_warning ("pango_layout_set_markup_with_accel: %s", error->message); + g_error_free (error); return; } - pango_glyph_string_extents_range (iter->run->glyphs, - iter->cluster_start, - iter->next_cluster_glyph, - iter->run->item->analysis.font, - ink_rect, - logical_rect); + g_free (layout->text); + layout->text = text; + layout->length = strlen (text); - if (ink_rect) - { - ink_rect->x += iter->cluster_x + iter->run->start_x_offset; - ink_rect->y -= iter->run->y_offset; - offset_y (iter, &ink_rect->y); - } + g_clear_pointer (&layout->attrs, pango_attr_list_unref); + layout->attrs = attrs; - if (logical_rect) - { - g_assert (logical_rect->width == iter->cluster_width); - logical_rect->x += iter->cluster_x + iter->run->start_x_offset; - logical_rect->y -= iter->run->y_offset; - offset_y (iter, &logical_rect->y); - } + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TEXT]); + g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ATTRIBUTES]); + layout_changed (layout); } /** - * pango_layout_iter_get_run_extents: - * @iter: a `PangoLayoutIter` - * @ink_rect: (out) (optional): rectangle to fill with ink extents - * @logical_rect: (out) (optional): rectangle to fill with logical extents + * pango_layout_get_character_count: + * @layout: a `PangoLayout` * - * Gets the extents of the current run in layout coordinates. + * Returns the number of Unicode characters in the + * the text of @layout. * - * Layout coordinates have the origin at the top left of the entire layout. + * Return value: the number of Unicode characters in @layout */ -void -pango_layout_iter_get_run_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +int +pango_layout_get_character_count (PangoLayout *layout) { - if (G_UNLIKELY (!ink_rect && !logical_rect)) - return; - - if (ITER_IS_INVALID (iter)) - return; - - if (iter->run) - { - pango_layout_run_get_extents_and_height (iter->run, ink_rect, logical_rect, NULL, NULL); - - if (ink_rect) - { - offset_y (iter, &ink_rect->y); - ink_rect->x += iter->run_x; - } - - if (logical_rect) - { - offset_y (iter, &logical_rect->y); - logical_rect->x += iter->run_x; - } - } - else - { - if (iter->line->runs) - { - /* The empty run at the end of a non-empty line */ - PangoLayoutRun *run = g_slist_last (iter->line->runs)->data; - pango_layout_run_get_extents_and_height (run, ink_rect, logical_rect, NULL, NULL); - } - else - { - PangoRectangle r; - - pango_layout_get_empty_extents_and_height_at_index (iter->layout, 0, &r, FALSE, NULL); + PangoLayoutLine *line; - if (ink_rect) - *ink_rect = r; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0); - if (logical_rect) - *logical_rect = r; - } + ensure_lines (layout); - if (ink_rect) - { - offset_y (iter, &ink_rect->y); - ink_rect->x = iter->run_x; - ink_rect->width = 0; - } + line = pango_lines_get_line (layout->lines, 0, NULL, NULL); - if (logical_rect) - { - offset_y (iter, &logical_rect->y); - logical_rect->x = iter->run_x; - logical_rect->width = 0; - } - } + return line->data->n_chars; } +/* }}} */ +/* {{{ Output getters */ + /** - * pango_layout_iter_get_line_extents: - * @iter: a `PangoLayoutIter` - * @ink_rect: (out) (optional): rectangle to fill with ink extents - * @logical_rect: (out) (optional): rectangle to fill with logical extents + * pango_layout_get_lines: + * @layout: a `PangoLayout` + * + * Gets the lines of the @layout. * - * Obtains the extents of the current line. + * The returned object will become invalid when any + * property of @layout is changed. Take a reference + * to keep it. * - * Extents are in layout coordinates (origin is the top-left corner - * of the entire `PangoLayout`). Thus the extents returned by this - * function will be the same width/height but not at the same x/y - * as the extents returned from [method@Pango.LayoutLine.get_extents]. + * Return value: (transfer none): a `PangoLines` object + * with the lines of @layout */ -void -pango_layout_iter_get_line_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) +PangoLines * +pango_layout_get_lines (PangoLayout *layout) { - const Extents *ext; - - if (ITER_IS_INVALID (iter)) - return; - - ext = &iter->line_extents[iter->line_index]; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - if (ink_rect) - { - get_line_extents_layout_coords (iter->layout, iter->line, - iter->layout_width, - ext->logical_rect.y, - NULL, - ink_rect, - NULL); - } + ensure_lines (layout); - if (logical_rect) - *logical_rect = ext->logical_rect; + return layout->lines; } /** - * pango_layout_iter_get_line_yrange: - * @iter: a `PangoLayoutIter` - * @y0_: (out) (optional): start of line - * @y1_: (out) (optional): end of line + * pango_layout_get_log_attrs: + * @layout: a `PangoLayout` + * @n_attrs: (out): return location for the length of the array * - * Divides the vertical space in the `PangoLayout` being iterated over - * between the lines in the layout, and returns the space belonging to - * the current line. + * Gets the `PangoLogAttr` array for the content + * of @layout. * - * A line's range includes the line's logical extents. plus half of the - * spacing above and below the line, if [method@Pango.Layout.set_spacing] - * has been called to set layout spacing. The Y positions are in layout - * coordinates (origin at top left of the entire layout). + * The returned array becomes invalid when + * any properties of @layout change. Make a + * copy if you want to keep it. * - * Note: Since 1.44, Pango uses line heights for placing lines, and there - * may be gaps between the ranges returned by this function. + * Returns: (transfer none): the `PangoLogAttr` array */ -void -pango_layout_iter_get_line_yrange (PangoLayoutIter *iter, - int *y0, - int *y1) +const PangoLogAttr * +pango_layout_get_log_attrs (PangoLayout *layout, + int *n_attrs) { - const Extents *ext; - int half_spacing; - - if (ITER_IS_INVALID (iter)) - return; - - ext = &iter->line_extents[iter->line_index]; - - half_spacing = iter->layout->spacing / 2; - - /* Note that if layout->spacing is odd, the remainder spacing goes - * above the line (this is pretty arbitrary of course) - */ + PangoLayoutLine *line; - if (y0) - { - /* No spacing above the first line */ + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - if (iter->line_index == 0) - *y0 = ext->logical_rect.y; - else - *y0 = ext->logical_rect.y - (iter->layout->spacing - half_spacing); - } + ensure_lines (layout); - if (y1) - { - /* No spacing below the last line */ - if (iter->line_index == iter->layout->line_count - 1) - *y1 = ext->logical_rect.y + ext->logical_rect.height; - else - *y1 = ext->logical_rect.y + ext->logical_rect.height + half_spacing; - } -} + line = pango_lines_get_line (layout->lines, 0, NULL, NULL); -/** - * pango_layout_iter_get_baseline: - * @iter: a `PangoLayoutIter` - * - * Gets the Y position of the current line's baseline, in layout - * coordinates. - * - * Layout coordinates have the origin at the top left of the entire layout. - * - * Return value: baseline of current line - */ -int -pango_layout_iter_get_baseline (PangoLayoutIter *iter) -{ - if (ITER_IS_INVALID (iter)) - return 0; + if (n_attrs) + *n_attrs = line->data->n_chars + 1; - return iter->line_extents[iter->line_index].baseline; + return line->data->log_attrs; } /** - * pango_layout_iter_get_run_baseline: - * @iter: a `PangoLayoutIter` - * - * Gets the Y position of the current run's baseline, in layout - * coordinates. + * pango_layout_get_iter: + * @layout: a `PangoLayout` * - * Layout coordinates have the origin at the top left of the entire layout. + * Returns an iterator to iterate over the visual extents + * of the layout. * - * The run baseline can be different from the line baseline, for - * example due to superscript or subscript positioning. + * This is a convenience wrapper for [method@Pango.Lines.get_iter]. * - * Since: 1.50 + * Returns: the new `PangoLayoutIter` */ -int -pango_layout_iter_get_run_baseline (PangoLayoutIter *iter) +PangoLayoutIter * +pango_layout_get_iter (PangoLayout *layout) { - if (ITER_IS_INVALID (iter)) - return 0; + g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); - if (!iter->run) - return iter->line_extents[iter->line_index].baseline; + ensure_lines (layout); - return iter->line_extents[iter->line_index].baseline - iter->run->y_offset; + return pango_lines_get_iter (layout->lines); } -/** - * pango_layout_iter_get_layout_extents: - * @iter: a `PangoLayoutIter` - * @ink_rect: (out) (optional): rectangle to fill with ink extents - * @logical_rect: (out) (optional): rectangle to fill with logical extents - * - * Obtains the extents of the `PangoLayout` being iterated over. - */ -void -pango_layout_iter_get_layout_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect) -{ - if (ITER_IS_INVALID (iter)) - return; +/* }}} */ +/* }}} */ - pango_layout_get_extents (iter->layout, ink_rect, logical_rect); -} +/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-layout.h b/pango/pango-layout.h index 45152848..1a5d5d41 100644 --- a/pango/pango-layout.h +++ b/pango/pango-layout.h @@ -1,322 +1,162 @@ -/* Pango - * pango-layout.h: High-level layout driver - * - * Copyright (C) 2000 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 - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __PANGO_LAYOUT_H__ -#define __PANGO_LAYOUT_H__ +#pragma once +#include <glib-object.h> #include <pango/pango-types.h> #include <pango/pango-attributes.h> -#include <pango/pango-context.h> -#include <pango/pango-glyph-item.h> +#include <pango/pango-lines.h> #include <pango/pango-tabs.h> G_BEGIN_DECLS -typedef struct _PangoLayout PangoLayout; -typedef struct _PangoLayoutClass PangoLayoutClass; -typedef struct _PangoLayoutLine PangoLayoutLine; - -/** - * PangoLayoutRun: - * - * A `PangoLayoutRun` represents a single run within a `PangoLayoutLine`. - * - * It is simply an alternate name for [struct@Pango.GlyphItem]. - * See the [struct@Pango.GlyphItem] docs for details on the fields. - */ -typedef PangoGlyphItem PangoLayoutRun; - -/** - * PangoLayoutLine: - * @layout: (nullable): the layout this line belongs to, might be %NULL - * @start_index: start of line as byte index into layout->text - * @length: length of line in bytes - * @runs: (nullable) (element-type Pango.LayoutRun): list of runs in the - * line, from left to right - * @is_paragraph_start: #TRUE if this is the first line of the paragraph - * @resolved_dir: #Resolved PangoDirection of line - * - * A `PangoLayoutLine` represents one of the lines resulting from laying - * out a paragraph via `PangoLayout`. - * - * `PangoLayoutLine` structures are obtained by calling - * [method@Pango.Layout.get_line] and are only valid until the text, - * attributes, or settings of the parent `PangoLayout` are modified. - */ -struct _PangoLayoutLine -{ - PangoLayout *layout; - gint start_index; /* start of line as byte index into layout->text */ - gint length; /* length of line in bytes */ - GSList *runs; - guint is_paragraph_start : 1; /* TRUE if this is the first line of the paragraph */ - guint resolved_dir : 3; /* Resolved PangoDirection of line */ -}; - -#define PANGO_TYPE_LAYOUT (pango_layout_get_type ()) -#define PANGO_LAYOUT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_LAYOUT, PangoLayout)) -#define PANGO_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_LAYOUT, PangoLayoutClass)) -#define PANGO_IS_LAYOUT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_LAYOUT)) -#define PANGO_IS_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_LAYOUT)) -#define PANGO_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_LAYOUT, PangoLayoutClass)) - -/* The PangoLayout and PangoLayoutClass structs are private; if you - * need to create a subclass of these, file a bug. - */ +#define PANGO_TYPE_LAYOUT pango_layout_get_type () PANGO_AVAILABLE_IN_ALL -GType pango_layout_get_type (void) G_GNUC_CONST; +G_DECLARE_FINAL_TYPE (PangoLayout, pango_layout, PANGO, LAYOUT, GObject); + PANGO_AVAILABLE_IN_ALL -PangoLayout *pango_layout_new (PangoContext *context); +PangoLayout * pango_layout_new (PangoContext *context); + PANGO_AVAILABLE_IN_ALL -PangoLayout *pango_layout_copy (PangoLayout *src); +PangoLayout * pango_layout_copy (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -PangoContext *pango_layout_get_context (PangoLayout *layout); +guint pango_layout_get_serial (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_attributes (PangoLayout *layout, - PangoAttrList *attrs); +PangoContext * pango_layout_get_context (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -PangoAttrList *pango_layout_get_attributes (PangoLayout *layout); +void pango_layout_context_changed (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_text (PangoLayout *layout, - const char *text, - int length); +void pango_layout_set_text (PangoLayout *layout, + const char *text, + int length); PANGO_AVAILABLE_IN_ALL -const char *pango_layout_get_text (PangoLayout *layout); - -PANGO_AVAILABLE_IN_1_30 -gint pango_layout_get_character_count (PangoLayout *layout); +const char * pango_layout_get_text (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_markup (PangoLayout *layout, - const char *markup, - int length); +void pango_layout_set_markup (PangoLayout *layout, + const char *markup, + int length); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_markup_with_accel (PangoLayout *layout, - const char *markup, - int length, - gunichar accel_marker, - gunichar *accel_char); +int pango_layout_get_character_count + (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_font_description (PangoLayout *layout, - const PangoFontDescription *desc); - -PANGO_AVAILABLE_IN_1_8 -const PangoFontDescription *pango_layout_get_font_description (PangoLayout *layout); +void pango_layout_set_attributes (PangoLayout *layout, + PangoAttrList *attrs); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_width (PangoLayout *layout, - int width); -PANGO_AVAILABLE_IN_ALL -int pango_layout_get_width (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_20 -void pango_layout_set_height (PangoLayout *layout, - int height); -PANGO_AVAILABLE_IN_1_20 -int pango_layout_get_height (PangoLayout *layout); -PANGO_AVAILABLE_IN_ALL -void pango_layout_set_wrap (PangoLayout *layout, - PangoWrapMode wrap); -PANGO_AVAILABLE_IN_ALL -PangoWrapMode pango_layout_get_wrap (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_16 -gboolean pango_layout_is_wrapped (PangoLayout *layout); +PangoAttrList * pango_layout_get_attributes (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_set_indent (PangoLayout *layout, - int indent); +void pango_layout_set_font_description + (PangoLayout *layout, + const PangoFontDescription *desc); + PANGO_AVAILABLE_IN_ALL -int pango_layout_get_indent (PangoLayout *layout); +const PangoFontDescription * + pango_layout_get_font_description + (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_set_spacing (PangoLayout *layout, - int spacing); +void pango_layout_set_line_spacing + (PangoLayout *layout, + float line_spacing); + PANGO_AVAILABLE_IN_ALL -int pango_layout_get_spacing (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_44 -void pango_layout_set_line_spacing (PangoLayout *layout, - float factor); -PANGO_AVAILABLE_IN_1_44 -float pango_layout_get_line_spacing (PangoLayout *layout); +float pango_layout_get_line_spacing + (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_set_justify (PangoLayout *layout, - gboolean justify); +void pango_layout_set_width (PangoLayout *layout, + int width); + PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_get_justify (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_50 -void pango_layout_set_justify_last_line (PangoLayout *layout, - gboolean justify); -PANGO_AVAILABLE_IN_1_50 -gboolean pango_layout_get_justify_last_line (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_4 -void pango_layout_set_auto_dir (PangoLayout *layout, - gboolean auto_dir); -PANGO_AVAILABLE_IN_1_4 -gboolean pango_layout_get_auto_dir (PangoLayout *layout); +int pango_layout_get_width (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_set_alignment (PangoLayout *layout, - PangoAlignment alignment); +void pango_layout_set_height (PangoLayout *layout, + int height); + PANGO_AVAILABLE_IN_ALL -PangoAlignment pango_layout_get_alignment (PangoLayout *layout); +int pango_layout_get_height (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_tabs (PangoLayout *layout, - PangoTabArray *tabs); +void pango_layout_set_tabs (PangoLayout *layout, + PangoTabArray *tabs); + PANGO_AVAILABLE_IN_ALL -PangoTabArray* pango_layout_get_tabs (PangoLayout *layout); +PangoTabArray * pango_layout_get_tabs (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_set_single_paragraph_mode (PangoLayout *layout, - gboolean setting); +void pango_layout_set_single_paragraph + (PangoLayout *layout, + gboolean single_paragraph); PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_get_single_paragraph_mode (PangoLayout *layout); - -PANGO_AVAILABLE_IN_1_6 -void pango_layout_set_ellipsize (PangoLayout *layout, - PangoEllipsizeMode ellipsize); -PANGO_AVAILABLE_IN_1_6 -PangoEllipsizeMode pango_layout_get_ellipsize (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_16 -gboolean pango_layout_is_ellipsized (PangoLayout *layout); - -PANGO_AVAILABLE_IN_1_16 -int pango_layout_get_unknown_glyphs_count (PangoLayout *layout); - -PANGO_AVAILABLE_IN_1_46 -PangoDirection pango_layout_get_direction (PangoLayout *layout, - int index); +gboolean pango_layout_get_single_paragraph + (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_context_changed (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_32 -guint pango_layout_get_serial (PangoLayout *layout); +void pango_layout_set_wrap (PangoLayout *layout, + PangoWrapMode wrap); PANGO_AVAILABLE_IN_ALL -void pango_layout_get_log_attrs (PangoLayout *layout, - PangoLogAttr **attrs, - gint *n_attrs); - -PANGO_AVAILABLE_IN_1_30 -const PangoLogAttr *pango_layout_get_log_attrs_readonly (PangoLayout *layout, - gint *n_attrs); +PangoWrapMode pango_layout_get_wrap (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_index_to_pos (PangoLayout *layout, - int index_, - PangoRectangle *pos); -PANGO_AVAILABLE_IN_ALL -void pango_layout_index_to_line_x (PangoLayout *layout, - int index_, - gboolean trailing, - int *line, - int *x_pos); -PANGO_AVAILABLE_IN_ALL -void pango_layout_get_cursor_pos (PangoLayout *layout, - int index_, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos); +void pango_layout_set_indent (PangoLayout *layout, + int indent); -PANGO_AVAILABLE_IN_1_50 -void pango_layout_get_caret_pos (PangoLayout *layout, - int index_, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos); +PANGO_AVAILABLE_IN_ALL +int pango_layout_get_indent (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_layout_move_cursor_visually (PangoLayout *layout, - gboolean strong, - int old_index, - int old_trailing, - int direction, - int *new_index, - int *new_trailing); +void pango_layout_set_alignment (PangoLayout *layout, + PangoAlignment alignment); + PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_xy_to_index (PangoLayout *layout, - int x, - int y, - int *index_, - int *trailing); +PangoAlignment pango_layout_get_alignment (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_get_extents (PangoLayout *layout, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); +void pango_layout_set_ellipsize (PangoLayout *layout, + PangoEllipsizeMode ellipsize); + PANGO_AVAILABLE_IN_ALL -void pango_layout_get_pixel_extents (PangoLayout *layout, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); +PangoEllipsizeMode pango_layout_get_ellipsize (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -void pango_layout_get_size (PangoLayout *layout, - int *width, - int *height); +void pango_layout_set_auto_dir (PangoLayout *layout, + gboolean auto_dir); + PANGO_AVAILABLE_IN_ALL -void pango_layout_get_pixel_size (PangoLayout *layout, - int *width, - int *height); -PANGO_AVAILABLE_IN_1_22 -int pango_layout_get_baseline (PangoLayout *layout); +gboolean pango_layout_get_auto_dir (PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -int pango_layout_get_line_count (PangoLayout *layout); +PangoLines * pango_layout_get_lines (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -PangoLayoutLine *pango_layout_get_line (PangoLayout *layout, - int line); -PANGO_AVAILABLE_IN_1_16 -PangoLayoutLine *pango_layout_get_line_readonly (PangoLayout *layout, - int line); +PangoLayoutIter * pango_layout_get_iter (PangoLayout *layout); + PANGO_AVAILABLE_IN_ALL -GSList * pango_layout_get_lines (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_16 -GSList * pango_layout_get_lines_readonly (PangoLayout *layout); +const PangoLogAttr * pango_layout_get_log_attrs (PangoLayout *layout, + int *n_attrs); -/** - * PangoLayoutSerializeFlags: - * @PANGO_LAYOUT_SERIALIZE_DEFAULT: Default behavior - * @PANGO_LAYOUT_SERIALIZE_CONTEXT: Include context information - * @PANGO_LAYOUT_SERIALIZE_OUTPUT: Include information about the formatted output - * - * Flags that influence the behavior of [method@Pango.Layout.serialize]. - * - * New members may be added to this enumeration over time. - * - * Since: 1.50 - */ typedef enum { PANGO_LAYOUT_SERIALIZE_DEFAULT = 0, PANGO_LAYOUT_SERIALIZE_CONTEXT = 1 << 0, PANGO_LAYOUT_SERIALIZE_OUTPUT = 1 << 1, } PangoLayoutSerializeFlags; -PANGO_AVAILABLE_IN_1_50 -GBytes * pango_layout_serialize (PangoLayout *layout, - PangoLayoutSerializeFlags flags); - -PANGO_AVAILABLE_IN_1_50 -gboolean pango_layout_write_to_file (PangoLayout *layout, - PangoLayoutSerializeFlags flags, +PANGO_AVAILABLE_IN_ALL +GBytes * pango_layout_serialize (PangoLayout *layout, + PangoLayoutSerializeFlags flags); - const char *filename, - GError **error); +PANGO_AVAILABLE_IN_ALL +gboolean pango_layout_write_to_file (PangoLayout *layout, + const char *filename); #define PANGO_LAYOUT_DESERIALIZE_ERROR (pango_layout_deserialize_error_quark ()) @@ -329,8 +169,6 @@ gboolean pango_layout_write_to_file (PangoLayout * not found * * Errors that can be returned by [func@Pango.Layout.deserialize]. - * - * Since: 1.50 */ typedef enum { PANGO_LAYOUT_DESERIALIZE_INVALID, @@ -338,155 +176,18 @@ typedef enum { PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE, } PangoLayoutDeserializeError; -PANGO_AVAILABLE_IN_1_50 -GQuark pango_layout_deserialize_error_quark (void); - -/** - * PangoLayoutDeserializeFlags: - * @PANGO_LAYOUT_DESERIALIZE_DEFAULT: Default behavior - * @PANGO_LAYOUT_DESERIALIZE_CONTEXT: Apply context information - * from the serialization to the `PangoContext` - * - * Flags that influence the behavior of [func@Pango.Layout.deserialize]. - * - * New members may be added to this enumeration over time. - * - * Since: 1.50 - */ typedef enum { PANGO_LAYOUT_DESERIALIZE_DEFAULT = 0, PANGO_LAYOUT_DESERIALIZE_CONTEXT = 1 << 0, } PangoLayoutDeserializeFlags; -PANGO_AVAILABLE_IN_1_50 -PangoLayout * pango_layout_deserialize (PangoContext *context, - GBytes *bytes, - PangoLayoutDeserializeFlags flags, - GError **error); - - -#define PANGO_TYPE_LAYOUT_LINE (pango_layout_line_get_type ()) - -PANGO_AVAILABLE_IN_ALL -GType pango_layout_line_get_type (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_1_10 -PangoLayoutLine *pango_layout_line_ref (PangoLayoutLine *line); -PANGO_AVAILABLE_IN_ALL -void pango_layout_line_unref (PangoLayoutLine *line); - -PANGO_AVAILABLE_IN_1_50 -int pango_layout_line_get_start_index (PangoLayoutLine *line); -PANGO_AVAILABLE_IN_1_50 -int pango_layout_line_get_length (PangoLayoutLine *line); -PANGO_AVAILABLE_IN_1_50 -gboolean pango_layout_line_is_paragraph_start (PangoLayoutLine *line); -PANGO_AVAILABLE_IN_1_50 -PangoDirection pango_layout_line_get_resolved_direction (PangoLayoutLine *line); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_line_x_to_index (PangoLayoutLine *line, - int x_pos, - int *index_, - int *trailing); -PANGO_AVAILABLE_IN_ALL -void pango_layout_line_index_to_x (PangoLayoutLine *line, - int index_, - gboolean trailing, - int *x_pos); -PANGO_AVAILABLE_IN_ALL -void pango_layout_line_get_x_ranges (PangoLayoutLine *line, - int start_index, - int end_index, - int **ranges, - int *n_ranges); -PANGO_AVAILABLE_IN_ALL -void pango_layout_line_get_extents (PangoLayoutLine *line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); -PANGO_AVAILABLE_IN_1_44 -void pango_layout_line_get_height (PangoLayoutLine *line, - int *height); - -PANGO_AVAILABLE_IN_ALL -void pango_layout_line_get_pixel_extents (PangoLayoutLine *layout_line, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - -typedef struct _PangoLayoutIter PangoLayoutIter; - -#define PANGO_TYPE_LAYOUT_ITER (pango_layout_iter_get_type ()) - -PANGO_AVAILABLE_IN_ALL -GType pango_layout_iter_get_type (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_ALL -PangoLayoutIter *pango_layout_get_iter (PangoLayout *layout); -PANGO_AVAILABLE_IN_1_20 -PangoLayoutIter *pango_layout_iter_copy (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_free (PangoLayoutIter *iter); - -PANGO_AVAILABLE_IN_ALL -int pango_layout_iter_get_index (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -PangoLayoutRun *pango_layout_iter_get_run (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_1_16 -PangoLayoutRun *pango_layout_iter_get_run_readonly (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -PangoLayoutLine *pango_layout_iter_get_line (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_1_16 -PangoLayoutLine *pango_layout_iter_get_line_readonly (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_iter_at_last_line (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_1_20 -PangoLayout *pango_layout_iter_get_layout (PangoLayoutIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_iter_next_char (PangoLayoutIter *iter); PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_iter_next_cluster (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_iter_next_run (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_ALL -gboolean pango_layout_iter_next_line (PangoLayoutIter *iter); +GQuark pango_layout_deserialize_error_quark (void); PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_char_extents (PangoLayoutIter *iter, - PangoRectangle *logical_rect); -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_cluster_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_run_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_line_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); -/* All the yranges meet, unlike the logical_rect's (i.e. the yranges - * assign between-line spacing to the nearest line) - */ -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_line_yrange (PangoLayoutIter *iter, - int *y0_, - int *y1_); -PANGO_AVAILABLE_IN_ALL -void pango_layout_iter_get_layout_extents (PangoLayoutIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); -PANGO_AVAILABLE_IN_ALL -int pango_layout_iter_get_baseline (PangoLayoutIter *iter); -PANGO_AVAILABLE_IN_1_50 -int pango_layout_iter_get_run_baseline (PangoLayoutIter *iter); - - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoLayout, g_object_unref) -G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoLayoutIter, pango_layout_iter_free) +PangoLayout * pango_layout_deserialize (PangoContext *context, + GBytes *bytes, + PangoLayoutDeserializeFlags flags, + GError **error); G_END_DECLS - -#endif /* __PANGO_LAYOUT_H__ */ - diff --git a/pango/pango-line-breaker.c b/pango/pango-line-breaker.c index bb3bd027..175984f2 100644 --- a/pango/pango-line-breaker.c +++ b/pango/pango-line-breaker.c @@ -1,7 +1,7 @@ #include "config.h" #include "pango-line-breaker.h" -#include "pango-line-private.h" +#include "pango-layout-line-private.h" #include "pango-tabs.h" #include "pango-impl-utils.h" @@ -28,10 +28,10 @@ * to influence the formatting. * * Then you can call [method@Pango.LineBreaker.next_line] repeatedly to obtain - * `PangoLine` objects for the text, one by one. + * `PangoLayoutLine` objects for the text, one by one. * * `PangoLineBreaker` is meant to enable use cases like flowing text around images, - * or shaped paragraphs. For simple formatting needs, [class@Pango.SimpleLayout] + * or shaped paragraphs. For simple formatting needs, [class@Pango.Layout] * is probably more convenient to use. */ @@ -401,7 +401,7 @@ get_resolved_dir (PangoLineBreaker *self) static gboolean should_ellipsize_current_line (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { return self->line_ellipsize != PANGO_ELLIPSIZE_NONE && self->line_width >= 0; } @@ -442,7 +442,7 @@ get_decimal_prefix_width (PangoItem *item, } static int -pango_line_compute_width (PangoLine *line) +pango_line_compute_width (PangoLayoutLine *line) { int width = 0; @@ -460,7 +460,7 @@ pango_line_compute_width (PangoLine *line) static inline int get_line_width (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { if (self->remaining_width > -1) return self->line_width - self->remaining_width; @@ -599,8 +599,8 @@ pad_glyphstring_left (PangoLineBreaker *self, } static gboolean -is_tab_run (PangoLine *line, - PangoGlyphItem *run) +is_tab_run (PangoLayoutLine *line, + PangoGlyphItem *run) { return line->data->text[run->item->offset] == '\t'; } @@ -675,7 +675,7 @@ reorder_runs_recurse (GSList *items, } static void -pango_line_reorder (PangoLine *line) +pango_line_reorder (PangoLayoutLine *line) { GSList *logical_runs = line->runs; GSList *tmp_list; @@ -713,7 +713,7 @@ pango_line_reorder (PangoLine *line) } static int -compute_n_chars (PangoLine *line) +compute_n_chars (PangoLayoutLine *line) { int n_chars = 0; @@ -731,7 +731,7 @@ compute_n_chars (PangoLine *line) static void get_tab_pos (PangoLineBreaker *self, - PangoLine *line, + PangoLayoutLine *line, int index, int *tab_pos, PangoTabAlign *alignment, @@ -807,7 +807,7 @@ get_tab_pos (PangoLineBreaker *self, static void shape_tab (PangoLineBreaker *self, - PangoLine *line, + PangoLayoutLine *line, int current_width, PangoItem *item, PangoGlyphString *glyphs) @@ -910,7 +910,7 @@ distribute_letter_spacing (int letter_spacing, static PangoGlyphString * shape_run (PangoLineBreaker *self, - PangoLine *line, + PangoLayoutLine *line, PangoItem *item) { PangoGlyphString *glyphs = pango_glyph_string_new (); @@ -999,7 +999,7 @@ free_run (PangoGlyphItem *run, } static PangoItem * -uninsert_run (PangoLine *line) +uninsert_run (PangoLayoutLine *line) { PangoGlyphItem *run; PangoItem *item; @@ -1020,7 +1020,7 @@ uninsert_run (PangoLine *line) static void insert_run (PangoLineBreaker *self, - PangoLine *line, + PangoLayoutLine *line, PangoItem *run_item, PangoGlyphString *glyphs, gboolean last_run) @@ -1239,7 +1239,7 @@ typedef enum static BreakResult process_item (PangoLineBreaker *self, - PangoLine *line, + PangoLayoutLine *line, gboolean force_fit, gboolean no_break_at_end, gboolean is_last_item) @@ -1585,7 +1585,7 @@ retry_break: static void process_line (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { gboolean have_break = FALSE; /* If we've seen a possible break yet */ int break_remaining_width = 0; /* Remaining width before adding run with break */ @@ -1700,7 +1700,7 @@ done: static void add_missing_hyphen (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { PangoGlyphItem *run; PangoItem *item; @@ -1743,7 +1743,7 @@ add_missing_hyphen (PangoLineBreaker *self, static void zero_line_final_space (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { PangoGlyphItem *run; PangoItem *item; @@ -1802,7 +1802,7 @@ zero_line_final_space (PangoLineBreaker *self, */ static void adjust_line_letter_spacing (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { gboolean reversed; PangoGlyphItem *last_run; @@ -2013,7 +2013,7 @@ collect_baseline_shift (PangoLineBreaker *self, static void apply_baseline_shift (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { int y_offset = 0; PangoItem *prev = NULL; @@ -2041,7 +2041,7 @@ apply_baseline_shift (PangoLineBreaker *self, static void apply_render_attributes (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { GSList *runs; @@ -2068,7 +2068,7 @@ apply_render_attributes (PangoLineBreaker *self, static void postprocess_line (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { add_missing_hyphen (self, line); @@ -2081,7 +2081,7 @@ postprocess_line (PangoLineBreaker *self, apply_baseline_shift (self, line); if (should_ellipsize_current_line (self, line)) - pango_line_ellipsize (line, self->context, self->line_ellipsize, self->line_width); + pango_layout_line_ellipsize (line, self->context, self->line_ellipsize, self->line_width); /* Now convert logical to visual order */ pango_line_reorder (line); @@ -2471,14 +2471,14 @@ pango_line_breaker_done (PangoLineBreaker *self) * Returns: (transfer full) (nullable): the next line, or `NULL` * if @self has no more input */ -PangoLine * +PangoLayoutLine * pango_line_breaker_next_line (PangoLineBreaker *self, int x, int width, PangoWrapMode wrap, PangoEllipsizeMode ellipsize) { - PangoLine *line; + PangoLayoutLine *line; g_return_val_if_fail (PANGO_IS_LINE_BREAKER (self), NULL); @@ -2487,7 +2487,7 @@ pango_line_breaker_next_line (PangoLineBreaker *self, if (!self->items) return NULL; - line = pango_line_new (self->context, self->data); + line = pango_layout_line_new (self->context, self->data); line->start_index = self->line_start_index; line->start_offset = self->line_start_offset; @@ -2530,7 +2530,7 @@ pango_line_breaker_next_line (PangoLineBreaker *self, g_clear_pointer (&self->render_attrs, pango_attr_list_unref); } - pango_line_check_invariants (line); + pango_layout_line_check_invariants (line); return line; } @@ -2556,7 +2556,7 @@ pango_line_breaker_next_line (PangoLineBreaker *self, */ gboolean pango_line_breaker_undo_line (PangoLineBreaker *self, - PangoLine *line) + PangoLayoutLine *line) { if (self->data == NULL && line->start_index == 0 && line->length == line->data->length) diff --git a/pango/pango-line-breaker.h b/pango/pango-line-breaker.h index 050d98ff..fb38318e 100644 --- a/pango/pango-line-breaker.h +++ b/pango/pango-line-breaker.h @@ -4,7 +4,7 @@ #include <pango/pango-types.h> #include <pango/pango-break.h> #include <pango/pango-layout.h> -#include <pango/pango-line.h> +#include <pango/pango-layout-line.h> G_BEGIN_DECLS @@ -44,7 +44,7 @@ PANGO_AVAILABLE_IN_ALL gboolean pango_line_breaker_done (PangoLineBreaker *self); PANGO_AVAILABLE_IN_ALL -PangoLine * pango_line_breaker_next_line (PangoLineBreaker *self, +PangoLayoutLine * pango_line_breaker_next_line (PangoLineBreaker *self, int x, int width, PangoWrapMode wrap, @@ -52,6 +52,6 @@ PangoLine * pango_line_breaker_next_line (PangoLineBreaker * PANGO_AVAILABLE_IN_ALL gboolean pango_line_breaker_undo_line (PangoLineBreaker *self, - PangoLine *line); + PangoLayoutLine *line); G_END_DECLS diff --git a/pango/pango-line-iter-private.h b/pango/pango-line-iter-private.h deleted file mode 100644 index e9ca3799..00000000 --- a/pango/pango-line-iter-private.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "pango-line-iter.h" - -PangoLineIter * pango_line_iter_new (PangoLines *lines); diff --git a/pango/pango-line-iter.h b/pango/pango-line-iter.h deleted file mode 100644 index bfd5d48c..00000000 --- a/pango/pango-line-iter.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include <glib-object.h> - -#include <pango/pango-types.h> -#include <pango/pango-lines.h> -#include <pango/pango-glyph-item.h> - -G_BEGIN_DECLS - -PANGO_AVAILABLE_IN_ALL -GType pango_line_iter_get_type (void) G_GNUC_CONST; - -PANGO_AVAILABLE_IN_ALL -PangoLineIter * pango_line_iter_copy (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_free (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -PangoLines * pango_line_iter_get_lines (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -PangoLine * pango_line_iter_get_line (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_line_iter_at_last_line (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -PangoLayoutRun * pango_line_iter_get_run (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -int pango_line_iter_get_index (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_line_iter_next_line (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_line_iter_next_run (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_line_iter_next_cluster (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_line_iter_next_char (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_layout_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_line_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_trimmed_line_extents - (PangoLineIter *iter, - PangoLeadingTrim trim, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_run_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_cluster_extents (PangoLineIter *iter, - PangoRectangle *ink_rect, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -void pango_line_iter_get_char_extents (PangoLineIter *iter, - PangoRectangle *logical_rect); - -PANGO_AVAILABLE_IN_ALL -int pango_line_iter_get_line_baseline (PangoLineIter *iter); - -PANGO_AVAILABLE_IN_ALL -int pango_line_iter_get_run_baseline (PangoLineIter *iter); - - -G_END_DECLS diff --git a/pango/pango-line-private.h b/pango/pango-line-private.h deleted file mode 100644 index 0bb28174..00000000 --- a/pango/pango-line-private.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "pango-line.h" -#include "pango-break.h" -#include "pango-attributes.h" -#include "pango-glyph-item.h" - -typedef struct _LineData LineData; -struct _LineData { - char *text; - int length; - int n_chars; - PangoDirection direction; - - PangoAttrList *attrs; - PangoLogAttr *log_attrs; -}; - -LineData * line_data_new (void); -LineData * line_data_ref (LineData *data); -void line_data_unref (LineData *data); -void line_data_clear (LineData *data); - -struct _PangoLine -{ - GObject parent_instance; - - PangoContext *context; - LineData *data; - - int start_index; - int length; - int start_offset; - int n_chars; - GSList *runs; - - guint wrapped : 1; - guint ellipsized : 1; - guint hyphenated : 1; - guint justified : 1; - guint starts_paragraph : 1; - guint ends_paragraph : 1; - guint has_extents : 1; - - PangoDirection direction; - - PangoRectangle ink_rect; - PangoRectangle logical_rect; -}; - -PangoLine * pango_line_new (PangoContext *context, - LineData *data); - -void pango_line_ellipsize (PangoLine *line, - PangoContext *context, - PangoEllipsizeMode ellipsize, - int goal_width); - -void pango_line_index_to_run (PangoLine *line, - int idx, - PangoLayoutRun **run); - -void pango_line_get_empty_extents (PangoLine *line, - PangoLeadingTrim trim, - PangoRectangle *logical_rect); - -void pango_line_check_invariants (PangoLine *line); diff --git a/pango/pango-lines.c b/pango/pango-lines.c index 195524bc..663f0581 100644 --- a/pango/pango-lines.c +++ b/pango/pango-lines.c @@ -1,16 +1,16 @@ #include "config.h" #include "pango-lines-private.h" -#include "pango-line-private.h" +#include "pango-layout-line-private.h" #include "pango-item-private.h" -#include "pango-line-iter-private.h" +#include "pango-layout-iter-private.h" /* {{{ PangoLines implementation */ typedef struct _Line Line; struct _Line { - PangoLine *line; + PangoLayoutLine *line; int x, y; }; @@ -71,8 +71,8 @@ compare_cursor (gconstpointer v1, } static void -pango_line_get_cursors (PangoLines *lines, - PangoLine *line, +pango_layout_line_get_cursors (PangoLines *lines, + PangoLayoutLine *line, gboolean strong, GArray *cursors) { @@ -111,7 +111,7 @@ pango_line_get_cursors (PangoLines *lines, { CursorPos cursor; - pango_line_get_cursor_pos (line, idx, + pango_layout_line_get_cursor_pos (line, idx, strong ? &pos : NULL, strong ? NULL : &pos); @@ -167,7 +167,7 @@ pango_lines_get_serial (PangoLines *lines) /** * pango_lines_add_line: * @lines: a `PangoLines` - * @line: (transfer full): the `PangoLine` to add + * @line: (transfer full): the `PangoLayoutLine` to add * @line_x: X coordinate of the position * @line_y: Y coordinate of the position * @@ -179,10 +179,10 @@ pango_lines_get_serial (PangoLines *lines) * Note that this function takes ownership of the line. */ void -pango_lines_add_line (PangoLines *lines, - PangoLine *line, - int x_line, - int y_line) +pango_lines_add_line (PangoLines *lines, + PangoLayoutLine *line, + int x_line, + int y_line) { Line l; @@ -209,12 +209,12 @@ pango_lines_add_line (PangoLines *lines, * * Note that the iter holds a reference to @lines. * - * Return value: the new `PangoLineIter` + * Return value: the new `PangoLayoutIter` */ -PangoLineIter * +PangoLayoutIter * pango_lines_get_iter (PangoLines *lines) { - return pango_line_iter_new (lines); + return pango_layout_iter_new (lines); } /** @@ -242,7 +242,7 @@ pango_lines_get_line_count (PangoLines *lines) * * Returns: (transfer none) (nullable): the line that was found */ -PangoLine * +PangoLayoutLine * pango_lines_get_line (PangoLines *lines, int num, int *line_x, @@ -318,7 +318,7 @@ pango_lines_wrapped (PangoLines *lines) for (int i = 0; i < lines->lines->len; i++) { Line *l = &g_array_index (lines->lines, Line, i); - if (pango_line_wrapped (l->line)) + if (pango_layout_line_wrapped (l->line)) return TRUE; } @@ -339,7 +339,7 @@ pango_lines_ellipsized (PangoLines *lines) for (int i = 0; i < lines->lines->len; i++) { Line *l = &g_array_index (lines->lines, Line, i); - if (pango_line_ellipsized (l->line)) + if (pango_layout_line_ellipsized (l->line)) return TRUE; } @@ -360,7 +360,7 @@ pango_lines_hyphenated (PangoLines *lines) for (int i = 0; i < lines->lines->len; i++) { Line *l = &g_array_index (lines->lines, Line, i); - if (pango_line_hyphenated (l->line)) + if (pango_layout_line_hyphenated (l->line)) return TRUE; } @@ -398,7 +398,7 @@ pango_lines_get_extents (PangoLines *lines, PangoRectangle line_ink; PangoRectangle line_logical; - pango_line_get_extents (l->line, &line_ink, &line_logical); + pango_layout_line_get_extents (l->line, &line_ink, &line_logical); line_ink.x += l->x; line_ink.y += l->y; line_logical.x += l->x; @@ -492,14 +492,14 @@ pango_lines_get_baseline (PangoLines *lines) /** * pango_layout_lines_get_x_ranges: * @lines: a `PangoLines` object - * @line: the `PangoLine` in @lines whose x ranges will be reported - * @start_line: (nullable): `PangoLine` wrt to which @start_index is + * @line: the `PangoLayoutLine` in @lines whose x ranges will be reported + * @start_line: (nullable): `PangoLayoutLine` wrt to which @start_index is * interpreted or `NULL` for the first matching line * @start_index: Start byte index of the logical range. If this value * is less than the start index for the line, then the first range * will extend all the way to the leading edge of the layout. Otherwise, * it will start at the leading edge of the first character. - * @end_line: (nullable): `PangoLine` wrt to which @end_index is + * @end_line: (nullable): `PangoLayoutLine` wrt to which @end_index is * interpreted or `NULL` for the first matching line * @end_index: Ending byte index of the logical range. If this value is * greater than the end index for the line, then the last range will @@ -521,14 +521,14 @@ pango_lines_get_baseline (PangoLines *lines) * layout, not with respect to the line. */ void -pango_lines_get_x_ranges (PangoLines *lines, - PangoLine *line, - PangoLine *start_line, - int start_index, - PangoLine *end_line, - int end_index, - int **ranges, - int *n_ranges) +pango_lines_get_x_ranges (PangoLines *lines, + PangoLayoutLine *line, + PangoLayoutLine *start_line, + int start_index, + PangoLayoutLine *end_line, + int end_index, + int **ranges, + int *n_ranges) { int x_offset; int line_no, start_line_no, end_line_no; @@ -539,10 +539,10 @@ pango_lines_get_x_ranges (PangoLines *lines, int accumulated_width; g_return_if_fail (PANGO_IS_LINES (lines)); - g_return_if_fail (PANGO_IS_LINE (line)); - g_return_if_fail (start_line == NULL || PANGO_IS_LINE (start_line)); + g_return_if_fail (PANGO_IS_LAYOUT_LINE (line)); + g_return_if_fail (start_line == NULL || PANGO_IS_LAYOUT_LINE (start_line)); g_return_if_fail (start_index >= 0); - g_return_if_fail (end_line == NULL || PANGO_IS_LINE (end_line)); + g_return_if_fail (end_line == NULL || PANGO_IS_LAYOUT_LINE (end_line)); g_return_if_fail (end_index >= 0); g_return_if_fail (ranges != NULL); g_return_if_fail (n_ranges != NULL); @@ -572,7 +572,7 @@ pango_lines_get_x_ranges (PangoLines *lines, *ranges = g_new (int, 2 * (2 + g_slist_length (line->runs))); range_count = 0; - dir = pango_line_get_resolved_direction (line); + dir = pango_layout_line_get_resolved_direction (line); if (x_offset > 0 && ((dir == PANGO_DIRECTION_LTR && start_line_no < line_no) || @@ -585,7 +585,7 @@ pango_lines_get_x_ranges (PangoLines *lines, } accumulated_width = 0; - for (GSList *l = pango_line_get_runs (line); l; l = l->next) + for (GSList *l = pango_layout_line_get_runs (line); l; l = l->next) { PangoGlyphItem *run = l->data; @@ -636,7 +636,7 @@ pango_lines_get_x_ranges (PangoLines *lines, accumulated_width += pango_glyph_string_get_width (run->glyphs); } - pango_line_get_extents (line, NULL, &ext); + pango_layout_line_get_extents (line, NULL, &ext); pango_lines_get_size (lines, &width, NULL); if (x_offset + ext.width < width && @@ -678,12 +678,12 @@ pango_lines_get_x_ranges (PangoLines *lines, * as *@line and use this function to find the line at @idx. */ void -pango_lines_index_to_line (PangoLines *lines, - int idx, - PangoLine **line, - int *line_no, - int *x_offset, - int *y_offset) +pango_lines_index_to_line (PangoLines *lines, + int idx, + PangoLayoutLine **line, + int *line_no, + int *x_offset, + int *y_offset) { Line *found = NULL; int num; @@ -740,12 +740,12 @@ pango_lines_index_to_line (PangoLines *lines, * Returns: (transfer none) (nullable): the line that was found */ -PangoLine * -pango_lines_pos_to_line (PangoLines *lines, - int x, - int y, - int *line_x, - int *line_y) +PangoLayoutLine * +pango_lines_pos_to_line (PangoLines *lines, + int x, + int y, + int *line_x, + int *line_y) { g_return_val_if_fail (PANGO_IS_LINES (lines), FALSE); @@ -754,7 +754,7 @@ pango_lines_pos_to_line (PangoLines *lines, Line *l = &g_array_index (lines->lines, Line, i); PangoRectangle ext; - pango_line_get_extents (l->line, NULL, &ext); + pango_layout_line_get_extents (l->line, NULL, &ext); ext.x += l->x; ext.y += l->y; @@ -782,12 +782,12 @@ pango_lines_pos_to_line (PangoLines *lines, /** * pango_lines_index_to_pos: * @lines: a `PangoLines` object - * @line: (nullable): `PangoLine` wrt to which @idx is interpreted + * @line: (nullable): `PangoLayoutLine` wrt to which @idx is interpreted * or `NULL` for the first matching line * @idx: byte index within @line * @pos: (out): rectangle in which to store the position of the grapheme * - * Converts from an index within a `PangoLine` to the + * Converts from an index within a `PangoLayoutLine` to the * position corresponding to the grapheme at that index. * * The return value is represented as rectangle. Note that `pos->x` @@ -799,15 +799,15 @@ pango_lines_pos_to_line (PangoLines *lines, * for the position off the end of the last line. */ void -pango_lines_index_to_pos (PangoLines *lines, - PangoLine *line, - int idx, - PangoRectangle *pos) +pango_lines_index_to_pos (PangoLines *lines, + PangoLayoutLine *line, + int idx, + PangoRectangle *pos) { int x_offset, y_offset; g_return_if_fail (PANGO_IS_LINES (lines)); - g_return_if_fail (line == NULL || PANGO_IS_LINE (line)); + g_return_if_fail (line == NULL || PANGO_IS_LAYOUT_LINE (line)); g_return_if_fail (idx >= 0); g_return_if_fail (pos != NULL); @@ -815,7 +815,7 @@ pango_lines_index_to_pos (PangoLines *lines, g_return_if_fail (line != NULL); - pango_line_index_to_pos (line, idx, pos); + pango_layout_line_index_to_pos (line, idx, pos); pos->x += x_offset; pos->y += y_offset; } @@ -836,14 +836,14 @@ pango_lines_index_to_pos (PangoLines *lines, * * Returns: (transfer none) (nullable): the line that was found */ -PangoLine * -pango_lines_pos_to_index (PangoLines *lines, - int x, - int y, - int *idx, - int *trailing) +PangoLayoutLine * +pango_lines_pos_to_index (PangoLines *lines, + int x, + int y, + int *idx, + int *trailing) { - PangoLine *line; + PangoLayoutLine *line; int x_offset; g_return_val_if_fail (PANGO_IS_LINES (lines), FALSE); @@ -852,7 +852,7 @@ pango_lines_pos_to_index (PangoLines *lines, line = pango_lines_pos_to_line (lines, x, y, &x_offset, NULL); if (line) - pango_line_x_to_index (line, x - x_offset, idx, trailing); + pango_layout_line_x_to_index (line, x - x_offset, idx, trailing); return line; } @@ -863,7 +863,7 @@ pango_lines_pos_to_index (PangoLines *lines, /** * pango_lines_get_cursor_pos: * @lines: a `PangoLines` object - * @line: (nullable): `PangoLine` wrt to which @idx is interpreted + * @line: (nullable): `PangoLayoutLine` wrt to which @idx is interpreted * or `NULL` for the first matching line * @idx: the byte index of the cursor * @strong_pos: (out) (optional): location to store the strong cursor position @@ -901,17 +901,17 @@ pango_lines_pos_to_index (PangoLines *lines, * will insert it at the end. */ void -pango_lines_get_cursor_pos (PangoLines *lines, - PangoLine *line, - int idx, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) +pango_lines_get_cursor_pos (PangoLines *lines, + PangoLayoutLine *line, + int idx, + PangoRectangle *strong_pos, + PangoRectangle *weak_pos) { int x_offset, y_offset; - PangoLine *l; + PangoLayoutLine *l; g_return_if_fail (PANGO_IS_LINES (lines)); - g_return_if_fail (line == NULL || PANGO_IS_LINE (line)); + g_return_if_fail (line == NULL || PANGO_IS_LAYOUT_LINE (line)); l = line; pango_lines_index_to_line (lines, idx, &l, NULL, &x_offset, &y_offset); @@ -921,7 +921,7 @@ pango_lines_get_cursor_pos (PangoLines *lines, line = l; - pango_line_get_cursor_pos (line, idx, strong_pos, weak_pos); + pango_layout_line_get_cursor_pos (line, idx, strong_pos, weak_pos); if (strong_pos) { @@ -938,7 +938,7 @@ pango_lines_get_cursor_pos (PangoLines *lines, /** * pango_lines_get_caret_pos: * @lines: a `PangoLines` object - * @line: (nullable): `PangoLine` wrt to which @idx is interpreted + * @line: (nullable): `PangoLayoutLine` wrt to which @idx is interpreted * or `NULL` for the first matching line * @idx: the byte index of the cursor * @strong_pos: (out) (optional): location to store the strong cursor position @@ -960,22 +960,22 @@ pango_lines_get_cursor_pos (PangoLines *lines, * </picture> */ void -pango_lines_get_caret_pos (PangoLines *lines, - PangoLine *line, - int idx, - PangoRectangle *strong_pos, - PangoRectangle *weak_pos) +pango_lines_get_caret_pos (PangoLines *lines, + PangoLayoutLine *line, + int idx, + PangoRectangle *strong_pos, + PangoRectangle *weak_pos) { int x_offset, y_offset; g_return_if_fail (PANGO_IS_LINES (lines)); - g_return_if_fail (line == NULL || PANGO_IS_LINE (line)); + g_return_if_fail (line == NULL || PANGO_IS_LAYOUT_LINE (line)); pango_lines_index_to_line (lines, idx, &line, NULL, &x_offset, &y_offset); g_return_if_fail (line != NULL); - pango_line_get_caret_pos (line, idx, strong_pos, weak_pos); + pango_layout_line_get_caret_pos (line, idx, strong_pos, weak_pos); if (strong_pos) { @@ -995,7 +995,7 @@ pango_lines_get_caret_pos (PangoLines *lines, * @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. - * @line: (nullable): `PangoLine` wrt to which @idx is interpreted + * @line: (nullable): `PangoLayoutLine` wrt to which @idx is interpreted * or `NULL` for the first matching line * @idx: the byte index of the current cursor position * @trailing: if 0, the cursor was at the leading edge of the @@ -1003,7 +1003,7 @@ pango_lines_get_caret_pos (PangoLines *lines, * was at the trailing edge. * @direction: direction to move cursor. A negative * value indicates motion to the left - * @new_line: `PangoLine` wrt to which @new_idx is interpreted + * @new_line: `PangoLayoutLine` wrt to which @new_idx is interpreted * @new_idx: (out): 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 @@ -1032,15 +1032,15 @@ pango_lines_get_caret_pos (PangoLines *lines, * when multiple characters combine to form a single grapheme. */ void -pango_lines_move_cursor (PangoLines *lines, - gboolean strong, - PangoLine *line, - int idx, - int trailing, - int direction, - PangoLine **new_line, - int *new_idx, - int *new_trailing) +pango_lines_move_cursor (PangoLines *lines, + gboolean strong, + PangoLayoutLine *line, + int idx, + int trailing, + int direction, + PangoLayoutLine **new_line, + int *new_idx, + int *new_trailing) { int line_no; GArray *cursors; @@ -1073,7 +1073,7 @@ pango_lines_move_cursor (PangoLines *lines, idx = line->start_index + line->length; cursors = g_array_new (FALSE, FALSE, sizeof (CursorPos)); - pango_line_get_cursors (lines, line, strong, cursors); + pango_layout_line_get_cursors (lines, line, strong, cursors); pango_lines_get_cursor_pos (lines, line, idx, strong ? &pos : NULL, strong ? NULL : &pos); @@ -1125,7 +1125,7 @@ pango_lines_move_cursor (PangoLines *lines, if (off_start) { - PangoLine *prev_line; + PangoLayoutLine *prev_line; prev_line = pango_lines_get_line (lines, line_no - 1, NULL, NULL); if (!prev_line) @@ -1143,7 +1143,7 @@ pango_lines_move_cursor (PangoLines *lines, } else { - PangoLine *next_line; + PangoLayoutLine *next_line; next_line = pango_lines_get_line (lines, line_no + 1, NULL, NULL); if (!next_line) @@ -1160,7 +1160,7 @@ pango_lines_move_cursor (PangoLines *lines, } g_array_set_size (cursors, 0); - pango_line_get_cursors (lines, line, strong, cursors); + pango_layout_line_get_cursors (lines, line, strong, cursors); n_vis = cursors->len; diff --git a/pango/pango-lines.h b/pango/pango-lines.h index 1ed2b86e..b61d5a84 100644 --- a/pango/pango-lines.h +++ b/pango/pango-lines.h @@ -3,7 +3,7 @@ #include <glib-object.h> #include <pango/pango-types.h> -#include <pango/pango-line.h> +#include <pango/pango-layout-line.h> G_BEGIN_DECLS @@ -12,7 +12,7 @@ G_BEGIN_DECLS PANGO_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (PangoLines, pango_lines, PANGO, LINES, GObject); -typedef struct _PangoLineIter PangoLineIter; +typedef struct _PangoLayoutIter PangoLayoutIter; PANGO_AVAILABLE_IN_ALL PangoLines * pango_lines_new (void); @@ -22,7 +22,7 @@ guint pango_lines_get_serial (PangoLines *lines); PANGO_AVAILABLE_IN_ALL void pango_lines_add_line (PangoLines *lines, - PangoLine *line, + PangoLayoutLine *line, int line_x, int line_y); @@ -30,13 +30,13 @@ PANGO_AVAILABLE_IN_ALL int pango_lines_get_line_count (PangoLines *lines); PANGO_AVAILABLE_IN_ALL -PangoLine * pango_lines_get_line (PangoLines *lines, +PangoLayoutLine * pango_lines_get_line (PangoLines *lines, int num, int *line_x, int *line_y); PANGO_AVAILABLE_IN_ALL -PangoLineIter * pango_lines_get_iter (PangoLines *lines); +PangoLayoutIter * pango_lines_get_iter (PangoLines *lines); PANGO_AVAILABLE_IN_ALL void pango_lines_get_extents (PangoLines *lines, @@ -53,10 +53,10 @@ int pango_lines_get_baseline (PangoLines *lines); PANGO_AVAILABLE_IN_ALL void pango_lines_get_x_ranges (PangoLines *lines, - PangoLine *line, - PangoLine *start_line, + PangoLayoutLine *line, + PangoLayoutLine *start_line, int start_index, - PangoLine *end_line, + PangoLayoutLine *end_line, int end_index, int **ranges, int *n_ranges); @@ -77,13 +77,13 @@ gboolean pango_lines_hyphenated (PangoLines *lines); PANGO_AVAILABLE_IN_ALL void pango_lines_index_to_line (PangoLines *lines, int idx, - PangoLine **line, + PangoLayoutLine **line, int *line_no, int *x_offset, int *y_offset); PANGO_AVAILABLE_IN_ALL -PangoLine * pango_lines_pos_to_line (PangoLines *lines, +PangoLayoutLine * pango_lines_pos_to_line (PangoLines *lines, int x, int y, int *line_x, @@ -91,12 +91,12 @@ PangoLine * pango_lines_pos_to_line (PangoLines *lines, PANGO_AVAILABLE_IN_ALL void pango_lines_index_to_pos (PangoLines *lines, - PangoLine *line, + PangoLayoutLine *line, int idx, PangoRectangle *pos); PANGO_AVAILABLE_IN_ALL -PangoLine * pango_lines_pos_to_index (PangoLines *lines, +PangoLayoutLine * pango_lines_pos_to_index (PangoLines *lines, int x, int y, int *idx, @@ -104,14 +104,14 @@ PangoLine * pango_lines_pos_to_index (PangoLines *lines, PANGO_AVAILABLE_IN_ALL void pango_lines_get_cursor_pos (PangoLines *lines, - PangoLine *line, + PangoLayoutLine *line, int idx, PangoRectangle *strong_pos, PangoRectangle *weak_pos); PANGO_AVAILABLE_IN_ALL void pango_lines_get_caret_pos (PangoLines *lines, - PangoLine *line, + PangoLayoutLine *line, int idx, PangoRectangle *strong_pos, PangoRectangle *weak_pos); @@ -119,11 +119,11 @@ void pango_lines_get_caret_pos (PangoLines *lines, PANGO_AVAILABLE_IN_ALL void pango_lines_move_cursor (PangoLines *lines, gboolean strong, - PangoLine *line, + PangoLayoutLine *line, int idx, int trailing, int direction, - PangoLine **new_line, + PangoLayoutLine **new_line, int *new_idx, int *new_trailing); diff --git a/pango/pango-renderer.c b/pango/pango-renderer.c index afb9b360..c7a81c6a 100644 --- a/pango/pango-renderer.c +++ b/pango/pango-renderer.c @@ -24,9 +24,9 @@ #include "pango-renderer.h" #include "pango-impl-utils.h" -#include "pango-layout-private.h" -#include "pango-line-private.h" +#include "pango-layout.h" #include "pango-layout-run-private.h" +#include "pango-layout-line-private.h" #define N_RENDER_PARTS 5 @@ -64,6 +64,7 @@ struct _PangoRendererPrivate gboolean color_set[N_RENDER_PARTS]; guint16 alpha[N_RENDER_PARTS]; + PangoLines *lines; PangoLayoutLine *line; LineState *line_state; PangoOverline overline; @@ -94,8 +95,8 @@ static void pango_renderer_default_draw_error_underline (PangoRenderer *rende static void pango_renderer_default_prepare_run (PangoRenderer *renderer, PangoLayoutRun *run); -static void pango_renderer_prepare_run (PangoRenderer *renderer, - PangoLayoutRun *run); +static void pango_renderer_prepare_run (PangoRenderer *renderer, + PangoLayoutRun *run); static void to_device (PangoMatrix *matrix, @@ -164,60 +165,6 @@ pango_renderer_activate_with_context (PangoRenderer *renderer, pango_renderer_activate (renderer); } -/** - * pango_renderer_draw_layout: - * @renderer: a `PangoRenderer` - * @layout: a `PangoLayout` - * @x: X position of left edge of baseline, in user space coordinates - * in Pango units. - * @y: Y position of left edge of baseline, in user space coordinates - * in Pango units. - * - * Draws @layout with the specified `PangoRenderer`. - * - * This is equivalent to drawing the lines of the layout, at their - * respective positions relative to @x, @y. - * - * Since: 1.8 - */ -void -pango_renderer_draw_layout (PangoRenderer *renderer, - PangoLayout *layout, - int x, - int y) -{ - PangoLayoutIter iter; - - g_return_if_fail (PANGO_IS_RENDERER (renderer)); - g_return_if_fail (PANGO_IS_LAYOUT (layout)); - - pango_renderer_activate_with_context (renderer, pango_layout_get_context (layout)); - - _pango_layout_get_iter (layout, &iter); - - do - { - PangoRectangle logical_rect; - PangoLayoutLine *line; - int baseline; - - line = pango_layout_iter_get_line_readonly (&iter); - - pango_layout_iter_get_line_extents (&iter, NULL, &logical_rect); - baseline = pango_layout_iter_get_baseline (&iter); - - pango_renderer_draw_layout_line (renderer, - line, - x + logical_rect.x, - y + baseline); - } - while (pango_layout_iter_next_line (&iter)); - - _pango_layout_iter_destroy (&iter); - - pango_renderer_deactivate (renderer); -} - static void draw_underline (PangoRenderer *renderer, LineState *state) @@ -577,65 +524,12 @@ static void pango_renderer_draw_runs (PangoRenderer *renderer, * This draws the glyph items that make up the line, as well as * shapes, backgrounds and lines that are specified by the attributes * of those items. - * - * Since: 1.8 */ void pango_renderer_draw_layout_line (PangoRenderer *renderer, - PangoLayoutLine *line, - int x, - int y) -{ - LineState state = { 0, }; - const char *text; - - g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer)); - - pango_renderer_activate_with_context (renderer, - line->layout ? pango_layout_get_context (line->layout) : NULL); - - renderer->priv->line = line; - renderer->priv->line_state = &state; - - state.underline = PANGO_UNDERLINE_NONE; - state.overline = PANGO_OVERLINE_NONE; - state.strikethrough = FALSE; - - text = G_LIKELY (line->layout) ? pango_layout_get_text (line->layout) : NULL; - - pango_renderer_draw_runs (renderer, line->runs, text, x, y); - - /* Finish off any remaining underlines */ - draw_underline (renderer, &state); - draw_overline (renderer, &state); - draw_strikethrough (renderer, &state); - - renderer->priv->line_state = NULL; - renderer->priv->line = NULL; - - pango_renderer_deactivate (renderer); -} - -/** - * pango_renderer_draw_line: - * @renderer: a `PangoRenderer` - * @line: a `PangoLine` - * @x: X position of left edge of baseline, in user space coordinates - * in Pango units. - * @y: Y position of left edge of baseline, in user space coordinates - * in Pango units. - * - * Draws @line with the specified `PangoRenderer`. - * - * This draws the glyph items that make up the line, as well as - * shapes, backgrounds and lines that are specified by the attributes - * of those items. - */ -void -pango_renderer_draw_line (PangoRenderer *renderer, - PangoLine *line, - int x, - int y) + PangoLayoutLine *line, + int x, + int y) { LineState state = { 0, }; @@ -643,7 +537,7 @@ pango_renderer_draw_line (PangoRenderer *renderer, pango_renderer_activate_with_context (renderer, line->context); - renderer->priv->line = NULL; + renderer->priv->line = line; renderer->priv->line_state = &state; state.underline = PANGO_UNDERLINE_NONE; @@ -657,6 +551,7 @@ pango_renderer_draw_line (PangoRenderer *renderer, draw_overline (renderer, &state); draw_strikethrough (renderer, &state); + renderer->priv->line = NULL; renderer->priv->line_state = NULL; renderer->priv->line = NULL; @@ -681,7 +576,7 @@ pango_renderer_draw_lines (PangoRenderer *renderer, int y) { int n; - PangoLine *line; + PangoLayoutLine *line; int line_x, line_y; g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer)); @@ -694,13 +589,15 @@ pango_renderer_draw_lines (PangoRenderer *renderer, if (n == 0) pango_renderer_activate_with_context (renderer, line->context); - pango_renderer_draw_line (renderer, line, x + line_x, y + line_y); + pango_renderer_draw_layout_line (renderer, line, x + line_x, y + line_y); n++; } if (n > 0) pango_renderer_deactivate (renderer); + + renderer->priv->lines = NULL; } static void @@ -917,8 +814,8 @@ pango_renderer_default_draw_glyphs (PangoRenderer *renderer, * * Note that this method does not handle attributes in @glyph_item. * If you want colors, shapes and lines handled automatically according - * to those attributes, you need to use pango_renderer_draw_layout_line() - * or pango_renderer_draw_layout(). + * to those attributes, you need to use [method@Pango.Renderer.draw_layout_line] + * or [method@Pango.Renderer.draw_lines]. * * Note that @text is the start of the text for layout, which is then * indexed by `glyph_item->item->offset`. @@ -1340,7 +1237,7 @@ pango_renderer_draw_glyph (PangoRenderer *renderer, * Does initial setup before rendering operations on @renderer. * * [method@Pango.Renderer.deactivate] should be called when done drawing. - * Calls such as [method@Pango.Renderer.draw_layout] automatically + * Calls such as [method@Pango.Renderer.draw_lines] automatically * activate the layout before drawing on it. * * Calls to [method@Pango.Renderer.activate] and @@ -1698,10 +1595,10 @@ pango_renderer_get_matrix (PangoRenderer *renderer) } /** - * pango_renderer_get_layout: + * pango_renderer_get_lines: * @renderer: a `PangoRenderer` * - * Gets the layout currently being rendered using @renderer. + * Gets the `PangoLines` currently being rendered using @renderer. * * Calling this function only makes sense from inside a subclass's * methods, like in its draw_shape vfunc, for example. @@ -1709,18 +1606,13 @@ pango_renderer_get_matrix (PangoRenderer *renderer) * The returned layout should not be modified while still being * rendered. * - * Return value: (transfer none) (nullable): the layout, or %NULL if - * no layout is being rendered using @renderer at this time. - * - * Since: 1.20 + * Return value: (transfer none) (nullable): the `PangoLines`, or + * %NULL if no layout is being rendered using @renderer at this time. */ -PangoLayout * -pango_renderer_get_layout (PangoRenderer *renderer) +PangoLines * +pango_renderer_get_lines (PangoRenderer *renderer) { - if (G_UNLIKELY (renderer->priv->line == NULL)) - return NULL; - - return renderer->priv->line->layout; + return renderer->priv->lines; } /** @@ -1737,8 +1629,6 @@ pango_renderer_get_layout (PangoRenderer *renderer) * * Return value: (transfer none) (nullable): the layout line, or %NULL * if no layout line is being rendered using @renderer at this time. - * - * Since: 1.20 */ PangoLayoutLine * pango_renderer_get_layout_line (PangoRenderer *renderer) diff --git a/pango/pango-renderer.h b/pango/pango-renderer.h index 61f18a72..08d49dfc 100644 --- a/pango/pango-renderer.h +++ b/pango/pango-renderer.h @@ -22,8 +22,9 @@ #define __PANGO_RENDERER_H_ #include <pango/pango-layout.h> -#include <pango/pango-line.h> #include <pango/pango-lines.h> +#include <pango/pango-glyph.h> +#include <pango/pango-glyph-item.h> G_BEGIN_DECLS @@ -199,24 +200,15 @@ struct _PangoRendererClass PANGO_AVAILABLE_IN_1_8 GType pango_renderer_get_type (void) G_GNUC_CONST; -PANGO_AVAILABLE_IN_1_8 -void pango_renderer_draw_layout (PangoRenderer *renderer, - PangoLayout *layout, - int x, - int y); -PANGO_AVAILABLE_IN_1_8 -void pango_renderer_draw_layout_line (PangoRenderer *renderer, - PangoLayoutLine *line, - int x, - int y); PANGO_AVAILABLE_IN_ALL -void pango_renderer_draw_line (PangoRenderer *renderer, - PangoLine *line, +void pango_renderer_draw_lines (PangoRenderer *renderer, + PangoLines *lines, int x, int y); + PANGO_AVAILABLE_IN_ALL -void pango_renderer_draw_lines (PangoRenderer *renderer, - PangoLines *lines, +void pango_renderer_draw_layout_line (PangoRenderer *renderer, + PangoLayoutLine *line, int x, int y); PANGO_AVAILABLE_IN_1_8 @@ -291,10 +283,11 @@ void pango_renderer_set_matrix (PangoRenderer *renderer, PANGO_AVAILABLE_IN_1_8 const PangoMatrix *pango_renderer_get_matrix (PangoRenderer *renderer); -PANGO_AVAILABLE_IN_1_20 -PangoLayout *pango_renderer_get_layout (PangoRenderer *renderer); -PANGO_AVAILABLE_IN_1_20 -PangoLayoutLine *pango_renderer_get_layout_line (PangoRenderer *renderer); +PANGO_AVAILABLE_IN_ALL +PangoLines * pango_renderer_get_lines (PangoRenderer *renderer); + +PANGO_AVAILABLE_IN_ALL +PangoLayoutLine * pango_renderer_get_layout_line (PangoRenderer *renderer); PANGO_AVAILABLE_IN_ALL PangoContext * pango_renderer_get_context (PangoRenderer *renderer); diff --git a/pango/pango-simple-layout.c b/pango/pango-simple-layout.c deleted file mode 100644 index adddd2fb..00000000 --- a/pango/pango-simple-layout.c +++ /dev/null @@ -1,1554 +0,0 @@ -#include "config.h" - -#include "pango-simple-layout.h" -#include "pango-line-breaker.h" -#include "pango-lines.h" -#include "pango-line-private.h" -#include "pango-enum-types.h" -#include "pango-markup.h" - -/* {{{ PangoSimpleLayout implementation */ - -struct _PangoSimpleLayout -{ - GObject parent_instance; - - PangoContext *context; - char *text; - int length; - PangoAttrList *attrs; - PangoFontDescription *font_desc; - float line_spacing; - int width; - int height; - PangoTabArray *tabs; - gboolean single_paragraph; - PangoWrapMode wrap; - int indent; - guint serial; - guint context_serial; - PangoAlignmentMode alignment; - PangoEllipsizeMode ellipsize; - gboolean auto_dir; - - PangoLines *lines; -}; - -struct _PangoSimpleLayoutClass -{ - GObjectClass parent_class; -}; - -enum -{ - PROP_CONTEXT = 1, - PROP_TEXT, - PROP_ATTRIBUTES, - PROP_FONT_DESCRIPTION, - PROP_LINE_SPACING, - PROP_WIDTH, - PROP_HEIGHT, - PROP_TABS, - PROP_SINGLE_PARAGRAPH, - PROP_WRAP, - PROP_INDENT, - PROP_ALIGNMENT, - PROP_ELLIPSIZE, - PROP_AUTO_DIR, - PROP_LINES, - NUM_PROPERTIES -}; - -static GParamSpec *props[NUM_PROPERTIES] = { NULL, }; - -G_DEFINE_TYPE (PangoSimpleLayout, pango_simple_layout, G_TYPE_OBJECT) - -static void -pango_simple_layout_init (PangoSimpleLayout *layout) -{ - layout->serial = 1; - layout->width = -1; - layout->height = -1; - layout->indent = 0; - layout->single_paragraph = FALSE; - layout->wrap = PANGO_WRAP_WORD; - layout->alignment = PANGO_ALIGNMENT_LEFT; - layout->ellipsize = PANGO_ELLIPSIZE_NONE; - layout->line_spacing = 0.0; - layout->auto_dir = TRUE; - layout->text = g_strdup (""); - layout->length = 0; -} - -static void -pango_simple_layout_finalize (GObject *object) -{ - PangoSimpleLayout *layout = PANGO_SIMPLE_LAYOUT (object); - - if (layout->font_desc) - pango_font_description_free (layout->font_desc); - g_object_unref (layout->context); - g_free (layout->text); - g_clear_pointer (&layout->attrs, pango_attr_list_unref); - g_clear_pointer (&layout->tabs, pango_tab_array_free); - g_clear_object (&layout->lines); - - G_OBJECT_CLASS (pango_simple_layout_parent_class)->finalize (object); -} - -static void -pango_simple_layout_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - PangoSimpleLayout *layout = PANGO_SIMPLE_LAYOUT (object); - - switch (prop_id) - { - case PROP_CONTEXT: - layout->context = g_value_dup_object (value); - layout->context_serial = pango_context_get_serial (layout->context); - break; - - case PROP_TEXT: - pango_simple_layout_set_text (layout, g_value_get_string (value), -1); - break; - - case PROP_ATTRIBUTES: - pango_simple_layout_set_attributes (layout, g_value_get_boxed (value)); - break; - - case PROP_FONT_DESCRIPTION: - pango_simple_layout_set_font_description (layout, g_value_get_boxed (value)); - break; - - case PROP_LINE_SPACING: - pango_simple_layout_set_line_spacing (layout, g_value_get_float (value)); - break; - - case PROP_WIDTH: - pango_simple_layout_set_width (layout, g_value_get_int (value)); - break; - - case PROP_HEIGHT: - pango_simple_layout_set_height (layout, g_value_get_int (value)); - break; - - case PROP_TABS: - pango_simple_layout_set_tabs (layout, g_value_get_boxed (value)); - break; - - case PROP_SINGLE_PARAGRAPH: - pango_simple_layout_set_single_paragraph (layout, g_value_get_boolean (value)); - break; - - case PROP_WRAP: - pango_simple_layout_set_wrap (layout, g_value_get_enum (value)); - break; - - case PROP_INDENT: - pango_simple_layout_set_indent (layout, g_value_get_int (value)); - break; - - case PROP_ALIGNMENT: - pango_simple_layout_set_alignment (layout, g_value_get_enum (value)); - break; - - case PROP_ELLIPSIZE: - pango_simple_layout_set_ellipsize (layout, g_value_get_enum (value)); - break; - - case PROP_AUTO_DIR: - pango_simple_layout_set_auto_dir (layout, g_value_get_boolean (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -pango_simple_layout_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PangoSimpleLayout *layout = PANGO_SIMPLE_LAYOUT (object); - - switch (prop_id) - { - case PROP_CONTEXT: - g_value_set_object (value, layout->context); - break; - - case PROP_TEXT: - g_value_set_string (value, layout->text); - break; - - case PROP_ATTRIBUTES: - g_value_set_boxed (value, layout->attrs); - break; - - case PROP_FONT_DESCRIPTION: - g_value_set_boxed (value, layout->font_desc); - break; - - case PROP_LINE_SPACING: - g_value_set_float (value, layout->line_spacing); - break; - - case PROP_WIDTH: - g_value_set_int (value, layout->width); - break; - - case PROP_HEIGHT: - g_value_set_int (value, layout->height); - break; - - case PROP_TABS: - g_value_set_boxed (value, layout->tabs); - break; - - case PROP_SINGLE_PARAGRAPH: - g_value_set_boolean (value, layout->single_paragraph); - break; - - case PROP_WRAP: - g_value_set_enum (value, layout->wrap); - break; - - case PROP_INDENT: - g_value_set_int (value, layout->indent); - break; - - case PROP_ALIGNMENT: - g_value_set_enum (value, layout->alignment); - break; - - case PROP_ELLIPSIZE: - g_value_set_enum (value, layout->ellipsize); - break; - - case PROP_AUTO_DIR: - g_value_set_boolean (value, layout->auto_dir); - break; - - case PROP_LINES: - g_value_set_object (value, pango_simple_layout_get_lines (layout)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -pango_simple_layout_class_init (PangoSimpleLayoutClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - object_class->finalize = pango_simple_layout_finalize; - object_class->set_property = pango_simple_layout_set_property; - object_class->get_property = pango_simple_layout_get_property; - - /** - * PangoSimpleLayout:context: (attributes org.gtk.Property.get=pango_simple_layout_get_context) - * - * The context for the `PangoSimpleLayout`. - */ - props[PROP_CONTEXT] = g_param_spec_object ("context", "context", "context", - PANGO_TYPE_CONTEXT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - /** - * PangoSimpleLayout:text: (attributes org.gtk.Property.get=pango_simple_layout_get_text org.gtk.Property.set=pango_simple_layout_set_text) - * - * The text of the `PangoSimpleLayout`. - */ - props[PROP_TEXT] = g_param_spec_string ("text", "text", "text", - "", - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:attributes: (attributes org.gtk.Property.get=pango_simple_layout_get_attributes org.gtk.Property.set=pango_simple_layout_set_attributes) - * - * The attributes of the `PangoSimpleLayout`. - * - * Attributes can affect how the text is formatted. - */ - props[PROP_ATTRIBUTES] = g_param_spec_boxed ("attributes", "attributes", "attributes", - PANGO_TYPE_ATTR_LIST, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:font-description: (attributes org.gtk.Property.get=pango_simple_layout_get_font_description org.gtk.Property.set=pango_simple_layout_set_font_description) - * - * The font description of the `PangoSimpleLayout`. - */ - props[PROP_FONT_DESCRIPTION] = g_param_spec_boxed ("font-description", "font-description", "font-description", - PANGO_TYPE_FONT_DESCRIPTION, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:line-spacing: (attributes org.gtk.Property.get=pango_simple_layout_get_line_spacing org.gtk.Property.set=pango_simple_layout_set_line_spacing) - * - * The line spacing factor of the `PangoSimpleLayout`. - */ - props[PROP_LINE_SPACING] = g_param_spec_float ("line-spacing", "line-spacing", "line-spacing", - 0., G_MAXFLOAT, 0., - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:width: (attributes org.gtk.Property.get=pango_simple_layout_get_width org.gtk.Property.set=pango_simple_layout_set_width) - * - * The width to which the text of `PangoSimpleLayout` will be broken. - * - * The width is specified in Pango units, with -1 meaning unlimited. - * - * The default value is -1. - */ - props[PROP_WIDTH] = g_param_spec_int ("width", "width", "width", - -1, G_MAXINT, -1, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:height: (attributes org.gtk.Property.get=pango_simple_layout_get_height org.gtk.Property.set=pango_simple_layout_set_height) - * - * The height to which the `PangoSimpleLayout` will be ellipsized. - * - * If @height is positive, it will be the maximum height of the - * layout. Only lines would be shown that would fit, and if there - * is any text omitted, an ellipsis added. At least one line is - * included in each paragraph regardless of how small the height - * value is. A value of zero will render exactly one line for the - * entire layout. - * - * If @height is negative, it will be the (negative of) maximum - * number of lines per paragraph. That is, the total number of lines - * shown may well be more than this value if the layout contains - * multiple paragraphs of text. - * - * The default value of -1 means that the first line of each - * paragraph is ellipsized. - * - * Height setting only has effect if a positive width is set on the - * layout and its ellipsization mode is not `PANGO_ELLIPSIZE_NONE`. - * The behavior is undefined if a height other than -1 is set and - * ellipsization mode is set to `PANGO_ELLIPSIZE_NONE`. - * - * The default value is -1. - */ - props[PROP_HEIGHT] = g_param_spec_int ("height", "height", "height", - -G_MAXINT, G_MAXINT, -1, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:tabs: (attributes org.gtk.Property.get=pango_simple_layout_get_tabs org.gtk.Property.set=pango_simple_layout_set_tabs) - * - * The tabs to use when formatting the text of `PangoSimpleLayout`. - * - * `PangoLayout` will place content at the next tab position - * whenever it meets a Tab character (U+0009). - */ - props[PROP_TABS] = g_param_spec_boxed ("tabs", "tabs", "tabs", - PANGO_TYPE_TAB_ARRAY, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:single-paragraph: (attributes org.gtk.Property.get=pango_simple_layout_get_single_paragraph org.gtk.Property.set=pango_simple_layout_set_single_paragraph) - * - * Whether to treat newlines and similar characters as paragraph - * separators or not. If this property is `TRUE`, all text is kept - * in a single paragraph, and paragraph separator characters are - * displayed with a glyph. - * - * This is useful to allow editing of newlines on a single text line. - * - * The default value is `FALSE`. - */ - props[PROP_SINGLE_PARAGRAPH] = g_param_spec_boolean ("single-paragraph", "single-paragraph", "single-paragraph", - FALSE, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:wrap: (attributes org.gtk.Property.get=pango_simple_layout_get_wrap org.gtk.Property.set=pango_simple_layout_set_wrap) - * - * The wrap mode of this `PangoSimpleLayout. - * - * The wrap mode influences how Pango chooses line breaks - * when text needs to be wrapped. - * - * The default value is `PANGO_WRAP_WORD`. - */ - props[PROP_WRAP] = g_param_spec_enum ("wrap", "wrap", "wrap", - PANGO_TYPE_WRAP_MODE, - PANGO_WRAP_WORD, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:indent: (attributes org.gtk.Property.get=pango_simple_layout_get_indent org.gtk.Property.set=pango_simple_layout_set_indent) - * - * The indent of this `PangoSimpleLayout. - * - * The indent is specified in Pango units. - * - * A negative value of @indent will produce a hanging indentation. - * That is, the first line will have the full width, and subsequent - * lines will be indented by the absolute value of @indent. - * - * The default value is 0. - */ - props[PROP_INDENT] = g_param_spec_int ("indent", "indent", "indent", - G_MININT, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:alignment: (attributes org.gtk.Property.get=pango_simple_layout_get_alignment org.gtk.Property.set=pango_simple_layout_set_alignment) - * - * The alignment mode of this `PangoSimpleLayout. - * - * The default value is `PANGO_ALIGNMENT_LEFT`. - */ - props[PROP_ALIGNMENT] = g_param_spec_enum ("alignment", "alignment", "alignment", - PANGO_TYPE_ALIGNMENT_MODE, - PANGO_ALIGNMENT_LEFT, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:ellipsize: (attributes org.gtk.Property.get=pango_simple_layout_get_ellipsize org.gtk.Property.set=pango_simple_layout_set_ellipsize) - * - * The ellipsization mode of this `PangoSimpleLayout. - * - * The default value is `PANGO_ELLIPSIZE_NONE`. - */ - props[PROP_ELLIPSIZE] = g_param_spec_enum ("ellipsize", "ellipsize", "ellipsize", - PANGO_TYPE_ELLIPSIZE_MODE, - PANGO_ELLIPSIZE_NONE, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:auto-dir: (attributes org.gtk.Property.get=pango_simple_layout_get_auto_dir org.gtk.Property.set=pango_simple_layout_set_auto_dir) - * - * Whether this `PangoSimpleLayout` determines the - * base direction from the content. - * - * The default value is `TRUE`. - */ - props[PROP_AUTO_DIR] = g_param_spec_boolean ("auto-dir", "auto-dir", "auto-dir", - TRUE, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); - - /** - * PangoSimpleLayout:lines: (attributes org.gtk.Property.get=pango_simple_layout_get_lines) - * - * The `PangoLines` object holding the formatted lines. - */ - props[PROP_LINES] = g_param_spec_object ("lines", "lines", "lines", - PANGO_TYPE_LINES, - G_PARAM_READABLE); - - g_object_class_install_properties (object_class, NUM_PROPERTIES, props); -} - -/* }}} */ -/* {{{ Utilities */ - -static void -layout_changed (PangoSimpleLayout *layout) -{ - layout->serial++; - if (layout->serial == 0) - layout->serial++; - - g_clear_object (&layout->lines); - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_LINES]); -} - -static void -check_context_changed (PangoSimpleLayout *layout) -{ - guint old_serial = layout->context_serial; - - layout->context_serial = pango_context_get_serial (layout->context); - - if (old_serial != layout->context_serial) - layout_changed (layout); -} - -static PangoAttrList * -ensure_attrs (PangoSimpleLayout *layout, - PangoAttrList *attrs) -{ - if (attrs) - return attrs; - else if (layout->attrs) - return pango_attr_list_copy (layout->attrs); - else - return pango_attr_list_new (); -} - -static PangoAttrList * -get_effective_attributes (PangoSimpleLayout *layout) -{ - PangoAttrList *attrs = NULL; - - if (layout->font_desc) - { - attrs = ensure_attrs (layout, attrs); - pango_attr_list_insert_before (attrs, - pango_attr_font_desc_new (layout->font_desc)); - } - - if (layout->line_spacing != 0.0) - { - attrs = ensure_attrs (layout, attrs); - pango_attr_list_insert_before (attrs, - pango_attr_line_height_new (layout->line_spacing)); - } - - if (layout->single_paragraph) - { - attrs = ensure_attrs (layout, attrs); - pango_attr_list_insert_before (attrs, - pango_attr_paragraph_new ()); - } - - if (attrs) - return attrs; - - return pango_attr_list_ref (layout->attrs); -} - -static gboolean -ends_with_paragraph_separator (PangoSimpleLayout *layout) -{ - if (layout->single_paragraph) - return FALSE; - - return g_str_has_suffix (layout->text, "\n") || - g_str_has_suffix (layout->text, "\r") || - g_str_has_suffix (layout->text, "\r\n") || - g_str_has_suffix (layout->text, "
"); -} - -static void -ensure_lines (PangoSimpleLayout *layout) -{ - PangoLineBreaker *breaker; - PangoAttrList *attrs; - int x, y, width; - int line_no; - - check_context_changed (layout); - - if (layout->lines) - return; - - breaker = pango_line_breaker_new (layout->context); - - pango_line_breaker_set_tabs (breaker, layout->tabs); - pango_line_breaker_set_base_dir (breaker, - layout->auto_dir - ? PANGO_DIRECTION_NEUTRAL - : pango_context_get_base_dir (layout->context)); - - attrs = get_effective_attributes (layout); - pango_line_breaker_add_text (breaker, layout->text ? layout->text : "", -1, attrs); - if (attrs) - pango_attr_list_unref (attrs); - - layout->lines = pango_lines_new (); - - x = y = 0; - line_no = 0; - while (!pango_line_breaker_done (breaker)) - { - PangoLine *line; - PangoRectangle ext; - int offset; - PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE; - - if ((line_no == 0) == (layout->indent > 0)) - { - x = abs (layout->indent); - width = layout->width - x; - } - else - { - x = 0; - width = layout->width; - } - - if (layout->height < 0 && line_no + 1 == - layout->height) - ellipsize = layout->ellipsize; - -retry: - line = pango_line_breaker_next_line (breaker, x, width, layout->wrap, ellipsize); - pango_line_get_extents (line, NULL, &ext); - - if (layout->height >= 0 && y + 2 * ext.height >= layout->height && - ellipsize != layout->ellipsize) - { - if (pango_line_breaker_undo_line (breaker, line)) - { - g_clear_object (&line); - ellipsize = layout->ellipsize; - goto retry; - } - } - - /* Handle alignment and justification */ - offset = 0; - switch (layout->alignment) - { - case PANGO_ALIGNMENT_LEFT: - break; - case PANGO_ALIGNMENT_CENTER: - if (ext.width < width) - offset = (width - ext.width) / 2; - break; - case PANGO_ALIGNMENT_RIGHT: - if (ext.width < width) - offset = width - ext.width; - break; - case PANGO_ALIGNMENT_JUSTIFY: - if (!pango_line_ends_paragraph (line)) - line = pango_line_justify (line, width); - break; - case PANGO_ALIGNMENT_JUSTIFY_ALL: - line = pango_line_justify (line, width); - break; - default: g_assert_not_reached (); - } - - pango_lines_add_line (layout->lines, line, x + offset, y - ext.y); - - y += ext.height; - line_no++; - } - - /* Append an empty line if we end with a newline. - * And always provide at least one line - */ - if (pango_lines_get_line_count (layout->lines) == 0 || - ends_with_paragraph_separator (layout)) - { - LineData *data; - int start_index; - int start_offset; - int offset; - PangoLine *line; - PangoRectangle ext; - - if (pango_lines_get_line_count (layout->lines) > 0) - { - PangoLine *last; - - last = pango_lines_get_line (layout->lines, - pango_lines_get_line_count (layout->lines) - 1, - NULL, NULL); - data = last->data; - start_index = data->length; - start_offset = last->data->n_chars; - offset = MAX (layout->indent, 0); - } - else - { - data = line_data_new (); - data->text = g_strdup (""); - data->length = 0; - data->attrs = get_effective_attributes (layout); - data->log_attrs = g_new0 (PangoLogAttr, 1); - data->log_attrs[0].is_cursor_position = TRUE; - start_index = 0; - start_offset = 0; - offset = 0; - } - - line = pango_line_new (layout->context, data); - line->starts_paragraph = TRUE; - line->ends_paragraph = TRUE; - line->start_index = start_index; - line->length = 0; - line->start_offset = start_offset; - line->n_chars = 0; - - pango_line_get_extents (line, NULL, &ext); - - pango_lines_add_line (layout->lines, line, x + offset, y - ext.y); - - line_data_unref (data); - } - - g_object_unref (breaker); -} - -/* }}} */ -/* {{{ Public API */ - -/** - * pango_simple_layout_new: - * @context: a `PangoContext` - * - * Creates a new `PangoSimpleLayout` with attribute initialized to - * default values for a particular `PangoContext` - * - * Return value: a newly allocated `PangoLayout` - */ -PangoSimpleLayout * -pango_simple_layout_new (PangoContext *context) -{ - g_return_val_if_fail (context != NULL, NULL); - - return g_object_new (PANGO_TYPE_SIMPLE_LAYOUT, "context", context, NULL); -} - -/** - * pango_simple_layout_copy: - * @layout: a `PangoSimpleLayout` - * - * Creates a deep copy-by-value of the layout. - * - * The attribute list, tab array, and text from the original layout - * are all copied by value. - * - * Return value: (transfer full): the newly allocated `PangoSimpleLayout` - */ -PangoSimpleLayout * -pango_simple_layout_copy (PangoSimpleLayout *layout) -{ - PangoSimpleLayout *copy; - - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - copy = pango_simple_layout_new (layout->context); - - copy->text = g_strdup (layout->text); - copy->length = layout->length; - if (layout->attrs) - copy->attrs = pango_attr_list_copy (layout->attrs); - if (layout->font_desc) - copy->font_desc = pango_font_description_copy (layout->font_desc); - copy->line_spacing = layout->line_spacing; - copy->width = layout->width; - copy->height = layout->height; - if (layout->tabs) - copy->tabs = pango_tab_array_copy (layout->tabs); - copy->wrap = layout->wrap; - copy->indent = layout->indent; - copy->serial = layout->serial; - copy->context_serial = layout->context_serial; - copy->alignment = layout->alignment; - copy->ellipsize = layout->ellipsize; - copy->auto_dir = layout->auto_dir; - - return copy; -} - -/** - * pango_simple_layout_get_serial: - * @layout: a `PangoSimpleLayout` - * - * Returns the current serial number of @layout. - * - * The serial number is initialized to an small number larger than zero - * when a new layout is created and is increased whenever the layout is - * changed using any of the setter functions, or the `PangoContext` it - * uses has changed. - * - * The serial may wrap, but will never have the value 0. Since it can - * wrap, never compare it with "less than", always use "not equals". - * - * This can be used to automatically detect changes to a `PangoSimpleLayout`, - * and is useful for example to decide whether a layout needs redrawing. - * - * Return value: The current serial number of @layout - */ -guint -pango_simple_layout_get_serial (PangoSimpleLayout *layout) -{ - check_context_changed (layout); - - return layout->serial; -} - -/* {{{ Property getters and setters */ - -/** - * pango_simple_layout_get_context: - * @layout: a `PangoSimpleLayout` - * - * Retrieves the `PangoContext` used for this layout. - * - * Return value: (transfer none): the `PangoContext` for the layout - */ -PangoContext * -pango_simple_layout_get_context (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - return layout->context; -} - -/** - * pango_simple_layout_set_text: - * @layout: a `PangoSimpleLayout` - * @text: the text - * @length: maximum length of @text, in bytes. -1 indicates that - * the string is nul-terminated - * - * Sets the text of the layout. - */ -void -pango_simple_layout_set_text (PangoSimpleLayout *layout, - const char *text, - int length) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (length < 0) - length = strlen (text); - - g_free (layout->text); - layout->text = g_strndup (text, length); - layout->length = length; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TEXT]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_text: - * @layout: a `PangoSimpleLayout` - * - * Gets the text in the layout. - * - * The returned text should not be freed or modified. - * - * Return value: (transfer none): the text in the @layout - */ -const char * -pango_simple_layout_get_text (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - return layout->text; -} - -/** - * pango_simple_layout_set_attributes: - * @layout: a `PangoSimpleLayout` - * @attrs: (nullable) (transfer none): a `PangoAttrList` - * - * Sets the attributes for a layout object. - * - * References @attrs, so the caller can unref its reference. - */ -void -pango_simple_layout_set_attributes (PangoSimpleLayout *layout, - PangoAttrList *attrs) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - g_clear_pointer (&layout->attrs, pango_attr_list_unref); - layout->attrs = attrs; - if (layout->attrs) - pango_attr_list_ref (layout->attrs); - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ATTRIBUTES]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_attributes: - * @layout: a `PangoSimpleLayout` - * - * Gets the attribute list for the layout, if any. - * - * Return value: (transfer none) (nullable): a `PangoAttrList` - */ -PangoAttrList * -pango_simple_layout_get_attributes (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - return layout->attrs; -} - -/** - * pango_simple_layout_set_font_description: - * @layout: a `PangoSimpleLayout` - * @desc: (nullable): the new `PangoFontDescription` - * - * Sets the default font description for the layout. - * - * If no font description is set on the layout, the - * font description from the layout's context is used. - * - * This method is a shorthand for adding a font-desc attribute. - */ -void -pango_simple_layout_set_font_description (PangoSimpleLayout *layout, - const PangoFontDescription *desc) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (desc != layout->font_desc && - (!desc || !layout->font_desc || !pango_font_description_equal (desc, layout->font_desc))) - { - if (layout->font_desc) - pango_font_description_free (layout->font_desc); - - layout->font_desc = desc ? pango_font_description_copy (desc) : NULL; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_FONT_DESCRIPTION]); - layout_changed (layout); - } -} - -/** - * pango_simple_layout_get_font_description: - * @layout: a `PangoSimpleLayout` - * - * Gets the font description for the layout, if any. - * - * Return value: (transfer none) (nullable): a pointer to the - * layout's font description, or %NULL if the font description - * from the layout's context is inherited. - * - * Since: 1.8 - */ -const PangoFontDescription * -pango_simple_layout_get_font_description (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - return layout->font_desc; -} - -/** - * pango_simple_layout_set_line_spacing: - * @layout: a `PangoSimpleLayout` - * @line_spacing: the new line spacing factor - * - * Sets a factor for line spacing. - * - * Typical values are: 0, 1, 1.5, 2. The default values is 0. - * - * If @line_spacing is non-zero, lines are placed so that - * - * baseline2 = baseline1 + factor * height2 - * - * where height2 is the line height of the second line (as determined - * by the font). - * - * This method is a shorthand for adding a line-height attribute. - */ -void -pango_simple_layout_set_line_spacing (PangoSimpleLayout *layout, - float line_spacing) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->line_spacing == line_spacing) - return; - - layout->line_spacing = line_spacing; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_LINE_SPACING]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_line_spacing: - * @layout: a `PangoSimpleLayout` - * - * Gets the line spacing factor of @layout. - * - * See [method@Pango.SimpleLayout.set_line_spacing]. - */ -float -pango_simple_layout_get_line_spacing (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), 0.0); - - return layout->line_spacing; -} - -/** - * pango_simple_layout_set_width: - * @layout: a `PangoSimpleLayout`. - * @width: the desired width in Pango units, or -1 to indicate that no - * wrapping or ellipsization should be performed. - * - * Sets the width to which the lines of the layout should - * be wrapped or ellipsized. - * - * The default value is -1: no width set. - */ -void -pango_simple_layout_set_width (PangoSimpleLayout *layout, - int width) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (width < -1) - width = -1; - - if (layout->width == width) - return; - - layout->width = width; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_WIDTH]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_width: - * @layout: a `PangoSimpleLayout` - * - * Gets the width to which the lines of the layout should wrap. - * - * Return value: the width in Pango units, or -1 if no width set. - */ -int -pango_simple_layout_get_width (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), -1); - - return layout->width; -} - -/** - * pango_simple_layout_set_height: - * @layout: a `PangoSimpleLayout`. - * @height: the desired height - * - * Sets the height to which the `PangoLayout` should be ellipsized at. - * - * There are two different behaviors, based on whether @height is positive - * or negative. - * - * See [property@Pango.SimpleLayout:height] for details. - */ -void -pango_simple_layout_set_height (PangoSimpleLayout *layout, - int height) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->height == height) - return; - - layout->height = height; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_HEIGHT]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_height: - * @layout: a `PangoSimpleLayout` - * - * Gets the height to which the lines of the layout should ellipsize. - * - * See [property@Pango.SimpleLayout:height] for details. - * - * Return value: the height - */ -int -pango_simple_layout_get_height (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), -1); - - return layout->height; -} - -/** - * pango_simple_layout_set_tabs: - * @layout: a `PangoSimpleLayout` - * @tabs: (nullable): a `PangoTabArray` - * - * Sets the tabs to use for @layout, overriding the default tabs. - * - * See [method@Pango.LineBreaker.set_tabs] for details. - */ -void -pango_simple_layout_set_tabs (PangoSimpleLayout *layout, - PangoTabArray *tabs) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->tabs == tabs) - return; - - g_clear_pointer (&layout->tabs, pango_tab_array_free); - layout->tabs = pango_tab_array_copy (tabs); - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TABS]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_tabs: - * @layout: a `PangoSimpleLayout` - * - * Gets the current `PangoTabArray` used by this layout. - * - * If no `PangoTabArray` has been set, then the default tabs are - * in use and %NULL is returned. Default tabs are every 8 spaces. - * - * Return value: (transfer none) (nullable): the tabs for this layout - */ -PangoTabArray * -pango_simple_layout_get_tabs (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - return layout->tabs; -} - -/** - * pango_simple_layout_set_single_paragraph: - * @layout: a `PangoSimpleLayout` - * @single_paragraph: the new setting - * - * Sets the single paragraph mode of @layout. - * - * If @single_paragraph is `TRUE`, do not treat newlines and similar - * characters as paragraph separators; instead, keep all text in a - * single paragraph, and display a glyph for paragraph separator - * characters. - * - * Used when you want to allow editing of newlines on a single text line. - * - * The default value is %FALSE. - */ -void -pango_simple_layout_set_single_paragraph (PangoSimpleLayout *layout, - gboolean single_paragraph) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->single_paragraph == single_paragraph) - return; - - layout->single_paragraph = single_paragraph; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_SINGLE_PARAGRAPH]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_single_paragraph: - * @layout: a `PangoSimpleLayout` - * - * Obtains whether @layout is in single paragraph mode. - * - * See [method@Pango.SimpleLayout.set_single_paragraph]. - * - * Return value: `TRUE` if the layout does not break paragraphs - * at paragraph separator characters, %FALSE otherwise - */ -gboolean -pango_simple_layout_get_single_paragraph (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), FALSE); - - return layout->single_paragraph; -} - -/** - * pango_simple_layout_set_wrap: - * @layout: a `PangoSimpleLayout` - * @wrap: the wrap mode - * - * Sets the wrap mode. - * - * The wrap mode only has effect if a width is set on the layout - * with [method@Pango.SimpleLayout.set_width]. To turn off wrapping, - * set the width to -1. - * - * The default value is %PANGO_WRAP_WORD. - */ -void -pango_simple_layout_set_wrap (PangoSimpleLayout *layout, - PangoWrapMode wrap) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->wrap == wrap) - return; - - layout->wrap = wrap; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_WRAP]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_wrap: - * @layout: a `PangoSimpleLayout` - * - * Gets the wrap mode for the layout. - * - * Return value: active wrap mode. - */ -PangoWrapMode -pango_simple_layout_get_wrap (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), PANGO_WRAP_WORD); - - return layout->wrap; -} - -/** - * pango_simple_layout_set_indent: - * @layout: a `PangoSimpleLayout` - * @indent: the amount by which to indent - * - * Sets the width in Pango units to indent each paragraph. - * - * A negative value of @indent will produce a hanging indentation. - * That is, the first line will have the full width, and subsequent - * lines will be indented by the absolute value of @indent. - * - * The default value is 0. - */ -void -pango_simple_layout_set_indent (PangoSimpleLayout *layout, - int indent) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->indent == indent) - return; - - layout->indent = indent; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_INDENT]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_indent: - * @layout: a `PangoSimpleLayout` - * - * Gets the paragraph indent width in Pango units. - * - * A negative value indicates a hanging indentation. - * - * Return value: the indent in Pango units - */ -int -pango_simple_layout_get_indent (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), 0); - - return layout->indent; -} - -/** - * pango_simple_layout_set_alignment: - * @layout: a `PangoSimpleLayout` - * @alignment: the alignment - * - * Sets the alignment for the layout: how short lines are - * positioned within the horizontal space available. - * - * The default alignment is %PANGO_ALIGNMENT_LEFT. - */ -void -pango_simple_layout_set_alignment (PangoSimpleLayout *layout, - PangoAlignmentMode alignment) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->alignment == alignment) - return; - - layout->alignment = alignment; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ALIGNMENT]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_alignment: - * @layout: a `PangoSimpleLayout` - * - * Gets the alignment for the layout: how short lines are - * positioned within the horizontal space available. - * - * Return value: the alignment - */ -PangoAlignmentMode -pango_simple_layout_get_alignment (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), PANGO_ALIGNMENT_LEFT); - - return layout->alignment; -} - -/** - * pango_simple_layout_set_ellipsize: - * @layout: a `PangoSimpleLayout` - * @ellipsize: the new ellipsization mode for @layout - * - * Sets the type of ellipsization being performed for @layout. - * - * Depending on the ellipsization mode @ellipsize text is removed - * from the start, middle, or end of text so they fit within the - * width of layout set with [method@Pango.SimpleLayout.set_width]. - * - * The default value is %PANGO_ELLIPSIZE_NONE. - */ -void -pango_simple_layout_set_ellipsize (PangoSimpleLayout *layout, - PangoEllipsizeMode ellipsize) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (layout->ellipsize == ellipsize) - return; - - layout->ellipsize = ellipsize; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ELLIPSIZE]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_ellipsize: - * @layout: a `PangoSimpleLayout` - * - * Gets the type of ellipsization being performed for @layout. - * - * See [method@Pango.SimpleLayout.set_ellipsize]. - * - * Return value: the current ellipsization mode for @layout - */ -PangoEllipsizeMode -pango_simple_layout_get_ellipsize (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), PANGO_ELLIPSIZE_NONE); - - return layout->ellipsize; -} - -/** - * pango_simple_layout_set_auto_dir: - * @layout: a `PangoSimpleLayout` - * @auto_dir: if %TRUE, compute the bidirectional base direction - * from the layout's contents - * - * Sets whether to calculate the base direction - * for the layout according to its contents. - * - * When this flag is on (the default), then paragraphs in - * @layout that begin with strong right-to-left characters - * (Arabic and Hebrew principally), will have right-to-left - * layout, paragraphs with letters from other scripts will - * have left-to-right layout. Paragraphs with only neutral - * characters get their direction from the surrounding - * paragraphs. - * - * When %FALSE, the choice between left-to-right and right-to-left - * layout is done according to the base direction of the layout's - * `PangoContext`. (See [method@Pango.Context.set_base_dir]). - * - * When the auto-computed direction of a paragraph differs - * from the base direction of the context, the interpretation - * of %PANGO_ALIGN_LEFT and %PANGO_ALIGN_RIGHT are swapped. - */ -void -pango_simple_layout_set_auto_dir (PangoSimpleLayout *layout, - gboolean auto_dir) -{ - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - if (auto_dir == layout->auto_dir) - return; - - layout->auto_dir = auto_dir; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_AUTO_DIR]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_auto_dir: - * @layout: a `PangoSimpleLayout` - * - * Gets whether to calculate the base direction for the layout - * according to its contents. - * - * See [method@Pango.SimpleLayout.set_auto_dir]. - * - * Return value: %TRUE if the bidirectional base direction - * is computed from the layout's contents, %FALSE otherwise - */ -gboolean -pango_simple_layout_get_auto_dir (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), TRUE); - - return layout->auto_dir; -} - -/* }}} */ -/* {{{ Miscellaneous */ - -/** - * pango_simple_layout_set_markup: - * @layout: a `PangoSimpleLayout` - * @markup: marked-up text - * @length: length of @markup in bytes, or -1 if it is `NUL`-terminated - * - * Sets the layout text and attribute list from marked-up text. - * - * See [Pango Markup](pango_markup.html)). - * - * Replaces the current text and attribute list. - */ -void -pango_simple_layout_set_markup (PangoSimpleLayout *layout, - const char *markup, - int length) -{ - PangoAttrList *attrs; - char *text; - GError *error = NULL; - - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - g_return_if_fail (markup != NULL); - - if (!pango_parse_markup (markup, length, 0, &attrs, &text, NULL, &error)) - { - g_warning ("pango_layout_set_markup_with_accel: %s", error->message); - g_error_free (error); - return; - } - - g_free (layout->text); - layout->text = text; - layout->length = strlen (text); - - g_clear_pointer (&layout->attrs, pango_attr_list_unref); - layout->attrs = attrs; - - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_TEXT]); - g_object_notify_by_pspec (G_OBJECT (layout), props[PROP_ATTRIBUTES]); - layout_changed (layout); -} - -/** - * pango_simple_layout_get_character_count: - * @layout: a `PangoSimpleLayout` - * - * Returns the number of Unicode characters in the - * the text of @layout. - * - * Return value: the number of Unicode characters in @layout - */ -int -pango_simple_layout_get_character_count (PangoSimpleLayout *layout) -{ - PangoLine *line; - - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), 0); - - ensure_lines (layout); - - line = pango_lines_get_line (layout->lines, 0, NULL, NULL); - - return line->data->n_chars; -} - -/* }}} */ -/* {{{ Output getters */ - -/** - * pango_simple_layout_get_lines: - * @layout: a `PangoSimpleLayout` - * - * Gets the lines of the @layout. - * - * The returned object will become invalid when any - * property of @layout is changed. Take a reference - * to keep it. - * - * Return value: (transfer none): a `PangoLines` object - * with the lines of @layout - */ -PangoLines * -pango_simple_layout_get_lines (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - ensure_lines (layout); - - return layout->lines; -} - -/** - * pango_simple_layout_get_log_attrs: - * @layout: a `PangoSimpleLayout` - * @n_attrs: (out): return location for the length of the array - * - * Gets the `PangoLogAttr` array for the content - * of @layout. - * - * The returned array becomes invalid when - * any properties of @layout change. Make a - * copy if you want to keep it. - * - * Returns: (transfer none): the `PangoLogAttr` array - */ -const PangoLogAttr * -pango_simple_layout_get_log_attrs (PangoSimpleLayout *layout, - int *n_attrs) -{ - PangoLine *line; - - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - ensure_lines (layout); - - line = pango_lines_get_line (layout->lines, 0, NULL, NULL); - - if (n_attrs) - *n_attrs = line->data->n_chars + 1; - - return line->data->log_attrs; -} - -/** - * pango_simple_layout_get_iter: - * @layout: a `PangoSimpleLayout` - * - * Returns an iterator to iterate over the visual extents - * of the layout. - * - * This is a convenience wrapper for [method@Pango.Lines.get_iter]. - * - * Returns: the new `PangoLineIter` - */ -PangoLineIter * -pango_simple_layout_get_iter (PangoSimpleLayout *layout) -{ - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - ensure_lines (layout); - - return pango_lines_get_iter (layout->lines); -} - -/* }}} */ -/* }}} */ - -/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-simple-layout.h b/pango/pango-simple-layout.h deleted file mode 100644 index 446a1093..00000000 --- a/pango/pango-simple-layout.h +++ /dev/null @@ -1,171 +0,0 @@ -#pragma once - -#include <glib-object.h> -#include <pango/pango-types.h> -#include <pango/pango-attributes.h> -#include <pango/pango-lines.h> -#include <pango/pango-tabs.h> - -G_BEGIN_DECLS - -#define PANGO_TYPE_SIMPLE_LAYOUT pango_simple_layout_get_type () - -PANGO_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (PangoSimpleLayout, pango_simple_layout, PANGO, SIMPLE_LAYOUT, GObject); - -PANGO_AVAILABLE_IN_ALL -PangoSimpleLayout * pango_simple_layout_new (PangoContext *context); - -PANGO_AVAILABLE_IN_ALL -PangoSimpleLayout * pango_simple_layout_copy (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -guint pango_simple_layout_get_serial (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -PangoContext * pango_simple_layout_get_context (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_text (PangoSimpleLayout *layout, - const char *text, - int length); -PANGO_AVAILABLE_IN_ALL -const char * pango_simple_layout_get_text (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_markup (PangoSimpleLayout *layout, - const char *markup, - int length); - -PANGO_AVAILABLE_IN_ALL -int pango_simple_layout_get_character_count - (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_attributes (PangoSimpleLayout *layout, - PangoAttrList *attrs); - -PANGO_AVAILABLE_IN_ALL -PangoAttrList * pango_simple_layout_get_attributes (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_font_description - (PangoSimpleLayout *layout, - const PangoFontDescription *desc); - -PANGO_AVAILABLE_IN_ALL -const PangoFontDescription * - pango_simple_layout_get_font_description - (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_line_spacing - (PangoSimpleLayout *layout, - float line_spacing); - -PANGO_AVAILABLE_IN_ALL -float pango_simple_layout_get_line_spacing - (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_width (PangoSimpleLayout *layout, - int width); - -PANGO_AVAILABLE_IN_ALL -int pango_simple_layout_get_width (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_height (PangoSimpleLayout *layout, - int height); - -PANGO_AVAILABLE_IN_ALL -int pango_simple_layout_get_height (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_tabs (PangoSimpleLayout *layout, - PangoTabArray *tabs); - -PANGO_AVAILABLE_IN_ALL -PangoTabArray * pango_simple_layout_get_tabs (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_single_paragraph - (PangoSimpleLayout *layout, - gboolean single_paragraph); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_simple_layout_get_single_paragraph - (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_wrap (PangoSimpleLayout *layout, - PangoWrapMode wrap); - -PANGO_AVAILABLE_IN_ALL -PangoWrapMode pango_simple_layout_get_wrap (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_indent (PangoSimpleLayout *layout, - int indent); - -PANGO_AVAILABLE_IN_ALL -int pango_simple_layout_get_indent (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_alignment (PangoSimpleLayout *layout, - PangoAlignmentMode alignment); - -PANGO_AVAILABLE_IN_ALL -PangoAlignmentMode pango_simple_layout_get_alignment (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_ellipsize (PangoSimpleLayout *layout, - PangoEllipsizeMode ellipsize); - -PANGO_AVAILABLE_IN_ALL -PangoEllipsizeMode pango_simple_layout_get_ellipsize (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -void pango_simple_layout_set_auto_dir (PangoSimpleLayout *layout, - gboolean auto_dir); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_simple_layout_get_auto_dir (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -PangoLines * pango_simple_layout_get_lines (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -PangoLineIter * pango_simple_layout_get_iter (PangoSimpleLayout *layout); - -PANGO_AVAILABLE_IN_ALL -const PangoLogAttr * pango_simple_layout_get_log_attrs (PangoSimpleLayout *layout, - int *n_attrs); - -typedef enum { - PANGO_SIMPLE_LAYOUT_SERIALIZE_DEFAULT = 0, - PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT = 1 << 0, - PANGO_SIMPLE_LAYOUT_SERIALIZE_OUTPUT = 1 << 1, -} PangoSimpleLayoutSerializeFlags; - -PANGO_AVAILABLE_IN_ALL -GBytes * pango_simple_layout_serialize (PangoSimpleLayout *layout, - PangoSimpleLayoutSerializeFlags flags); - -PANGO_AVAILABLE_IN_ALL -gboolean pango_simple_layout_write_to_file (PangoSimpleLayout *layout, - const char *filename); - -typedef enum { - PANGO_SIMPLE_LAYOUT_DESERIALIZE_DEFAULT = 0, - PANGO_SIMPLE_LAYOUT_DESERIALIZE_CONTEXT = 1 << 0, -} PangoSimpleLayoutDeserializeFlags; - -PANGO_AVAILABLE_IN_ALL -PangoSimpleLayout * pango_simple_layout_deserialize (PangoContext *context, - GBytes *bytes, - PangoSimpleLayoutDeserializeFlags flags, - GError **error); - - -G_END_DECLS diff --git a/pango/pango-types.h b/pango/pango-types.h index 5c111a65..69913b31 100644 --- a/pango/pango-types.h +++ b/pango/pango-types.h @@ -53,7 +53,9 @@ typedef struct _PangoLanguage PangoLanguage; */ typedef guint32 PangoGlyph; - +typedef struct _PangoLines PangoLines; +typedef struct _PangoGlyphItem PangoLayoutRun; +typedef struct _PangoLayoutIter PangoLayoutIter; /** * PANGO_SCALE: @@ -243,31 +245,23 @@ void pango_extents_to_pixels (PangoRectangle *inclusive, * @PANGO_ALIGN_LEFT: Put all available space on the right * @PANGO_ALIGN_CENTER: Center the line within the available space * @PANGO_ALIGN_RIGHT: Put all available space on the left + * @PANGO_ALIGN_JUSTIFY: Justify the content to fill the available + * space, unless the line ends the paragraph + * @PANGO_ALIGN_JUSTIFY_ALL: Justify the content to fill the available + * space, even if the line ends the paragraph * * `PangoAlignment` describes how to align the lines of a `PangoLayout` * within the available space. - * - * If the `PangoLayout` is set to justify using [method@Pango.Layout.set_justify], - * this only affects partial lines. - * - * See [method@Pango.Layout.set_auto_dir] for how text direction affects - * the interpretation of `PangoAlignment` values. */ -typedef enum { +typedef enum +{ PANGO_ALIGN_LEFT, PANGO_ALIGN_CENTER, - PANGO_ALIGN_RIGHT + PANGO_ALIGN_RIGHT, + PANGO_ALIGN_JUSTIFY, + PANGO_ALIGN_JUSTIFY_ALL, } PangoAlignment; -typedef enum -{ - PANGO_ALIGNMENT_LEFT, - PANGO_ALIGNMENT_CENTER, - PANGO_ALIGNMENT_RIGHT, - PANGO_ALIGNMENT_JUSTIFY, - PANGO_ALIGNMENT_JUSTIFY_ALL, -} PangoAlignmentMode; - /** * PangoWrapMode: * @PANGO_WRAP_WORD: wrap lines at word boundaries. diff --git a/pango/pango.h b/pango/pango.h index 41167631..f9c70eca 100644 --- a/pango/pango.h +++ b/pango/pango.h @@ -42,16 +42,15 @@ #include <pango/pango-item.h> #include <pango/pango-language.h> #include <pango/pango-layout.h> +#include <pango/pango-layout-line.h> #include <pango/pango-layout-run.h> -#include <pango/pango-line.h> #include <pango/pango-line-breaker.h> -#include <pango/pango-line-iter.h> +#include <pango/pango-layout-iter.h> #include <pango/pango-lines.h> #include <pango/pango-matrix.h> #include <pango/pango-markup.h> #include <pango/pango-renderer.h> #include <pango/pango-script.h> -#include <pango/pango-simple-layout.h> #include <pango/pango-tabs.h> #include <pango/pango-types.h> #include <pango/pango-utils.h> diff --git a/pango/pangocairo-context.c b/pango/pangocairo-context.c index 0ea8332a..b1d6a03e 100644 --- a/pango/pangocairo-context.c +++ b/pango/pangocairo-context.c @@ -463,7 +463,7 @@ pango_cairo_create_context (cairo_t *cr) * and target surface of the Cairo context. * * This layout can then be used for text measurement with functions - * like [method@Pango.Layout.get_size] or drawing with functions like + * like [method@Pango.Lines.get_size] or drawing with functions like * [func@show_layout]. If you change the transformation or target * surface for @cr, you need to call [func@update_layout]. * @@ -491,21 +491,6 @@ pango_cairo_create_layout (cairo_t *cr) return layout; } -PangoSimpleLayout * -pango_cairo_create_simple_layout (cairo_t *cr) -{ - PangoContext *context; - PangoSimpleLayout *layout; - - g_return_val_if_fail (cr != NULL, NULL); - - context = pango_cairo_create_context (cr); - layout = pango_simple_layout_new (context); - g_object_unref (context); - - return layout; -} - /** * pango_cairo_update_layout: * @cr: a Cairo context @@ -526,14 +511,3 @@ pango_cairo_update_layout (cairo_t *cr, _pango_cairo_update_context (cr, pango_layout_get_context (layout)); } - -void -pango_cairo_update_simple_layout (cairo_t *cr, - PangoSimpleLayout *layout) -{ - g_return_if_fail (cr != NULL); - g_return_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout)); - - _pango_cairo_update_context (cr, pango_simple_layout_get_context (layout)); -} - diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c index 598065c0..0374971a 100644 --- a/pango/pangocairo-font.c +++ b/pango/pangocairo-font.c @@ -185,26 +185,29 @@ _pango_cairo_font_install (PangoFont *font, return TRUE; } - static int max_glyph_width (PangoLayout *layout) { + PangoLines *lines; int max_width = 0; - GSList *l, *r; + GSList *r; - for (l = pango_layout_get_lines_readonly (layout); l; l = l->next) + lines = pango_layout_get_lines (layout); + for (int i = 0; i < pango_lines_get_line_count (lines); i++) { - PangoLayoutLine *line = l->data; - - for (r = line->runs; r; r = r->next) - { - PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; - int i; + PangoLayoutLine *line = pango_lines_get_line (lines, i, NULL, NULL); - for (i = 0; i < glyphs->num_glyphs; i++) - if (glyphs->glyphs[i].geometry.width > max_width) - max_width = glyphs->glyphs[i].geometry.width; - } + for (r = pango_layout_line_get_runs (line); r; r = r->next) + { + PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; + int i; + + for (i = 0; i < glyphs->num_glyphs; i++) + { + if (glyphs->glyphs[i].geometry.width > max_width) + max_width = glyphs->glyphs[i].geometry.width; + } + } } return max_width; @@ -319,7 +322,7 @@ _pango_cairo_font_get_metrics (PangoFont *font, pango_font_description_free (desc); pango_layout_set_text (layout, sample_str, -1); - pango_layout_get_extents (layout, NULL, &extents); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &extents); sample_str_width = pango_utf8_strwidth (sample_str); g_assert (sample_str_width > 0); diff --git a/pango/pangocairo-render.c b/pango/pangocairo-render.c index 21f32c58..361fc563 100644 --- a/pango/pangocairo-render.c +++ b/pango/pangocairo-render.c @@ -973,9 +973,9 @@ _pango_cairo_do_glyph_item (cairo_t *cr, } static void -_pango_cairo_do_layout_line (cairo_t *cr, - PangoLayoutLine *line, - gboolean do_path) +_pango_cairo_do_layout_line (cairo_t *cr, + PangoLayoutLine *line, + gboolean do_path) { PangoCairoRenderer *crenderer = acquire_renderer (); PangoRenderer *renderer = (PangoRenderer *) crenderer; @@ -992,25 +992,6 @@ _pango_cairo_do_layout_line (cairo_t *cr, } static void -_pango_cairo_do_line (cairo_t *cr, - PangoLine *line, - gboolean do_path) -{ - PangoCairoRenderer *crenderer = acquire_renderer (); - PangoRenderer *renderer = (PangoRenderer *) crenderer; - - crenderer->cr = cr; - crenderer->do_path = do_path; - save_current_point (crenderer); - - pango_renderer_draw_line (renderer, line, 0, 0); - - restore_current_point (crenderer); - - release_renderer (crenderer); -} - -static void _pango_cairo_do_lines (cairo_t *cr, PangoLines *lines, gboolean do_path) @@ -1041,7 +1022,7 @@ _pango_cairo_do_layout (cairo_t *cr, crenderer->do_path = do_path; save_current_point (crenderer); - pango_renderer_draw_layout (renderer, layout, 0, 0); + pango_renderer_draw_lines (renderer, pango_layout_get_lines (layout), 0, 0); restore_current_point (crenderer); @@ -1133,7 +1114,7 @@ pango_cairo_show_glyph_item (cairo_t *cr, } /** - * pango_cairo_show_layout_line: + * pango_cairo_show_line: * @cr: a Cairo context * @line: a `PangoLayoutLine` * @@ -1141,12 +1122,10 @@ pango_cairo_show_glyph_item (cairo_t *cr, * * The origin of the glyphs (the left edge of the line) will * be drawn at the current point of the cairo context. - * - * Since: 1.10 */ void -pango_cairo_show_layout_line (cairo_t *cr, - PangoLayoutLine *line) +pango_cairo_show_layout_line (cairo_t *cr, + PangoLayoutLine *line) { g_return_if_fail (cr != NULL); g_return_if_fail (line != NULL); @@ -1155,26 +1134,6 @@ pango_cairo_show_layout_line (cairo_t *cr, } /** - * pango_cairo_show_line: - * @cr: a Cairo context - * @line: a `PangoLine` - * - * Draws a `PangoLine` in the specified cairo context. - * - * The origin of the glyphs (the left edge of the line) will - * be drawn at the current point of the cairo context. - */ -void -pango_cairo_show_line (cairo_t *cr, - PangoLine *line) -{ - g_return_if_fail (cr != NULL); - g_return_if_fail (line != NULL); - - _pango_cairo_do_line (cr, line, FALSE); -} - -/** * pango_cairo_show_lines: * @cr: a Cairo context * @lines: a `PangoLines` object @@ -1282,41 +1241,18 @@ pango_cairo_glyph_string_path (cairo_t *cr, * * The origin of the glyphs (the left edge of the line) will be * at the current point of the cairo context. - * - * Since: 1.10 */ void -pango_cairo_layout_line_path (cairo_t *cr, - PangoLayoutLine *line) +pango_cairo_layout_line_path (cairo_t *cr, + PangoLayoutLine *line) { g_return_if_fail (cr != NULL); - g_return_if_fail (line != NULL); + g_return_if_fail (PANGO_IS_LAYOUT_LINE (line)); _pango_cairo_do_layout_line (cr, line, TRUE); } /** - * pango_cairo_line_path: - * @cr: a Cairo context - * @line: a `PangoLayoutLine` - * - * Adds the text in `PangoLine` to the current path in the - * specified cairo context. - * - * The origin of the glyphs (the left edge of the line) will be - * at the current point of the cairo context. - */ -void -pango_cairo_line_path (cairo_t *cr, - PangoLine *line) -{ - g_return_if_fail (cr != NULL); - g_return_if_fail (PANGO_IS_LINE (line)); - - _pango_cairo_do_line (cr, line, TRUE); -} - -/** * pango_cairo_layout_path: * @cr: a Cairo context * @layout: a Pango layout diff --git a/pango/pangocairo.h b/pango/pangocairo.h index 60d9d9d6..d42b9258 100644 --- a/pango/pangocairo.h +++ b/pango/pangocairo.h @@ -169,11 +169,6 @@ PANGO_AVAILABLE_IN_1_10 void pango_cairo_update_layout (cairo_t *cr, PangoLayout *layout); -PANGO_AVAILABLE_IN_ALL -PangoSimpleLayout *pango_cairo_create_simple_layout (cairo_t *cr); -PANGO_AVAILABLE_IN_ALL -void pango_cairo_update_simple_layout (cairo_t *cr, - PangoSimpleLayout *layout); /* * Rendering */ @@ -185,12 +180,9 @@ PANGO_AVAILABLE_IN_1_22 void pango_cairo_show_glyph_item (cairo_t *cr, const char *text, PangoGlyphItem *glyph_item); -PANGO_AVAILABLE_IN_1_10 -void pango_cairo_show_layout_line (cairo_t *cr, - PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -void pango_cairo_show_line (cairo_t *cr, - PangoLine *line); +void pango_cairo_show_layout_line (cairo_t *cr, + PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL void pango_cairo_show_lines (cairo_t *cr, PangoLines *lines); @@ -214,17 +206,14 @@ void pango_cairo_glyph_string_path (cairo_t *cr, PangoFont *font, PangoGlyphString *glyphs); PANGO_AVAILABLE_IN_1_10 -void pango_cairo_layout_line_path (cairo_t *cr, - PangoLayoutLine *line); -PANGO_AVAILABLE_IN_1_10 void pango_cairo_layout_path (cairo_t *cr, PangoLayout *layout); PANGO_AVAILABLE_IN_ALL -void pango_cairo_line_path (cairo_t *cr, - PangoLine *line); +void pango_cairo_layout_line_path (cairo_t *cr, + PangoLayoutLine *line); PANGO_AVAILABLE_IN_ALL -void pango_cairo_lines_path (cairo_t *cr, - PangoLines *lines); +void pango_cairo_lines_path (cairo_t *cr, + PangoLines *lines); PANGO_AVAILABLE_IN_1_14 void pango_cairo_error_underline_path (cairo_t *cr, diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c index 9d555a37..4f0ad457 100644 --- a/pango/pangofc-font.c +++ b/pango/pangofc-font.c @@ -419,22 +419,26 @@ pango_fc_font_create_base_metrics_for_context (PangoFcFont *fcfont, static int max_glyph_width (PangoLayout *layout) { + PangoLines *lines; int max_width = 0; - GSList *l, *r; + GSList *r; - for (l = pango_layout_get_lines_readonly (layout); l; l = l->next) + lines = pango_layout_get_lines (layout); + for (int i = 0; i < pango_lines_get_line_count (lines); i++) { - PangoLayoutLine *line = l->data; + PangoLayoutLine *line = pango_lines_get_line (lines, i, NULL, NULL); - for (r = line->runs; r; r = r->next) - { - PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; - int i; + for (r = pango_layout_line_get_runs (line); r; r = r->next) + { + PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; + int i; - for (i = 0; i < glyphs->num_glyphs; i++) - if (glyphs->glyphs[i].geometry.width > max_width) - max_width = glyphs->glyphs[i].geometry.width; - } + for (i = 0; i < glyphs->num_glyphs; i++) + { + if (glyphs->glyphs[i].geometry.width > max_width) + max_width = glyphs->glyphs[i].geometry.width; + } + } } return max_width; @@ -476,8 +480,7 @@ pango_fc_font_get_metrics (PangoFont *font, /* Note: we need to add info to the list before calling * into PangoLayout below, to prevent recursion */ - fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang, - info); + fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang, info); info->sample_str = sample_str; @@ -501,7 +504,7 @@ pango_fc_font_get_metrics (PangoFont *font, pango_font_description_free (desc); pango_layout_set_text (layout, sample_str, -1); - pango_layout_get_extents (layout, NULL, &extents); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &extents); sample_str_width = pango_utf8_strwidth (sample_str); g_assert (sample_str_width > 0); diff --git a/pango/pangoft2-render.c b/pango/pangoft2-render.c index f2da8e7f..902f7d6f 100644 --- a/pango/pangoft2-render.c +++ b/pango/pangoft2-render.c @@ -26,6 +26,7 @@ #include "pango-font-private.h" #include "pangoft2-private.h" #include "pango-impl-utils.h" +#include "pango-layout-line-private.h" /* for compatibility with older freetype versions */ #ifndef FT_LOAD_TARGET_MONO @@ -613,7 +614,7 @@ pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap, pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap); - pango_renderer_draw_layout (renderer, layout, x, y); + pango_renderer_draw_lines (renderer, pango_layout_get_lines (layout), x, y); } /** @@ -653,19 +654,17 @@ pango_ft2_render_layout (FT_Bitmap *bitmap, */ void pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y) + PangoLayoutLine *line, + int x, + int y) { - PangoContext *context; PangoFontMap *fontmap; PangoRenderer *renderer; g_return_if_fail (bitmap != NULL); g_return_if_fail (line != NULL); - context = pango_layout_get_context (line->layout); - fontmap = pango_context_get_font_map (context); + fontmap = pango_context_get_font_map (line->context); renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap)); pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap); @@ -683,10 +682,10 @@ pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap, * Render a `PangoLayoutLine` onto a FreeType2 bitmap */ void -pango_ft2_render_layout_line (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y) +pango_ft2_render_layout_line (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y) { pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE); } diff --git a/pango/pangoft2.h b/pango/pangoft2.h index 239eb05e..3610a125 100644 --- a/pango/pangoft2.h +++ b/pango/pangoft2.h @@ -87,15 +87,16 @@ void pango_ft2_render_transformed (FT_Bitmap *bitmap, int y); PANGO_AVAILABLE_IN_ALL -void pango_ft2_render_layout_line (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y); +void pango_ft2_render_layout_line (FT_Bitmap *bitmap, + PangoLayoutLine *line, + int x, + int y); PANGO_AVAILABLE_IN_1_6 void pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap, - PangoLayoutLine *line, - int x, - int y); + PangoLayoutLine *line, + int x, + int y); + PANGO_AVAILABLE_IN_ALL void pango_ft2_render_layout (FT_Bitmap *bitmap, PangoLayout *layout, diff --git a/pango/pangoxft-render.c b/pango/pangoxft-render.c index 9228a5c5..714bc5c3 100644 --- a/pango/pangoxft-render.c +++ b/pango/pangoxft-render.c @@ -24,6 +24,7 @@ #include "pangoxft-render.h" #include "pangoxft-private.h" +#include "pango-layout-line-private.h" enum { PROP_0, @@ -718,10 +719,10 @@ release_renderer (PangoRenderer *renderer) */ void pango_xft_render_layout (XftDraw *draw, - XftColor *color, - PangoLayout *layout, - int x, - int y) + XftColor *color, + PangoLayout *layout, + int x, + int y) { PangoContext *context; PangoFontMap *fontmap; @@ -735,7 +736,7 @@ pango_xft_render_layout (XftDraw *draw, fontmap = pango_context_get_font_map (context); renderer = get_renderer (fontmap, draw, color); - pango_renderer_draw_layout (renderer, layout, x, y); + pango_renderer_draw_lines (renderer, pango_layout_get_lines (layout), x, y); release_renderer (renderer); } @@ -755,12 +756,11 @@ pango_xft_render_layout (XftDraw *draw, */ void pango_xft_render_layout_line (XftDraw *draw, - XftColor *color, - PangoLayoutLine *line, - int x, - int y) + XftColor *color, + PangoLayoutLine *line, + int x, + int y) { - PangoContext *context; PangoFontMap *fontmap; PangoRenderer *renderer; @@ -768,8 +768,7 @@ pango_xft_render_layout_line (XftDraw *draw, g_return_if_fail (color != NULL); g_return_if_fail (line != NULL); - context = pango_layout_get_context (line->layout); - fontmap = pango_context_get_font_map (context); + fontmap = pango_context_get_font_map (line->context); renderer = get_renderer (fontmap, draw, color); pango_renderer_draw_layout_line (renderer, line, x, y); diff --git a/pango/pangoxft-render.h b/pango/pangoxft-render.h index bf4b33e9..8e0316c2 100644 --- a/pango/pangoxft-render.h +++ b/pango/pangoxft-render.h @@ -148,10 +148,10 @@ void pango_xft_render_layout_line (XftDraw *draw, int y); PANGO_AVAILABLE_IN_1_8 void pango_xft_render_layout (XftDraw *draw, - XftColor *color, - PangoLayout *layout, - int x, - int y); + XftColor *color, + PangoLayout *layout, + int x, + int y); G_END_DECLS diff --git a/pango/serializer.c b/pango/serializer.c index 426eee87..4ba8e690 100644 --- a/pango/serializer.c +++ b/pango/serializer.c @@ -22,13 +22,10 @@ #include "config.h" #include <pango/pango-layout.h> -#include <pango/pango-layout-private.h> #include <pango/pango-context-private.h> #include <pango/pango-enum-types.h> #include <pango/pango-font-private.h> -#include <pango/pango-line-private.h> -#include <pango/pango-lines.h> -#include <pango/pango-simple-layout.h> +#include <pango/pango-layout-line-private.h> #include <pango/pango-utils-internal.h> #include <hb-ot.h> @@ -244,14 +241,14 @@ static const char *direction_names[] = { NULL }; -static const char *alignment_names[] = { - "left", - "center", - "right", +static const char *wrap_names[] = { + "word", + "char", + "word-char", NULL }; -static const char *alignment_names2[] = { +static const char *alignment_names[] = { "left", "center", "right", @@ -260,13 +257,6 @@ static const char *alignment_names2[] = { NULL }; -static const char *wrap_names[] = { - "word", - "char", - "word-char", - NULL -}; - static const char *ellipsize_names[] = { "none", "start", @@ -647,7 +637,7 @@ add_font (GtkJsonPrinter *printer, static void add_run (GtkJsonPrinter *printer, const char *text, - PangoLayoutRun *run) + PangoGlyphItem *run) { char *str; @@ -719,136 +709,10 @@ add_run (GtkJsonPrinter *printer, #undef ANALYSIS_FLAGS static void -add_line (GtkJsonPrinter *printer, - PangoLayoutLine *line) -{ - gtk_json_printer_start_object (printer, NULL); - - gtk_json_printer_add_integer (printer, "start-index", line->start_index); - gtk_json_printer_add_integer (printer, "length", line->length); - gtk_json_printer_add_boolean (printer, "paragraph-start", line->is_paragraph_start); - gtk_json_printer_add_string (printer, "direction", direction_names[line->resolved_dir]); - - gtk_json_printer_start_array (printer, "runs"); - for (GSList *l = line->runs; l; l = l->next) - { - PangoLayoutRun *run = l->data; - add_run (printer, line->layout->text, run); - } - gtk_json_printer_end (printer); - - gtk_json_printer_end (printer); -} - -static void -add_output (GtkJsonPrinter *printer, - PangoLayout *layout) -{ - int width, height; - const PangoLogAttr *log_attrs; - int n_attrs; - - gtk_json_printer_start_object (printer, "output"); - - gtk_json_printer_add_boolean (printer, "is-wrapped", pango_layout_is_wrapped (layout)); - gtk_json_printer_add_boolean (printer, "is-ellipsized", pango_layout_is_ellipsized (layout)); - gtk_json_printer_add_integer (printer, "unknown-glyphs", pango_layout_get_unknown_glyphs_count (layout)); - - pango_layout_get_size (layout, &width, &height); - gtk_json_printer_add_integer (printer, "width", width); - gtk_json_printer_add_integer (printer, "height", height); - - log_attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); - add_log_attrs (printer, log_attrs, n_attrs); - - gtk_json_printer_start_array (printer, "lines"); - for (GSList *l = layout->lines; l; l = l->next) - { - PangoLayoutLine *line = l->data; - - add_line (printer, line); - } - gtk_json_printer_end (printer); - - gtk_json_printer_end (printer); -} - -static void -layout_to_json (GtkJsonPrinter *printer, - PangoLayout *layout, - PangoLayoutSerializeFlags flags) -{ - const char *str; - - gtk_json_printer_start_object (printer, NULL); - - if (flags & PANGO_LAYOUT_SERIALIZE_CONTEXT) - add_context (printer, layout->context); - - str = (const char *) g_object_get_data (G_OBJECT (layout), "comment"); - if (str) - gtk_json_printer_add_string (printer, "comment", str); - - gtk_json_printer_add_string (printer, "text", layout->text); - - add_attr_list (printer, layout->attrs); - - if (layout->font_desc) - { - char *str = pango_font_description_to_string (layout->font_desc); - gtk_json_printer_add_string (printer, "font", str); - g_free (str); - } - - add_tab_array (printer, layout->tabs); - - if (layout->justify) - gtk_json_printer_add_boolean (printer, "justify", TRUE); - - if (layout->justify_last_line) - gtk_json_printer_add_boolean (printer, "justify-last-line", TRUE); - - if (layout->single_paragraph) - gtk_json_printer_add_boolean (printer, "single-paragraph", TRUE); - - if (!layout->auto_dir) - gtk_json_printer_add_boolean (printer, "auto-dir", FALSE); - - if (layout->alignment != PANGO_ALIGN_LEFT) - gtk_json_printer_add_string (printer, "alignment", alignment_names[layout->alignment]); - - if (layout->wrap != PANGO_WRAP_WORD) - gtk_json_printer_add_string (printer, "wrap", wrap_names[layout->wrap]); - - if (layout->ellipsize != PANGO_ELLIPSIZE_NONE) - gtk_json_printer_add_string (printer, "ellipsize", ellipsize_names[layout->ellipsize]); - - if (layout->width != -1) - gtk_json_printer_add_integer (printer, "width", layout->width); - - if (layout->height != -1) - gtk_json_printer_add_integer (printer, "height", layout->height); - - if (layout->indent != 0) - gtk_json_printer_add_integer (printer, "indent", layout->indent); - - if (layout->spacing != 0) - gtk_json_printer_add_integer (printer, "spacing", layout->spacing); - - if (layout->line_spacing != 0.) - gtk_json_printer_add_number (printer, "line-spacing", layout->line_spacing); - - if (flags & PANGO_LAYOUT_SERIALIZE_OUTPUT) - add_output (printer, layout); - - gtk_json_printer_end (printer); -} - -static void -line_to_json (GtkJsonPrinter *printer, - PangoLine *line, - int x, - int y) +line_to_json (GtkJsonPrinter *printer, + PangoLayoutLine *line, + int x, + int y) { gtk_json_printer_start_object (printer, NULL); @@ -875,7 +739,7 @@ line_to_json (GtkJsonPrinter *printer, gtk_json_printer_start_array (printer, "runs"); for (GSList *l = line->runs; l; l = l->next) { - PangoLayoutRun *run = l->data; + PangoGlyphItem *run = l->data; add_run (printer, line->data->text, run); } gtk_json_printer_end (printer); @@ -893,6 +757,10 @@ lines_to_json (GtkJsonPrinter *printer, gtk_json_printer_start_object (printer, "output"); + gtk_json_printer_add_boolean (printer, "wrapped", pango_lines_wrapped (lines)); + gtk_json_printer_add_boolean (printer, "ellipsized", pango_lines_ellipsized (lines)); + gtk_json_printer_add_boolean (printer, "hypenated", pango_lines_hyphenated (lines)); + gtk_json_printer_add_integer (printer, "unknown-glyphs", pango_lines_get_unknown_glyphs_count (lines)); pango_lines_get_size (lines, &width, &height); gtk_json_printer_add_integer (printer, "width", width); gtk_json_printer_add_integer (printer, "height", height); @@ -901,7 +769,7 @@ lines_to_json (GtkJsonPrinter *printer, for (int i = 0; i < pango_lines_get_line_count (lines); i++) { - PangoLine *line; + PangoLayoutLine *line; int x, y; line = pango_lines_get_line (lines, i, &x, &y); line_to_json (printer, line, x, y); @@ -913,68 +781,67 @@ lines_to_json (GtkJsonPrinter *printer, } static void -simple_layout_to_json (GtkJsonPrinter *printer, - PangoSimpleLayout *layout, - PangoSimpleLayoutSerializeFlags flags) +layout_to_json (GtkJsonPrinter *printer, + PangoLayout *layout, + PangoLayoutSerializeFlags flags) { const char *str; gtk_json_printer_start_object (printer, NULL); - if (flags & PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT) - add_context (printer, pango_simple_layout_get_context (layout)); + if (flags & PANGO_LAYOUT_SERIALIZE_CONTEXT) + add_context (printer, pango_layout_get_context (layout)); str = (const char *) g_object_get_data (G_OBJECT (layout), "comment"); if (str) gtk_json_printer_add_string (printer, "comment", str); - gtk_json_printer_add_string (printer, "text", pango_simple_layout_get_text (layout)); + gtk_json_printer_add_string (printer, "text", pango_layout_get_text (layout)); - add_attr_list (printer, pango_simple_layout_get_attributes (layout)); + add_attr_list (printer, pango_layout_get_attributes (layout)); - if (pango_simple_layout_get_font_description (layout)) + if (pango_layout_get_font_description (layout)) { - char *str = pango_font_description_to_string (pango_simple_layout_get_font_description (layout)); + char *str = pango_font_description_to_string (pango_layout_get_font_description (layout)); gtk_json_printer_add_string (printer, "font", str); g_free (str); } - if (pango_simple_layout_get_tabs (layout)) - add_tab_array (printer, pango_simple_layout_get_tabs (layout)); + add_tab_array (printer, pango_layout_get_tabs (layout)); - if (!pango_simple_layout_get_auto_dir (layout)) + if (!pango_layout_get_auto_dir (layout)) gtk_json_printer_add_boolean (printer, "auto-dir", FALSE); - if (pango_simple_layout_get_alignment (layout) != PANGO_ALIGNMENT_LEFT) - gtk_json_printer_add_string (printer, "alignment", alignment_names2[pango_simple_layout_get_alignment (layout)]); + if (pango_layout_get_alignment (layout) != PANGO_ALIGN_LEFT) + gtk_json_printer_add_string (printer, "alignment", alignment_names[pango_layout_get_alignment (layout)]); - if (pango_simple_layout_get_wrap (layout) != PANGO_WRAP_WORD) - gtk_json_printer_add_string (printer, "wrap", wrap_names[pango_simple_layout_get_wrap (layout)]); + if (pango_layout_get_wrap (layout) != PANGO_WRAP_WORD) + gtk_json_printer_add_string (printer, "wrap", wrap_names[pango_layout_get_wrap (layout)]); - if (pango_simple_layout_get_ellipsize (layout) != PANGO_ELLIPSIZE_NONE) - gtk_json_printer_add_string (printer, "ellipsize", ellipsize_names[pango_simple_layout_get_ellipsize (layout)]); + if (pango_layout_get_ellipsize (layout) != PANGO_ELLIPSIZE_NONE) + gtk_json_printer_add_string (printer, "ellipsize", ellipsize_names[pango_layout_get_ellipsize (layout)]); - if (pango_simple_layout_get_width (layout) != -1) - gtk_json_printer_add_integer (printer, "width", pango_simple_layout_get_width (layout)); + if (pango_layout_get_width (layout) != -1) + gtk_json_printer_add_integer (printer, "width", pango_layout_get_width (layout)); - if (pango_simple_layout_get_height (layout) != -1) - gtk_json_printer_add_integer (printer, "height", pango_simple_layout_get_height (layout)); + if (pango_layout_get_height (layout) != -1) + gtk_json_printer_add_integer (printer, "height", pango_layout_get_height (layout)); - if (pango_simple_layout_get_indent (layout) != 0) - gtk_json_printer_add_integer (printer, "indent", pango_simple_layout_get_indent (layout)); + if (pango_layout_get_indent (layout) != 0) + gtk_json_printer_add_integer (printer, "indent", pango_layout_get_indent (layout)); - if (pango_simple_layout_get_line_spacing (layout) != 0.) - gtk_json_printer_add_number (printer, "line-spacing", pango_simple_layout_get_line_spacing (layout)); + if (pango_layout_get_line_spacing (layout) != 0.) + gtk_json_printer_add_number (printer, "line-spacing", pango_layout_get_line_spacing (layout)); if (flags & PANGO_LAYOUT_SERIALIZE_OUTPUT) { const PangoLogAttr *log_attrs; int n_attrs; - log_attrs = pango_simple_layout_get_log_attrs (layout, &n_attrs); + log_attrs = pango_layout_get_log_attrs (layout, &n_attrs); add_log_attrs (printer, log_attrs, n_attrs); - lines_to_json (printer, pango_simple_layout_get_lines (layout)); + lines_to_json (printer, pango_layout_get_lines (layout)); } gtk_json_printer_end (printer); @@ -1527,9 +1394,6 @@ enum { LAYOUT_ATTRIBUTES, LAYOUT_FONT, LAYOUT_TABS, - LAYOUT_JUSTIFY, - LAYOUT_JUSTIFY_LAST_LINE, - LAYOUT_SINGLE_PARAGRAPH, LAYOUT_AUTO_DIR, LAYOUT_ALIGNMENT, LAYOUT_WRAP, @@ -1537,9 +1401,8 @@ enum { LAYOUT_WIDTH, LAYOUT_HEIGHT, LAYOUT_INDENT, - LAYOUT_SPACING, LAYOUT_LINE_SPACING, - LAYOUT_OUTPUT + LAYOUT_LINES }; static const char *layout_members[] = { @@ -1549,9 +1412,6 @@ static const char *layout_members[] = { "attributes", "font", "tabs", - "justify", - "justify-last-line", - "single-paragraph", "auto-dir", "alignment", "wrap", @@ -1559,9 +1419,8 @@ static const char *layout_members[] = { "width", "height", "indent", - "spacing", "line-spacing", - "output", + "lines", NULL }; @@ -1611,6 +1470,14 @@ json_parser_fill_layout (GtkJsonParser *parser, } break; + case LAYOUT_AUTO_DIR: + pango_layout_set_auto_dir (layout, gtk_json_parser_get_boolean (parser)); + break; + + case LAYOUT_LINE_SPACING: + pango_layout_set_line_spacing (layout, gtk_json_parser_get_number (parser)); + break; + case LAYOUT_TABS: { PangoTabArray *tabs = pango_tab_array_new (0, FALSE); @@ -1620,22 +1487,6 @@ json_parser_fill_layout (GtkJsonParser *parser, } break; - case LAYOUT_JUSTIFY: - pango_layout_set_justify (layout, gtk_json_parser_get_boolean (parser)); - break; - - case LAYOUT_JUSTIFY_LAST_LINE: - pango_layout_set_justify_last_line (layout, gtk_json_parser_get_boolean (parser)); - break; - - case LAYOUT_SINGLE_PARAGRAPH: - pango_layout_set_single_paragraph_mode (layout, gtk_json_parser_get_boolean (parser)); - break; - - case LAYOUT_AUTO_DIR: - pango_layout_set_auto_dir (layout, gtk_json_parser_get_boolean (parser)); - break; - case LAYOUT_ALIGNMENT: pango_layout_set_alignment (layout, (PangoAlignment) parser_select_string (parser, alignment_names)); break; @@ -1660,151 +1511,7 @@ json_parser_fill_layout (GtkJsonParser *parser, pango_layout_set_indent (layout, (int) gtk_json_parser_get_number (parser)); break; - case LAYOUT_SPACING: - pango_layout_set_spacing (layout, (int) gtk_json_parser_get_number (parser)); - break; - - case LAYOUT_LINE_SPACING: - pango_layout_set_line_spacing (layout, gtk_json_parser_get_number (parser)); - break; - - case LAYOUT_OUTPUT: - break; - - default: - break; - } - } - while (gtk_json_parser_next (parser)); - - gtk_json_parser_end (parser); -} - -enum { - SIMPLE_LAYOUT_CONTEXT, - SIMPLE_LAYOUT_COMMENT, - SIMPLE_LAYOUT_TEXT, - SIMPLE_LAYOUT_ATTRIBUTES, - SIMPLE_LAYOUT_FONT, - SIMPLE_LAYOUT_TABS, - SIMPLE_LAYOUT_AUTO_DIR, - SIMPLE_LAYOUT_ALIGNMENT, - SIMPLE_LAYOUT_WRAP, - SIMPLE_LAYOUT_ELLIPSIZE, - SIMPLE_LAYOUT_WIDTH, - SIMPLE_LAYOUT_HEIGHT, - SIMPLE_LAYOUT_INDENT, - SIMPLE_LAYOUT_LINE_SPACING, - SIMPLE_LAYOUT_LINES -}; - -static const char *simple_layout_members[] = { - "context", - "comment", - "text", - "attributes", - "font", - "tabs", - "auto-dir", - "alignment", - "wrap", - "ellipsize", - "width", - "height", - "indent", - "line-spacing", - "lines", - NULL -}; - -static void -json_parser_fill_simple_layout (GtkJsonParser *parser, - PangoSimpleLayout *layout, - PangoSimpleLayoutDeserializeFlags flags) -{ - gtk_json_parser_start_object (parser); - - do - { - char *str; - - switch (gtk_json_parser_select_member (parser, simple_layout_members)) - { - case SIMPLE_LAYOUT_CONTEXT: - if (flags & PANGO_LAYOUT_DESERIALIZE_CONTEXT) - json_parser_fill_context (parser, pango_simple_layout_get_context (layout)); - break; - - case SIMPLE_LAYOUT_COMMENT: - str = gtk_json_parser_get_string (parser); - g_object_set_data_full (G_OBJECT (layout), "comment", str, g_free); - break; - - case SIMPLE_LAYOUT_TEXT: - str = gtk_json_parser_get_string (parser); - pango_simple_layout_set_text (layout, str, -1); - g_free (str); - break; - - case SIMPLE_LAYOUT_ATTRIBUTES: - { - PangoAttrList *attributes = pango_attr_list_new (); - json_parser_fill_attr_list (parser, attributes); - pango_simple_layout_set_attributes (layout, attributes); - pango_attr_list_unref (attributes); - } - break; - - case SIMPLE_LAYOUT_FONT: - { - PangoFontDescription *desc = parser_get_font_description (parser);; - pango_simple_layout_set_font_description (layout, desc); - pango_font_description_free (desc); - } - break; - - case SIMPLE_LAYOUT_AUTO_DIR: - pango_simple_layout_set_auto_dir (layout, gtk_json_parser_get_boolean (parser)); - break; - - case SIMPLE_LAYOUT_LINE_SPACING: - pango_simple_layout_set_line_spacing (layout, gtk_json_parser_get_number (parser)); - break; - - case SIMPLE_LAYOUT_TABS: - { - PangoTabArray *tabs = pango_tab_array_new (0, FALSE); - json_parser_fill_tab_array (parser, tabs); - pango_simple_layout_set_tabs (layout, tabs); - pango_tab_array_free (tabs); - } - break; - - case SIMPLE_LAYOUT_ALIGNMENT: - pango_simple_layout_set_alignment (layout, (PangoAlignment) parser_select_string (parser, alignment_names2)); - break; - - case SIMPLE_LAYOUT_WRAP: - pango_simple_layout_set_wrap (layout, (PangoWrapMode) parser_select_string (parser, wrap_names)); - break; - - case SIMPLE_LAYOUT_ELLIPSIZE: - pango_simple_layout_set_ellipsize (layout, (PangoEllipsizeMode) parser_select_string (parser, ellipsize_names)); - break; - - case SIMPLE_LAYOUT_WIDTH: - pango_simple_layout_set_width (layout, (int) gtk_json_parser_get_number (parser)); - break; - - case SIMPLE_LAYOUT_HEIGHT: - pango_simple_layout_set_height (layout, (int) gtk_json_parser_get_number (parser)); - break; - - case SIMPLE_LAYOUT_INDENT: - pango_simple_layout_set_indent (layout, (int) gtk_json_parser_get_number (parser)); - break; - - case SIMPLE_LAYOUT_LINES: + case LAYOUT_LINES: break; default: @@ -1879,8 +1586,6 @@ json_parser_load_font (GtkJsonParser *parser, * The format is not meant as a permanent storage format. * * Returns: a `GBytes` containing the serialized form of @layout - * - * Since: 1.50 */ GBytes * pango_layout_serialize (PangoLayout *layout, @@ -1911,9 +1616,6 @@ pango_layout_serialize (PangoLayout *layout, /** * pango_layout_write_to_file: * @layout: a `PangoLayout` - * @flags: `PangoLayoutSerializeFlags` - * @filename: (type filename): the file to save it to - * @error: Return location for a potential error * * A convenience method to serialize a layout to a file. * @@ -1926,27 +1628,24 @@ pango_layout_serialize (PangoLayout *layout, * a layout to a file for later inspection. * * Returns: %TRUE if saving was successful - * - * Since: 1.50 */ gboolean -pango_layout_write_to_file (PangoLayout *layout, - PangoLayoutSerializeFlags flags, - const char *filename, - GError **error) +pango_layout_write_to_file (PangoLayout *layout, + const char *filename) { GBytes *bytes; gboolean result; g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE); g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - bytes = pango_layout_serialize (layout, flags); + bytes = pango_layout_serialize (layout, PANGO_LAYOUT_SERIALIZE_CONTEXT | + PANGO_LAYOUT_SERIALIZE_OUTPUT); + result = g_file_set_contents (filename, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), - error); + NULL); g_bytes_unref (bytes); return result; @@ -1968,8 +1667,6 @@ pango_layout_write_to_file (PangoLayout *layout, * result of serializing the layout again. * * Returns: (nullable) (transfer full): a new `PangoLayout` - * - * Since: 1.50 */ PangoLayout * pango_layout_deserialize (PangoContext *context, @@ -2091,147 +1788,6 @@ pango_font_deserialize (PangoContext *context, return font; } -/** - * pango_simple_layout_serialize: - * @layout: a `PangoSimpleLayout` - * @flags: `PangoSipleLayoutSerializeFlags` - * - * Serializes the @layout for later deserialization via [func@Pango.SimpleLayout.deserialize]. - * - * There are no guarantees about the format of the output across different - * versions of Pango and [func@Pango.SimpleLayout.deserialize] will reject data - * that it cannot parse. - * - * The intended use of this function is testing, benchmarking and debugging. - * The format is not meant as a permanent storage format. - * - * Returns: a `GBytes` containing the serialized form of @layout - */ -GBytes * -pango_simple_layout_serialize (PangoSimpleLayout *layout, - PangoSimpleLayoutSerializeFlags flags) -{ - GString *str; - GtkJsonPrinter *printer; - char *data; - gsize size; - - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), NULL); - - str = g_string_new (""); - - printer = gtk_json_printer_new (gstring_write, str, NULL); - gtk_json_printer_set_flags (printer, GTK_JSON_PRINTER_PRETTY); - simple_layout_to_json (printer, layout, flags); - gtk_json_printer_free (printer); - - g_string_append_c (str, '\n'); - - size = str->len; - data = g_string_free (str, FALSE); - - return g_bytes_new_take (data, size); -} - -/** - * pango_simple_layout_write_to_file: - * @layout: a `PangoLayout` - * - * A convenience method to serialize a layout to a file. - * - * It is equivalent to calling [method@Pango.SimpleLayout.serialize] - * followed by [func@GLib.file_set_contents]. - * - * See those two functions for details on the arguments. - * - * It is mostly intended for use inside a debugger to quickly dump - * a layout to a file for later inspection. - * - * Returns: %TRUE if saving was successful - */ -gboolean -pango_simple_layout_write_to_file (PangoSimpleLayout *layout, - const char *filename) -{ - GBytes *bytes; - gboolean result; - - g_return_val_if_fail (PANGO_IS_SIMPLE_LAYOUT (layout), FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - - bytes = pango_simple_layout_serialize (layout, PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT | - PANGO_SIMPLE_LAYOUT_SERIALIZE_OUTPUT); - - result = g_file_set_contents (filename, - g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes), - NULL); - g_bytes_unref (bytes); - - return result; -} - -/** - * pango_simple_layout_deserialize: - * @context: a `PangoContext` - * @flags: `PangoSimpleLayoutDeserializeFlags` - * @bytes: the bytes containing the data - * @error: return location for an error - * - * Loads data previously created via [method@Pango.SimpleLayout.serialize]. - * - * For a discussion of the supported format, see that function. - * - * Note: to verify that the returned layout is identical to - * the one that was serialized, you can compare @bytes to the - * result of serializing the layout again. - * - * Returns: (nullable) (transfer full): a new `PangoSimpleLayout` - */ -PangoSimpleLayout * -pango_simple_layout_deserialize (PangoContext *context, - GBytes *bytes, - PangoSimpleLayoutDeserializeFlags flags, - GError **error) -{ - PangoSimpleLayout *layout; - GtkJsonParser *parser; - const GError *parser_error; - - g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL); - - layout = pango_simple_layout_new (context); - - parser = gtk_json_parser_new_for_bytes (bytes); - json_parser_fill_simple_layout (parser, layout, flags); - - parser_error = gtk_json_parser_get_error (parser); - - if (parser_error) - { - gsize start, end; - int code; - - gtk_json_parser_get_error_offset (parser, &start, &end); - - if (g_error_matches (parser_error, GTK_JSON_ERROR, GTK_JSON_ERROR_VALUE)) - code = PANGO_LAYOUT_DESERIALIZE_INVALID_VALUE; - else if (g_error_matches (parser_error, GTK_JSON_ERROR, GTK_JSON_ERROR_SCHEMA)) - code = PANGO_LAYOUT_DESERIALIZE_MISSING_VALUE; - else - code = PANGO_LAYOUT_DESERIALIZE_INVALID; - - g_set_error (error, PANGO_LAYOUT_DESERIALIZE_ERROR, code, - "%ld:%ld: %s", start, end, parser_error->message); - - g_clear_object (&layout); - } - - gtk_json_parser_free (parser); - - return layout; -} - /* }}} */ /* vim:set foldmethod=marker expandtab: */ diff --git a/tests/test-bidi.c b/tests/test-bidi.c index cd650ca5..f8b05588 100644 --- a/tests/test-bidi.c +++ b/tests/test-bidi.c @@ -158,8 +158,8 @@ test_bidi_embedding_levels (void) } } -/* Some basic tests for pango_simple_layout_move_cursor inside - * a single PangoLine: +/* Some basic tests for pango_layout_move_cursor inside + * a single PangoLayoutLine: * - check that we actually move the cursor in the right direction * - check that we get through the line with at most n steps * - check that we don't skip legitimate cursor positions @@ -174,10 +174,10 @@ test_move_cursor_line (void) "aאב12b", "paragraph", // soft hyphens }; - PangoSimpleLayout *layout; + PangoLayout *layout; gboolean fail = FALSE; - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); for (int i = 0; i < G_N_ELEMENTS (tests); i++) { @@ -189,8 +189,8 @@ test_move_cursor_line (void) PangoRectangle s_pos, old_s_pos; PangoRectangle w_pos, old_w_pos; PangoLines *lines; - PangoLine *line; - PangoLine *new_line; + PangoLayoutLine *line; + PangoLayoutLine *new_line; struct { int direction; gboolean strong; @@ -208,15 +208,15 @@ test_move_cursor_line (void) int j; const char *p; - pango_simple_layout_set_text (layout, tests[i], -1); + pango_layout_set_text (layout, tests[i], -1); - text = pango_simple_layout_get_text (layout); - lines = pango_simple_layout_get_lines (layout); + text = pango_layout_get_text (layout); + lines = pango_layout_get_lines (layout); line = pango_lines_get_line (lines, 0, NULL, NULL); n_chars = g_utf8_strlen (text, -1); - attrs = pango_simple_layout_get_log_attrs (layout, &n_attrs); + attrs = pango_layout_get_log_attrs (layout, &n_attrs); strong_cursor = g_new (int, n_attrs); weak_cursor = g_new (int, n_attrs); met_cursor = g_new (gboolean, n_attrs); @@ -242,7 +242,7 @@ test_move_cursor_line (void) params[j].direction > 0 ? "->" : "<-", params[j].strong ? "strong" : "weak"); - if ((pango_line_get_resolved_direction (line) == PANGO_DIRECTION_LTR) == (params[j].direction > 0)) + if ((pango_layout_line_get_resolved_direction (line) == PANGO_DIRECTION_LTR) == (params[j].direction > 0)) start_index = 0; else start_index = strlen (text); @@ -354,30 +354,30 @@ test_move_cursor_para (void) { "some text, some more text,\n\n even more text", 60 }, { "long word", 40 }, }; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle pos, old_pos; int index; int trailing; const char *text; - PangoLine *line; + PangoLayoutLine *line; PangoRectangle ext; PangoLines *lines; - PangoLineIter *iter; - PangoLine *new_line; + PangoLayoutIter *iter; + PangoLayoutLine *new_line; - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); for (int i = 0; i < G_N_ELEMENTS (tests); i++) { - pango_simple_layout_set_text (layout, tests[i].text, -1); - text = pango_simple_layout_get_text (layout); + pango_layout_set_text (layout, tests[i].text, -1); + text = pango_layout_get_text (layout); if (tests[i].width > 0) - pango_simple_layout_set_width (layout, tests[i].width * PANGO_SCALE); + pango_layout_set_width (layout, tests[i].width * PANGO_SCALE); else - pango_simple_layout_set_width (layout, -1); + pango_layout_set_width (layout, -1); index = 0; - lines = pango_simple_layout_get_lines (layout); + lines = pango_layout_get_lines (layout); pango_lines_get_cursor_pos (lines, NULL, index, &pos, NULL); while (index < G_MAXINT) @@ -389,10 +389,10 @@ test_move_cursor_para (void) break; iter = pango_lines_get_iter (lines); - while (pango_line_iter_get_line (iter) != line) - pango_line_iter_next_line (iter); - pango_line_iter_get_line_extents (iter, NULL, &ext); - pango_line_iter_free (iter); + while (pango_layout_iter_get_line (iter) != line) + pango_layout_iter_next_line (iter); + pango_layout_iter_get_line_extents (iter, NULL, &ext); + pango_layout_iter_free (iter); pango_lines_move_cursor(lines, TRUE, NULL, @@ -433,10 +433,10 @@ test_move_cursor_para (void) pango_lines_index_to_line (lines, index, &line, NULL, NULL, NULL); g_assert_nonnull (line); iter = pango_lines_get_iter (lines); - while (pango_line_iter_get_line (iter) != line) - pango_line_iter_next_line (iter); - pango_line_iter_get_line_extents (iter, NULL, &ext); - pango_line_iter_free (iter); + while (pango_layout_iter_get_line (iter) != line) + pango_layout_iter_next_line (iter); + pango_layout_iter_get_line_extents (iter, NULL, &ext); + pango_layout_iter_free (iter); pango_lines_move_cursor (lines, TRUE, NULL, diff --git a/tests/test-break.c b/tests/test-break.c index 570ba1a5..d9039fc0 100644 --- a/tests/test-break.c +++ b/tests/test-break.c @@ -52,7 +52,7 @@ test_file (const gchar *filename, GString *string) char *test; char *text; PangoAttrList *attributes; - PangoSimpleLayout *layout; + PangoLayout *layout; g_file_get_contents (filename, &contents, &length, &error); g_assert_no_error (error); @@ -69,9 +69,9 @@ test_file (const gchar *filename, GString *string) pango_parse_markup (test, -1, 0, &attributes, &text, NULL, &error); g_assert_no_error (error); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, text, length); - pango_simple_layout_set_attributes (layout, attributes); + layout = pango_layout_new (context); + pango_layout_set_text (layout, text, length); + pango_layout_set_attributes (layout, attributes); #if 0 if (pango_layout_get_unknown_glyphs_count (layout) > 0) @@ -90,7 +90,7 @@ test_file (const gchar *filename, GString *string) } #endif - attrs = pango_simple_layout_get_log_attrs (layout, &len); + attrs = pango_layout_get_log_attrs (layout, &len); if (!pango_validate_log_attrs (text, length, attrs, len, &error)) { diff --git a/tests/test-ellipsize.c b/tests/test-ellipsize.c index d0fe2dec..f68d9baf 100644 --- a/tests/test-ellipsize.c +++ b/tests/test-ellipsize.c @@ -31,26 +31,26 @@ static PangoContext *context; static void test_ellipsize_height (void) { - PangoSimpleLayout *layout; + PangoLayout *layout; int height1, height2; PangoFontDescription *desc; - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); desc = pango_font_description_from_string ("Fixed 7"); //pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); - pango_simple_layout_set_text (layout, "some text that should be ellipsized", -1); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); - pango_lines_get_size (pango_simple_layout_get_lines (layout), NULL, &height1); + pango_layout_set_text (layout, "some text that should be ellipsized", -1); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); + pango_lines_get_size (pango_layout_get_lines (layout), NULL, &height1); - pango_simple_layout_set_width (layout, 100 * PANGO_SCALE); - pango_simple_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_width (layout, 100 * PANGO_SCALE); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); - g_assert_true (pango_lines_ellipsized (pango_simple_layout_get_lines (layout))); - pango_lines_get_size (pango_simple_layout_get_lines (layout), NULL, &height2); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); + g_assert_true (pango_lines_ellipsized (pango_layout_get_lines (layout))); + pango_lines_get_size (pango_layout_get_lines (layout), NULL, &height2); g_assert_cmpint (height1, ==, height2); @@ -62,18 +62,18 @@ test_ellipsize_height (void) static void test_ellipsize_crash (void) { - PangoSimpleLayout *layout; + PangoLayout *layout; - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); - pango_simple_layout_set_text (layout, "some text that should be ellipsized", -1); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); + pango_layout_set_text (layout, "some text that should be ellipsized", -1); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); - pango_simple_layout_set_width (layout, 100 * PANGO_SCALE); - pango_simple_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_width (layout, 100 * PANGO_SCALE); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); - g_assert_true (pango_lines_ellipsized (pango_simple_layout_get_lines (layout))); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); + g_assert_true (pango_lines_ellipsized (pango_layout_get_lines (layout))); g_object_unref (layout); } @@ -84,21 +84,21 @@ test_ellipsize_crash (void) static void test_ellipsize_fully (void) { - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle ink, logical; PangoRectangle ink2, logical2; - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); - pango_simple_layout_set_text (layout, "…", -1); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), &ink, &logical); + pango_layout_set_text (layout, "…", -1); + pango_lines_get_extents (pango_layout_get_lines (layout), &ink, &logical); - pango_simple_layout_set_text (layout, "ellipsized", -1); + pango_layout_set_text (layout, "ellipsized", -1); - pango_simple_layout_set_width (layout, 10 * PANGO_SCALE); - pango_simple_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_width (layout, 10 * PANGO_SCALE); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), &ink2, &logical2); + pango_lines_get_extents (pango_layout_get_lines (layout), &ink2, &logical2); g_assert_cmpint (ink.width, ==, ink2.width); g_assert_cmpint (logical.width, ==, logical2.width); diff --git a/tests/test-layout.c b/tests/test-layout.c index d7ee7377..f69e6904 100644 --- a/tests/test-layout.c +++ b/tests/test-layout.c @@ -45,7 +45,7 @@ test_layout (gconstpointer d) gsize length; GBytes *orig; PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; if (!PANGO_IS_FC_FONT_MAP (pango_cairo_font_map_get_default ())) { @@ -69,11 +69,11 @@ test_layout (gconstpointer d) orig = g_bytes_new_take (contents, length); context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_deserialize (context, orig, PANGO_SIMPLE_LAYOUT_DESERIALIZE_CONTEXT, &error); + layout = pango_layout_deserialize (context, orig, PANGO_LAYOUT_DESERIALIZE_CONTEXT, &error); g_assert_no_error (error); - bytes = pango_simple_layout_serialize (layout, PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT | - PANGO_SIMPLE_LAYOUT_SERIALIZE_OUTPUT); + bytes = pango_layout_serialize (layout, PANGO_LAYOUT_SERIALIZE_CONTEXT | + PANGO_LAYOUT_SERIALIZE_OUTPUT); g_object_unref (layout); g_object_unref (context); @@ -176,17 +176,17 @@ main (int argc, char *argv[]) GBytes *orig; GBytes *bytes; PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; g_file_get_contents (argv[1], &contents, &length, &error); g_assert_no_error (error); orig = g_bytes_new_take (contents, length); context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_deserialize (context, orig, PANGO_SIMPLE_LAYOUT_DESERIALIZE_CONTEXT, &error); + layout = pango_layout_deserialize (context, orig, PANGO_LAYOUT_DESERIALIZE_CONTEXT, &error); g_assert_no_error (error); - bytes = pango_simple_layout_serialize (layout, PANGO_SIMPLE_LAYOUT_SERIALIZE_CONTEXT | - PANGO_SIMPLE_LAYOUT_SERIALIZE_OUTPUT); + bytes = pango_layout_serialize (layout, PANGO_LAYOUT_SERIALIZE_CONTEXT | + PANGO_LAYOUT_SERIALIZE_OUTPUT); g_object_unref (layout); g_object_unref (context); diff --git a/tests/test-pangocairo-threads.c b/tests/test-pangocairo-threads.c index 308f87e4..abdc5624 100644 --- a/tests/test-pangocairo-threads.c +++ b/tests/test-pangocairo-threads.c @@ -18,20 +18,20 @@ create_surface (void) return cairo_image_surface_create (CAIRO_FORMAT_A8, WIDTH, HEIGHT); } -static PangoSimpleLayout * +static PangoLayout * create_layout (cairo_t *cr) { - PangoSimpleLayout *layout; + PangoLayout *layout; - layout = pango_cairo_create_simple_layout (cr); - pango_simple_layout_set_text (layout, text, -1); - pango_simple_layout_set_width (layout, WIDTH * PANGO_SCALE); + layout = pango_cairo_create_layout (cr); + pango_layout_set_text (layout, text, -1); + pango_layout_set_width (layout, WIDTH * PANGO_SCALE); return layout; } static void -draw (cairo_t *cr, PangoSimpleLayout *layout, unsigned int i) +draw (cairo_t *cr, PangoLayout *layout, unsigned int i) { cairo_set_source_rgba (cr, 1, 1, 1, 1); cairo_paint (cr); @@ -40,16 +40,16 @@ draw (cairo_t *cr, PangoSimpleLayout *layout, unsigned int i) cairo_identity_matrix (cr); cairo_scale (cr, (100 + i) / 100., (100 + i) / 100.); - pango_cairo_update_context (cr, pango_simple_layout_get_context (layout)); + pango_cairo_update_context (cr, pango_layout_get_context (layout)); - pango_cairo_show_lines (cr, pango_simple_layout_get_lines (layout)); + pango_cairo_show_lines (cr, pango_layout_get_lines (layout)); } static gpointer thread_func (gpointer data) { cairo_surface_t *surface = data; - PangoSimpleLayout *layout; + PangoLayout *layout; int i; cairo_t *cr = cairo_create (surface); @@ -102,7 +102,7 @@ pangocairo_threads (void) { cairo_surface_t *ref_surface = create_surface (); cairo_t *cr = cairo_create (ref_surface); - PangoSimpleLayout *layout = create_layout (cr); + PangoLayout *layout = create_layout (cr); unsigned char *ref_data = cairo_image_surface_get_data (ref_surface); unsigned int len = WIDTH * HEIGHT; diff --git a/tests/testiter.c b/tests/testiter.c index 5282c236..7327e1df 100644 --- a/tests/testiter.c +++ b/tests/testiter.c @@ -77,10 +77,10 @@ const char *test_texts[] = * - GlyphString's index_to_x positions match those returned by the Iter */ static void -iter_char_test (PangoSimpleLayout *layout) +iter_char_test (PangoLayout *layout) { PangoRectangle extents, run_extents; - PangoLineIter *iter; + PangoLayoutIter *iter; PangoGlyphItem *run; int num_chars; int i, index, offset; @@ -88,10 +88,10 @@ iter_char_test (PangoSimpleLayout *layout) gboolean iter_next_ok, rtl; const char *text, *ptr; - text = pango_simple_layout_get_text (layout); + text = pango_layout_get_text (layout); num_chars = g_utf8_strlen (text, -1); - iter = pango_lines_get_iter (pango_simple_layout_get_lines (layout)); + iter = pango_lines_get_iter (pango_layout_get_lines (layout)); iter_next_ok = TRUE; for (i = 0 ; i < num_chars; ++i) @@ -99,19 +99,19 @@ iter_char_test (PangoSimpleLayout *layout) gchar *char_str; g_assert (iter_next_ok); - index = pango_line_iter_get_index (iter); + index = pango_layout_iter_get_index (iter); ptr = text + index; char_str = g_strndup (ptr, g_utf8_next_char (ptr) - ptr); verbose ("i=%d (visual), index = %d '%s':\n", i, index, char_str); g_free (char_str); - pango_line_iter_get_char_extents (iter, &extents); + pango_layout_iter_get_char_extents (iter, &extents); verbose (" char extents: x=%d,y=%d w=%d,h=%d\n", extents.x, extents.y, extents.width, extents.height); - run = pango_line_iter_get_run (iter); + run = pango_layout_iter_get_run (iter); if (run) { @@ -119,7 +119,7 @@ iter_char_test (PangoSimpleLayout *layout) char *str; /* Get needed data for the GlyphString */ - pango_line_iter_get_run_extents (iter, NULL, &run_extents); + pango_layout_iter_get_run_extents (iter, NULL, &run_extents); offset = run->item->offset; rtl = run->item->analysis.level%2; desc = pango_font_describe (run->item->analysis.font); @@ -153,7 +153,7 @@ iter_char_test (PangoSimpleLayout *layout) /* We're on a line terminator */ } - iter_next_ok = pango_line_iter_next_char (iter); + iter_next_ok = pango_layout_iter_next_char (iter); verbose ("more to go? %d\n", iter_next_ok); } @@ -161,34 +161,34 @@ iter_char_test (PangoSimpleLayout *layout) * input string */ g_assert (!iter_next_ok); - pango_line_iter_free (iter); + pango_layout_iter_free (iter); } static void -iter_cluster_test (PangoSimpleLayout *layout) +iter_cluster_test (PangoLayout *layout) { PangoRectangle extents; - PangoLineIter *iter; + PangoLayoutIter *iter; int index; gboolean iter_next_ok; - PangoLine *last_line = NULL; + PangoLayoutLine *last_line = NULL; int expected_next_x = 0; - iter = pango_lines_get_iter (pango_simple_layout_get_lines (layout)); + iter = pango_lines_get_iter (pango_layout_get_lines (layout)); iter_next_ok = TRUE; while (iter_next_ok) { - PangoLine *line = pango_line_iter_get_line (iter); + PangoLayoutLine *line = pango_layout_iter_get_line (iter); /* Every cluster is part of a run */ - g_assert (pango_line_iter_get_run (iter)); + g_assert (pango_layout_iter_get_run (iter)); - index = pango_line_iter_get_index (iter); + index = pango_layout_iter_get_index (iter); - pango_line_iter_get_cluster_extents (iter, NULL, &extents); + pango_layout_iter_get_cluster_extents (iter, NULL, &extents); - iter_next_ok = pango_line_iter_next_cluster (iter); + iter_next_ok = pango_layout_iter_next_cluster (iter); verbose ("index = %d:\n", index); verbose (" cluster extents: x=%d,y=%d w=%d,h=%d\n", @@ -210,7 +210,7 @@ iter_cluster_test (PangoSimpleLayout *layout) g_assert (!iter_next_ok); - pango_line_iter_free (iter); + pango_layout_iter_free (iter); } static void @@ -220,15 +220,15 @@ test_layout_iter (void) PangoFontMap *fontmap; PangoContext *context; PangoFontDescription *font_desc; - PangoSimpleLayout *layout; + PangoLayout *layout; fontmap = pango_cairo_font_map_get_default (); context = pango_font_map_create_context (fontmap); font_desc = pango_font_description_from_string ("cantarell 11"); pango_context_set_font_description (context, font_desc); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_width (layout, LAYOUT_WIDTH); + layout = pango_layout_new (context); + pango_layout_set_width (layout, LAYOUT_WIDTH); for (ptext = test_texts; *ptext != NULL; ++ptext) { @@ -237,7 +237,7 @@ test_layout_iter (void) verbose ( "len=%ld, bytes=%ld\n", (long)g_utf8_strlen (*ptext, -1), (long)strlen (*ptext)); - pango_simple_layout_set_text (layout, *ptext, -1); + pango_layout_set_text (layout, *ptext, -1); iter_char_test (layout); iter_cluster_test (layout); } @@ -253,8 +253,8 @@ test_glyphitem_iter (void) PangoFontMap *fontmap; PangoContext *context; PangoFontDescription *font_desc; - PangoSimpleLayout *layout; - PangoLine *line; + PangoLayout *layout; + PangoLayoutLine *line; const char *text; GSList *l; @@ -263,13 +263,13 @@ test_glyphitem_iter (void) font_desc = pango_font_description_from_string ("cantarell 11"); pango_context_set_font_description (context, font_desc); - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); /* This shouldn't form any ligatures. */ - pango_simple_layout_set_text (layout, "test تست", -1); - text = pango_simple_layout_get_text (layout); + pango_layout_set_text (layout, "test تست", -1); + text = pango_layout_get_text (layout); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); - for (l = pango_line_get_runs (line); l; l = l->next) + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); + for (l = pango_layout_line_get_runs (line); l; l = l->next) { PangoGlyphItem *run = l->data; int direction; diff --git a/tests/testmisc.c b/tests/testmisc.c index 7bb46f35..98e022cd 100644 --- a/tests/testmisc.c +++ b/tests/testmisc.c @@ -61,13 +61,13 @@ static void test_short_string_crash (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle ext; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "short text", 200); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), &ext, &ext); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "short text", 200); + pango_lines_get_extents (pango_layout_get_lines (layout), &ext, &ext); g_object_unref (layout); g_object_unref (context); @@ -91,15 +91,15 @@ static void test_line_height (void) { PangoContext *context; - PangoSimpleLayout *layout; - PangoLine *line; + PangoLayout *layout; + PangoLayoutLine *line; PangoRectangle ext; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one\ttwo", -1); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); - pango_line_get_extents (line, NULL, &ext); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one\ttwo", -1); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); + pango_layout_line_get_extents (line, NULL, &ext); g_assert_cmpint (ext.height, >, 0); @@ -111,27 +111,27 @@ static void test_line_height2 (void) { PangoContext *context; - PangoSimpleLayout *layout; - PangoLine *line; + PangoLayout *layout; + PangoLayoutLine *line; PangoRectangle ext1, ext2; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one", -1); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one", -1); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); g_assert_nonnull (line); - pango_line_get_extents (line, NULL, &ext1); + pango_layout_line_get_extents (line, NULL, &ext1); - pango_simple_layout_write_to_file (layout, "one.layout"); + pango_layout_write_to_file (layout, "one.layout"); - pango_simple_layout_set_text (layout, "", -1); + pango_layout_set_text (layout, "", -1); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); g_assert_nonnull (line); - pango_line_get_extents (line, NULL, &ext2); + pango_layout_line_get_extents (line, NULL, &ext2); - pango_simple_layout_write_to_file (layout, "empty.layout"); + pango_layout_write_to_file (layout, "empty.layout"); g_assert_cmpint (ext1.height, ==, ext2.height); @@ -143,29 +143,29 @@ static void test_line_height3 (void) { PangoContext *context; - PangoSimpleLayout *layout; - PangoLine *line; + PangoLayout *layout; + PangoLayoutLine *line; PangoAttrList *attrs; PangoRectangle ext1; PangoRectangle ext2; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one", -1); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one", -1); attrs = pango_attr_list_new (); pango_attr_list_insert (attrs, pango_attr_line_height_new (2.0)); - pango_simple_layout_set_attributes (layout, attrs); + pango_layout_set_attributes (layout, attrs); pango_attr_list_unref (attrs); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); - pango_line_get_extents (line, NULL, &ext1); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); + pango_layout_line_get_extents (line, NULL, &ext1); - pango_simple_layout_set_text (layout, "", -1); + pango_layout_set_text (layout, "", -1); - g_assert_cmpint (pango_lines_get_line_count (pango_simple_layout_get_lines (layout)), ==, 1); - line = pango_lines_get_line (pango_simple_layout_get_lines (layout), 0, NULL, NULL); - pango_line_get_extents (line, NULL, &ext2); + g_assert_cmpint (pango_lines_get_line_count (pango_layout_get_lines (layout)), ==, 1); + line = pango_lines_get_line (pango_layout_get_lines (layout), 0, NULL, NULL); + pango_layout_line_get_extents (line, NULL, &ext2); g_assert_cmpint (ext1.height, ==, ext2.height); @@ -177,8 +177,8 @@ static void test_run_height (void) { PangoContext *context; - PangoSimpleLayout *layout; - PangoLineIter *iter; + PangoLayout *layout; + PangoLayoutIter *iter; PangoRectangle logical1, logical2; if (strcmp (G_OBJECT_TYPE_NAME (pango_cairo_font_map_get_default ()), "PangoCairoCoreTextFontMap") == 0) @@ -188,18 +188,18 @@ test_run_height (void) } context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one", -1); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one", -1); - iter = pango_lines_get_iter (pango_simple_layout_get_lines (layout)); - pango_line_iter_get_run_extents (iter, NULL, &logical1); - pango_line_iter_free (iter); + iter = pango_lines_get_iter (pango_layout_get_lines (layout)); + pango_layout_iter_get_run_extents (iter, NULL, &logical1); + pango_layout_iter_free (iter); - pango_simple_layout_set_text (layout, "", -1); + pango_layout_set_text (layout, "", -1); - iter = pango_lines_get_iter (pango_simple_layout_get_lines (layout)); - pango_line_iter_get_run_extents (iter, NULL, &logical2); - pango_line_iter_free (iter); + iter = pango_lines_get_iter (pango_layout_get_lines (layout)); + pango_layout_iter_get_run_extents (iter, NULL, &logical2); + pango_layout_iter_free (iter); g_assert_cmpint (logical1.height, ==, logical2.height); @@ -211,13 +211,13 @@ static void test_cursor_height (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle strong; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one\ttwo", -1); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 0, &strong, NULL); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one\ttwo", -1); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 0, &strong, NULL); g_assert_cmpint (strong.height, >, 0); @@ -229,7 +229,7 @@ static void test_cursor_height2 (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle strong1, strong2; if (strcmp (G_OBJECT_TYPE_NAME (pango_cairo_font_map_get_default ()), "PangoCairoCoreTextFontMap") == 0) @@ -239,14 +239,14 @@ test_cursor_height2 (void) } context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "one", -1); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one", -1); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 0, &strong1, NULL); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 0, &strong1, NULL); - pango_simple_layout_set_text (layout, "", -1); + pango_layout_set_text (layout, "", -1); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 0, &strong2, NULL); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 0, &strong2, NULL); g_assert_cmpint (strong1.height, ==, strong2.height); @@ -440,22 +440,22 @@ static void test_get_cursor_crash (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; int i; const char *string = "foo\n\rbar\r\nbaz\n\nqux\n\n.."; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); - pango_simple_layout_set_text (layout, string, -1); + pango_layout_set_text (layout, string, -1); for (i = 0; string[i]; i++) { PangoRectangle rectA, rectB; - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, i, &rectA, &rectB); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, i, &rectA, &rectB); g_assert_cmpint (rectA.x, ==, rectB.x); } @@ -472,27 +472,27 @@ test_get_cursor (void) { const char *text = "abאב"; PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle strong, weak; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, text, -1); + layout = pango_layout_new (context); + pango_layout_set_text (layout, text, -1); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 0, &strong, &weak); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 0, &strong, &weak); g_assert_cmpint (strong.x, ==, weak.x); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 1, &strong, &weak); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 1, &strong, &weak); g_assert_cmpint (strong.x, ==, weak.x); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 2, &strong, &weak); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 2, &strong, &weak); g_assert_cmpint (strong.x, !=, weak.x); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 4, &strong, &weak); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 4, &strong, &weak); g_assert_cmpint (strong.x, ==, weak.x); - pango_lines_get_cursor_pos (pango_simple_layout_get_lines (layout), NULL, 6, &strong, &weak); + pango_lines_get_cursor_pos (pango_layout_get_lines (layout), NULL, 6, &strong, &weak); g_assert_cmpint (strong.x, !=, weak.x); g_object_unref (layout); @@ -512,29 +512,29 @@ test_index_to_x (void) for (int i = 0; i < G_N_ELEMENTS (tests); i++) { - PangoSimpleLayout *layout; + PangoLayout *layout; const char *text; const char *p; - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, tests[i], -1); - text = pango_simple_layout_get_text (layout); + layout = pango_layout_new (context); + pango_layout_set_text (layout, tests[i], -1); + text = pango_layout_get_text (layout); for (p = text; *p; p = g_utf8_next_char (p)) { int index = p - text; - PangoLine *line; + PangoLayoutLine *line; int x; int index2, trailing; gunichar ch; ch = g_utf8_get_char (p); - pango_lines_index_to_line (pango_simple_layout_get_lines (layout), index, &line, NULL, NULL, NULL); + pango_lines_index_to_line (pango_layout_get_lines (layout), index, &line, NULL, NULL, NULL); g_assert_nonnull (line); - pango_line_index_to_x (line, index, 0, &x); - pango_line_x_to_index (line, x, &index2, &trailing); + pango_layout_line_index_to_x (line, index, 0, &x); + pango_layout_line_x_to_index (line, x, &index2, &trailing); if (!pango_is_zero_width (ch)) g_assert_cmpint (index, ==, index2); } @@ -579,9 +579,9 @@ test_extents (void) for (int i = 0; i < G_N_ELEMENTS (tests); i++) { - PangoSimpleLayout *layout; + PangoLayout *layout; PangoLines *lines; - PangoLineIter *iter; + PangoLayoutIter *iter; PangoRectangle layout_extents; PangoRectangle line_extents; PangoRectangle run_extents; @@ -591,22 +591,22 @@ test_extents (void) PangoRectangle strong, weak; int index; - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, tests[i].text, -1); - pango_simple_layout_set_width (layout, tests[i].width > 0 ? tests[i].width * PANGO_SCALE : tests[i].width); + layout = pango_layout_new (context); + pango_layout_set_text (layout, tests[i].text, -1); + pango_layout_set_width (layout, tests[i].width > 0 ? tests[i].width * PANGO_SCALE : tests[i].width); - lines = pango_simple_layout_get_lines (layout); + lines = pango_layout_get_lines (layout); pango_lines_get_extents (lines, NULL, &layout_extents); iter = pango_lines_get_iter (lines); do { - pango_line_iter_get_line_extents (iter, NULL, &line_extents); - pango_line_iter_get_run_extents (iter, NULL, &run_extents); - pango_line_iter_get_cluster_extents (iter, NULL, &cluster_extents); - pango_line_iter_get_char_extents (iter, &char_extents); - index = pango_line_iter_get_index (iter); + pango_layout_iter_get_line_extents (iter, NULL, &line_extents); + pango_layout_iter_get_run_extents (iter, NULL, &run_extents); + pango_layout_iter_get_cluster_extents (iter, NULL, &cluster_extents); + pango_layout_iter_get_char_extents (iter, &char_extents); + index = pango_layout_iter_get_index (iter); pango_lines_index_to_pos (lines, NULL, index, &pos); if (pos.width < 0) { @@ -624,9 +624,9 @@ test_extents (void) g_assert_true (pango_rectangle_contains (&line_extents, &strong)); g_assert_true (pango_rectangle_contains (&line_extents, &weak)); } - while (pango_line_iter_next_char (iter)); + while (pango_layout_iter_next_char (iter)); - pango_line_iter_free (iter); + pango_layout_iter_free (iter); g_object_unref (layout); } @@ -637,7 +637,7 @@ static void test_empty_line_height (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoFontDescription *description; PangoRectangle ext1, ext2, ext3; cairo_font_options_t *options; @@ -664,20 +664,20 @@ test_empty_line_height (void) pango_cairo_context_set_font_options (context, options); cairo_font_options_destroy (options); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_font_description (layout, description); + layout = pango_layout_new (context); + pango_layout_set_font_description (layout, description); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext1); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext1); - pango_simple_layout_set_text (layout, "a", 1); + pango_layout_set_text (layout, "a", 1); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext2); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext2); g_assert_cmpint (ext1.height, ==, ext2.height); - pango_simple_layout_set_text (layout, "Pg", 1); + pango_layout_set_text (layout, "Pg", 1); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext3); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext3); g_assert_cmpint (ext2.height, ==, ext3.height); @@ -772,19 +772,19 @@ static void test_wrap_char (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoRectangle ext, ext1; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, "Rows can have suffix widgets", -1); - pango_simple_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "Rows can have suffix widgets", -1); + pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); - pango_simple_layout_set_width (layout, 0); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext); + pango_layout_set_width (layout, 0); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext); - pango_simple_layout_set_width (layout, ext.width); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext1); + pango_layout_set_width (layout, ext.width); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext1); g_assert_cmpint (ext.width, ==, ext1.width); g_assert_cmpint (ext.height, >=, ext1.height); @@ -798,7 +798,7 @@ static void test_small_caps_crash (void) { PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; PangoFontDescription *desc; PangoRectangle ext; @@ -809,13 +809,13 @@ test_small_caps_crash (void) } context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); - layout = pango_simple_layout_new (context); + layout = pango_layout_new (context); desc = pango_font_description_from_string ("Cantarell Small-Caps 11"); - pango_simple_layout_set_font_description (layout, desc); + pango_layout_set_font_description (layout, desc); - pango_simple_layout_set_text (layout, "Pere Ràfols Soler\nEqualiser, LV2\nAudio: 1, 1\nMidi: 0, 0\nControls: 53, 2\nCV: 0, 0", -1); + pango_layout_set_text (layout, "Pere Ràfols Soler\nEqualiser, LV2\nAudio: 1, 1\nMidi: 0, 0\nControls: 53, 2\nCV: 0, 0", -1); - pango_lines_get_extents (pango_simple_layout_get_lines (layout), NULL, &ext); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &ext); pango_font_description_free (desc); g_object_unref (layout); diff --git a/tests/testrandom.c b/tests/testrandom.c index 8c0ef83f..d2e1bd19 100644 --- a/tests/testrandom.c +++ b/tests/testrandom.c @@ -92,13 +92,13 @@ compare_size (gconstpointer a, } static void -layout_check_size (PangoSimpleLayout *layout, +layout_check_size (PangoLayout *layout, int width, Size *out_size) { out_size->set_width = width; - pango_simple_layout_set_width (layout, width); - pango_lines_get_size (pango_simple_layout_get_lines (layout), &out_size->width, &out_size->height); + pango_layout_set_width (layout, width); + pango_lines_get_size (pango_layout_get_lines (layout), &out_size->width, &out_size->height); } static void @@ -107,7 +107,7 @@ test_wrap_char (gconstpointer data) PangoDirection dir = GPOINTER_TO_UINT (data); PangoFontDescription *desc; PangoContext *context; - PangoSimpleLayout *layout; + PangoLayout *layout; char *sentence; Size min, max; Size sizes[100]; @@ -115,15 +115,15 @@ test_wrap_char (gconstpointer data) context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); desc = pango_font_description_from_string ("Sans 10"); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_font_description (layout, desc); + layout = pango_layout_new (context); + pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); - pango_simple_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); + pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); for (j = 0; j < N_SENTENCES; j++) { sentence = create_random_sentence (dir); - pango_simple_layout_set_text (layout, sentence, -1); + pango_layout_set_text (layout, sentence, -1); g_test_message ("%s", sentence); g_free (sentence); @@ -177,7 +177,7 @@ test_wrap_char_min_width (gconstpointer data) PangoDirection dir = GPOINTER_TO_UINT (data); PangoFontDescription *desc; PangoContext *context; - PangoSimpleLayout *test_layout, *ref_layout; + PangoLayout *test_layout, *ref_layout; char *sentence, *s; GString *ref_string; gsize j; @@ -185,18 +185,18 @@ test_wrap_char_min_width (gconstpointer data) context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); desc = pango_font_description_from_string ("Sans 10"); - ref_layout = pango_simple_layout_new (context); - pango_simple_layout_set_font_description (ref_layout, desc); - test_layout = pango_simple_layout_new (context); - pango_simple_layout_set_font_description (test_layout, desc); - pango_simple_layout_set_wrap (test_layout, PANGO_WRAP_WORD_CHAR); - pango_simple_layout_set_width (test_layout, 0); + ref_layout = pango_layout_new (context); + pango_layout_set_font_description (ref_layout, desc); + test_layout = pango_layout_new (context); + pango_layout_set_font_description (test_layout, desc); + pango_layout_set_wrap (test_layout, PANGO_WRAP_WORD_CHAR); + pango_layout_set_width (test_layout, 0); pango_font_description_free (desc); for (j = 0; j < N_SENTENCES; j++) { sentence = create_random_sentence (dir); - pango_simple_layout_set_text (test_layout, sentence, -1); + pango_layout_set_text (test_layout, sentence, -1); g_test_message ("%s", sentence); ref_string = g_string_new (""); for (s = sentence; *s; s = g_utf8_next_char (s)) @@ -205,12 +205,12 @@ test_wrap_char_min_width (gconstpointer data) g_string_append_unichar (ref_string, g_test_rand_bit () ? 0x2010 : '-'); g_string_append_c (ref_string, '\n'); } - pango_simple_layout_set_text (ref_layout, ref_string->str, ref_string->len); + pango_layout_set_text (ref_layout, ref_string->str, ref_string->len); g_string_free (ref_string, TRUE); g_free (sentence); - pango_lines_get_size (pango_simple_layout_get_lines (test_layout), &test_width, NULL); - pango_lines_get_size (pango_simple_layout_get_lines (ref_layout), &ref_width, NULL); + pango_lines_get_size (pango_layout_get_lines (test_layout), &test_width, NULL); + pango_lines_get_size (pango_layout_get_lines (ref_layout), &ref_width, NULL); g_assert_cmpint (test_width, <=, ref_width); } diff --git a/utils/pango-segmentation.c b/utils/pango-segmentation.c index d0971673..ac6071ad 100644 --- a/utils/pango-segmentation.c +++ b/utils/pango-segmentation.c @@ -68,7 +68,7 @@ show_segmentation (const char *input, int i; char *text; PangoAttrList *attributes; - PangoSimpleLayout *layout; + PangoLayout *layout; context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); @@ -80,11 +80,11 @@ show_segmentation (const char *input, pango_parse_markup (input, -1, 0, &attributes, &text, NULL, &error); g_assert_no_error (error); - layout = pango_simple_layout_new (context); - pango_simple_layout_set_text (layout, text, length); - pango_simple_layout_set_attributes (layout, attributes); + layout = pango_layout_new (context); + pango_layout_set_text (layout, text, length); + pango_layout_set_attributes (layout, attributes); - attrs = pango_simple_layout_get_log_attrs (layout, &len); + attrs = pango_layout_get_log_attrs (layout, &len); for (i = 0, p = text; i < len; i++, p = g_utf8_next_char (p)) { diff --git a/utils/viewer-pangocairo.c b/utils/viewer-pangocairo.c index 8fe9db59..c2f988fc 100644 --- a/utils/viewer-pangocairo.c +++ b/utils/viewer-pangocairo.c @@ -202,9 +202,9 @@ render_callback (PangoLayout *layout, cairo_pattern_t *pattern; PangoRectangle ink, logical; double lw = cairo_get_line_width (cr); - PangoLayoutIter* iter; + PangoLayoutIter *iter; - pango_layout_get_extents (layout, &ink, &logical); + pango_lines_get_extents (pango_layout_get_lines (layout), &ink, &logical); if (annotate & ANNOTATE_GRAVITY_ROOF) { @@ -285,12 +285,12 @@ render_callback (PangoLayout *layout, PangoLayoutLine *line = pango_layout_iter_get_line (iter); double width = (double)logical.width / PANGO_SCALE; - y = pango_layout_iter_get_baseline (iter); + y = pango_layout_iter_get_line_baseline (iter); cairo_save (cr); cairo_translate (cr, (double)logical.x / PANGO_SCALE + width * 0.5, (double)y / PANGO_SCALE); - if (line->resolved_dir) + if (pango_layout_line_get_resolved_direction (line)) cairo_scale (cr, -1, 1); cairo_move_to (cr, -width * .5, -lw*0.2); cairo_rel_line_to (cr, +width * .9, -lw*0.3); @@ -367,7 +367,7 @@ render_callback (PangoLayout *layout, iter = pango_layout_get_iter (layout); do { - PangoLayoutRun *run; + PangoGlyphItem *run; PangoRectangle rect; run = pango_layout_iter_get_run (iter); @@ -444,7 +444,7 @@ render_callback (PangoLayout *layout, iter = pango_layout_get_iter (layout); do { - PangoLayoutRun *run; + PangoGlyphItem *run; PangoRectangle rect; int x_pos, y_pos; @@ -502,19 +502,19 @@ render_callback (PangoLayout *layout, 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); + attrs = pango_layout_get_log_attrs (layout, &n_attrs); iter = pango_layout_get_iter (layout); do { PangoRectangle rect; - PangoLayoutRun *run; + PangoGlyphItem *run; const char *text, *start, *p; int x, y; gboolean trailing; pango_layout_iter_get_run_extents (iter, NULL, &rect); - run = pango_layout_iter_get_run_readonly (iter); + run = pango_layout_iter_get_run (iter); if (!run) continue; @@ -582,7 +582,7 @@ render_callback (PangoLayout *layout, cairo_save (cr); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); - attrs = pango_layout_get_log_attrs_readonly (layout, &n_attrs); + attrs = pango_layout_get_log_attrs (layout, &n_attrs); for (i = 0, p = text; i <= length; i++, p = g_utf8_next_char (p)) { @@ -591,7 +591,7 @@ render_callback (PangoLayout *layout, if (!attrs[i].is_cursor_position) continue; - pango_layout_get_caret_pos (layout, p - text, &rect, NULL); + pango_lines_get_caret_pos (pango_layout_get_lines (layout), NULL, p - text, &rect, NULL); cairo_move_to (cr, (double)rect.x / PANGO_SCALE + (double)rect.width / PANGO_SCALE - lw / 2, diff --git a/utils/viewer-render.c b/utils/viewer-render.c index 8816f06f..e85c0d6c 100644 --- a/utils/viewer-render.c +++ b/utils/viewer-render.c @@ -52,10 +52,7 @@ gboolean opt_waterfall = FALSE; int opt_width = -1; int opt_height = -1; int opt_indent = 0; -int opt_spacing = 0; double opt_line_spacing = -1.0; -gboolean opt_justify = 0; -gboolean opt_justify_last_line = 0; int opt_runs = 1; PangoAlignment opt_align = PANGO_ALIGN_LEFT; PangoEllipsizeMode opt_ellipsize = PANGO_ELLIPSIZE_NONE; @@ -131,9 +128,7 @@ make_layout(PangoContext *context, pango_layout_set_auto_dir (layout, opt_auto_dir); pango_layout_set_ellipsize (layout, opt_ellipsize); - pango_layout_set_justify (layout, opt_justify); - pango_layout_set_justify_last_line (layout, opt_justify_last_line); - pango_layout_set_single_paragraph_mode (layout, opt_single_par); + pango_layout_set_single_paragraph (layout, opt_single_par); pango_layout_set_wrap (layout, opt_wrap); font_description = pango_font_description_from_string (opt_font); @@ -166,14 +161,6 @@ make_layout(PangoContext *context, pango_layout_set_indent (layout, (opt_indent * opt_dpi * PANGO_SCALE + 36) / 72); } - if (opt_spacing != 0) - { - if (opt_pango_units) - pango_layout_set_spacing (layout, opt_spacing); - else - pango_layout_set_spacing (layout, (opt_spacing * opt_dpi * PANGO_SCALE + 36) / 72); - pango_layout_set_line_spacing (layout, 0.0); - } if (opt_line_spacing >= 0.0) pango_layout_set_line_spacing (layout, (float)opt_line_spacing); @@ -195,13 +182,8 @@ make_layout(PangoContext *context, out: if (opt_serialized_output) { - GError *error = NULL; - - if (!pango_layout_write_to_file (layout, - PANGO_LAYOUT_SERIALIZE_CONTEXT|PANGO_LAYOUT_SERIALIZE_OUTPUT, - opt_serialized_output, - &error)) - fail ("%s\n", error->message); + if (!pango_layout_write_to_file (layout, opt_serialized_output)) + fail ("Failed to serialize\n"); } return layout; @@ -278,7 +260,8 @@ output_body (PangoLayout *layout, pango_font_description_free (desc); } - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &logical_rect); + pango_extents_to_pixels (&logical_rect, NULL); if (render_cb) (*render_cb) (layout, x, y+*height, cb_context, cb_data); @@ -347,7 +330,7 @@ do_output (PangoContext *context, char *options_string = get_options_string (); pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH); layout = make_layout (context, options_string, 10); - pango_layout_get_extents (layout, NULL, &rect); + pango_lines_get_extents (pango_layout_get_lines (layout), NULL, &rect); width = MAX (width, PANGO_PIXELS (rect.width)); height += PANGO_PIXELS (rect.height); @@ -865,14 +848,8 @@ parse_options (int argc, char *argv[]) "Subpixel order", "rgb/bgr/vrgb/vbgr"}, {"indent", 0, 0, G_OPTION_ARG_INT, &opt_indent, "Width in points to indent paragraphs", "points"}, - {"spacing", 0, 0, G_OPTION_ARG_INT, &opt_spacing, - "Spacing in points between lines", "points"}, {"line-spacing", 0, 0, G_OPTION_ARG_DOUBLE, &opt_line_spacing, "Spread factor for line height", "factor"}, - {"justify", 0, 0, G_OPTION_ARG_NONE, &opt_justify, - "Stretch paragraph lines to be justified", NULL}, - {"justify-last-line", 0, 0, G_OPTION_ARG_NONE, &opt_justify_last_line, - "Justify the last line of the paragraph", NULL}, {"language", 0, 0, G_OPTION_ARG_STRING, &opt_language, "Language to use for font selection", "en_US/etc"}, {"margin", 0, 0, G_OPTION_ARG_CALLBACK, &parse_margin, @@ -893,8 +870,8 @@ parse_options (int argc, char *argv[]) "Angle at which to rotate results", "degrees"}, {"runs", 'n', 0, G_OPTION_ARG_INT, &opt_runs, "Run Pango layout engine this many times", "integer"}, - {"single-par", 0, 0, G_OPTION_ARG_NONE, &opt_single_par, - "Enable single-paragraph mode", NULL}, + {"single-par", 0, 0, G_OPTION_ARG_NONE, &opt_single_par, + "Enable single-paragraph mode", NULL}, {"text", 't', 0, G_OPTION_ARG_STRING, &opt_text, "Text to display (instead of a file)", "string"}, {"version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &show_version, |