From 430f105d81ff4ba8e7dce73910c77459cfcb5b3f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Nov 2021 19:52:50 -0500 Subject: Cosmetics --- pango/pango-layout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 1a460d4c..7731532c 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3943,9 +3943,9 @@ process_item (PangoLayout *layout, * the cluster here. But should be fine in practice. */ if (break_num_chars > 0 && break_num_chars < item->num_chars && layout->log_attrs[state->start_offset + break_num_chars - 1].is_white) - { + { break_width -= state->log_widths[state->log_widths_offset + break_num_chars - 1]; - } + } if (layout->wrap == PANGO_WRAP_WORD_CHAR && force_fit && break_width + break_extra_width > state->remaining_width && !retrying_with_char_breaks) { -- cgit v1.2.1 From 7b688167a30fe9861bd896c8ab317483daf8286b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 10 Nov 2021 22:25:23 -0500 Subject: pango-view: Add --pango-units This can make it easier to reproduce problems. --- utils/viewer-render.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/utils/viewer-render.c b/utils/viewer-render.c index 6f7e96c5..ab0da2dd 100644 --- a/utils/viewer-render.c +++ b/utils/viewer-render.c @@ -35,6 +35,7 @@ gboolean opt_display = TRUE; int opt_dpi = 96; gboolean opt_pixels = FALSE; +gboolean opt_pango_units = FALSE; const char *opt_font = ""; gboolean opt_header = FALSE; const char *opt_output = NULL; @@ -120,19 +121,37 @@ make_layout(PangoContext *context, pango_font_description_set_size (font_description, size * PANGO_SCALE); if (opt_width > 0) - pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 36) / 72); + { + if (opt_pango_units) + pango_layout_set_width (layout, opt_width); + else + pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 36) / 72); + } if (opt_height > 0) - pango_layout_set_height (layout, (opt_height * opt_dpi * PANGO_SCALE + 36) / 72); + { + if (opt_pango_units) + pango_layout_set_width (layout, opt_height); + else + pango_layout_set_height (layout, (opt_height * opt_dpi * PANGO_SCALE + 36) / 72); + } else pango_layout_set_height (layout, opt_height); if (opt_indent != 0) - pango_layout_set_indent (layout, (opt_indent * opt_dpi * PANGO_SCALE + 36) / 72); + { + if (opt_pango_units) + pango_layout_set_indent (layout, opt_indent); + else + pango_layout_set_indent (layout, (opt_indent * opt_dpi * PANGO_SCALE + 36) / 72); + } if (opt_spacing != 0) { - pango_layout_set_spacing (layout, (opt_spacing * opt_dpi * PANGO_SCALE + 36) / 72); + 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) @@ -360,6 +379,9 @@ do_output (PangoContext *context, pango_context_set_matrix (context, orig_matrix); pango_matrix_free (orig_matrix); + int w, h; + pango_layout_get_size (layout, &w, &h); + g_print ("layout %d %d\n", w, h); g_object_unref (layout); } @@ -829,6 +851,8 @@ parse_options (int argc, char *argv[]) "Deprecated", "file"}, {"pixels", 0, 0, G_OPTION_ARG_NONE, &opt_pixels, "Use pixel units instead of points (sets dpi to 72)", NULL}, + {"pango-units", 0, 0, G_OPTION_ARG_NONE, &opt_pango_units, + "Use Pango units instead of points", NULL}, {"rtl", 0, 0, G_OPTION_ARG_NONE, &opt_rtl, "Set base direction to right-to-left", NULL}, {"rotate", 0, 0, G_OPTION_ARG_DOUBLE, &opt_rotate, -- cgit v1.2.1 From 6082a2eab8b8368cd167f8cc61c0df84d28a98ba Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Nov 2021 20:13:17 -0500 Subject: pango-view: Accept width 0 GTK frequently uses this width during measuring, so it is good if we can reproduce what happens in this case. --- utils/viewer-render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/viewer-render.c b/utils/viewer-render.c index ab0da2dd..d4b3f0f4 100644 --- a/utils/viewer-render.c +++ b/utils/viewer-render.c @@ -120,7 +120,7 @@ make_layout(PangoContext *context, if (size > 0) pango_font_description_set_size (font_description, size * PANGO_SCALE); - if (opt_width > 0) + if (opt_width >= 0) { if (opt_pango_units) pango_layout_set_width (layout, opt_width); @@ -128,7 +128,7 @@ make_layout(PangoContext *context, pango_layout_set_width (layout, (opt_width * opt_dpi * PANGO_SCALE + 36) / 72); } - if (opt_height > 0) + if (opt_height >= 0) { if (opt_pango_units) pango_layout_set_width (layout, opt_height); -- cgit v1.2.1 From 399a4b9ba16e32edce848339f6a77389b93b09bc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Nov 2021 19:47:33 -0500 Subject: Reserve the remaining bits in PangoLogAttr This will let us use some of them during layout. --- pango/pango-break.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pango/pango-break.h b/pango/pango-break.h index 5d791e27..797fefd1 100644 --- a/pango/pango-break.h +++ b/pango/pango-break.h @@ -97,6 +97,8 @@ struct _PangoLogAttr guint is_word_boundary : 1; guint break_inserts_hyphen : 1; guint break_removes_preceding : 1; + + guint reserved : 17; }; PANGO_DEPRECATED_IN_1_44 -- cgit v1.2.1 From 0c80c6d0b80cce4443e9a18fad2b4bccabaf4325 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Nov 2021 19:48:19 -0500 Subject: Add pango_item_unsplit This undoes the effect of pango_item_split. We will use this in future commits. Private for now. --- pango/pango-item-private.h | 4 ++++ pango/pango-item.c | 27 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pango/pango-item-private.h b/pango/pango-item-private.h index ef3e8ed0..d37fc3f8 100644 --- a/pango/pango-item-private.h +++ b/pango/pango-item-private.h @@ -88,6 +88,10 @@ GList * pango_itemize_post_process_items (PangoContext PangoLogAttr *log_attrs, GList *items); +void pango_item_unsplit (PangoItem *orig, + int split_index, + int split_offset); + G_END_DECLS diff --git a/pango/pango-item.c b/pango/pango-item.c index 4b02c277..2b2664c5 100644 --- a/pango/pango-item.c +++ b/pango/pango-item.c @@ -138,7 +138,7 @@ G_DEFINE_BOXED_TYPE (PangoItem, pango_item, * Return value: new item representing text before @split_index, which * should be freed with [method@Pango.Item.free]. */ -PangoItem* +PangoItem * pango_item_split (PangoItem *orig, int split_index, int split_offset) @@ -164,6 +164,31 @@ pango_item_split (PangoItem *orig, return new_item; } +/*< private > + * pango_item_unsplit: + * @orig: the item to unsplit + * @split_index: value passed to pango_item_split() + * @split_offset: value passed to pango_item_split() + * + * Undoes the effect of a pango_item_split() call with + * the same arguments. + * + * You are expected to free the new item that was returned + * by pango_item_split() yourself. + */ +void +pango_item_unsplit (PangoItem *orig, + int split_index, + int split_offset) +{ + orig->offset -= split_index; + orig->length += split_index; + orig->num_chars += split_offset; + + if (orig->analysis.flags & PANGO_ANALYSIS_FLAG_HAS_CHAR_OFFSET) + ((PangoItemPrivate *)orig)->char_offset -= split_offset; +} + static int compare_attr (gconstpointer p1, gconstpointer p2) { -- cgit v1.2.1 From 401237f4f19690771b5383a08dd71a638f77b2a0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 11 Nov 2021 19:58:21 -0500 Subject: Try harder to not produce overlong lines Our accounting for run lengths is imperfect (mainly due to log widths for clusters being evenly distributed), so it can happen that after reshaping the split item, we find that it does not actually fit in the remaining width. Previously, we would just use the split run at that point and produce an overlong line. Instead, undo the split, disable the breakpoint we used, and try again. --- pango/pango-layout.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 7731532c..fad92b3b 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3525,6 +3525,29 @@ shape_tab (PangoLayoutLine *line, } } +#define DISABLE_BREAKPOINT_FLAG (1 << 16) + +static inline void +disable_breakpoint (PangoLayout *layout, + int offset) +{ + layout->log_attrs[offset].reserved |= DISABLE_BREAKPOINT_FLAG; +} + +static inline gboolean +breakpoint_is_disabled (PangoLayout *layout, + int offset) +{ + return (layout->log_attrs[offset].reserved & DISABLE_BREAKPOINT_FLAG) != 0; +} + +static void +clear_breakpoint_flags (PangoLayout *layout) +{ + for (int i = 0; i < layout->n_chars + 1; i++) + layout->log_attrs[i].reserved = 0; +} + static inline gboolean can_break_at (PangoLayout *layout, gint offset, @@ -3542,6 +3565,8 @@ can_break_at (PangoLayout *layout, if (offset == layout->n_chars) return TRUE; + else if (breakpoint_is_disabled (layout, offset)) + return FALSE; else if (wrap == PANGO_WRAP_WORD) return layout->log_attrs[offset].is_line_break; else if (wrap == PANGO_WRAP_CHAR) @@ -3990,7 +4015,28 @@ process_item (PangoLayout *layout, /* Add the width back, to the line, reshape, subtract the new width */ state->remaining_width += break_width; insert_run (line, state, new_item, FALSE); + break_width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs); + if (break_width > state->remaining_width && + !breakpoint_is_disabled (layout, break_num_chars) && + break_num_chars > 1) + { + /* Unsplit the item, disable the breakpoint, try again */ + + uninsert_run (line); + pango_item_free (new_item); + pango_item_unsplit (item, length, break_num_chars); + + disable_breakpoint (layout, break_num_chars); + + num_chars = item->num_chars; + width = orig_width; + break_num_chars = num_chars; + break_width = width; + + goto retry_break; + } + state->remaining_width -= break_width; state->log_widths_offset += break_num_chars; @@ -4598,6 +4644,8 @@ pango_layout_check_lines (PangoLayout *layout) } while (!done); + clear_breakpoint_flags (layout); + g_free (state.log_widths); g_list_free_full (state.baseline_shifts, g_free); -- cgit v1.2.1