From e2a297b31f440c75675680ae5cc8e611718ed0e0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 11:37:00 -0500 Subject: Simplify breakpoint disabling We only want this inside process_item, so we can make this a purely local thing, without modifying log_attrs. --- pango/pango-layout.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index bf096739..bf7c5fc5 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3525,29 +3525,6 @@ 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, @@ -3565,8 +3542,6 @@ 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) @@ -3926,6 +3901,7 @@ process_item (PangoLayout *layout, int orig_width = width; int break_extra_width = 0; gboolean retrying_with_char_breaks = FALSE; + gboolean *break_disabled; if (processing_new_item) { @@ -3938,6 +3914,9 @@ process_item (PangoLayout *layout, pango_glyph_item_get_logical_widths (&glyph_item, layout->text, state->log_widths); } + break_disabled = g_alloca (sizeof (gboolean) * (item->num_chars + 1)); + memset (break_disabled, 0, sizeof (gboolean) * (item->num_chars + 1)); + retry_break: /* See how much of the item we can stuff in the line. */ @@ -3951,7 +3930,8 @@ process_item (PangoLayout *layout, 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, retrying_with_char_breaks) && + if (!break_disabled[num_chars] && + can_break_at (layout, state->start_offset + num_chars, retrying_with_char_breaks) && (num_chars > 0 || line->runs)) { break_num_chars = num_chars; @@ -4013,13 +3993,14 @@ process_item (PangoLayout *layout, if (break_needs_hyphen (layout, state, break_num_chars)) new_item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; + /* 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_disabled[break_num_chars] && break_num_chars > 1) { /* Unsplit the item, disable the breakpoint, try again */ @@ -4028,7 +4009,7 @@ process_item (PangoLayout *layout, pango_item_free (new_item); pango_item_unsplit (item, length, break_num_chars); - disable_breakpoint (layout, break_num_chars); + break_disabled[break_num_chars] = TRUE; num_chars = item->num_chars; width = orig_width; @@ -4645,8 +4626,6 @@ 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 From a4fb00b9d290cec81b51ba38bd3bbc7f5ae62b93 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 13:52:15 -0500 Subject: Simplify find_break_extra_width We can use the log_widths that we already have. --- pango/pango-layout.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index bf7c5fc5..ebc9ce67 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3737,23 +3737,6 @@ find_hyphen_width (PangoItem *item) return 0; } -static int -find_char_width (PangoItem *item, - gunichar wc) -{ - hb_font_t *hb_font; - hb_codepoint_t glyph; - - if (!item->analysis.font) - return 0; - - hb_font = pango_font_get_hb_font (item->analysis.font); - if (hb_font_get_nominal_glyph (hb_font, wc, &glyph)) - return hb_font_get_glyph_h_advance (hb_font, glyph); - - return 0; -} - static inline void ensure_hyphen_width (ParaBreakState *state) { @@ -3775,14 +3758,7 @@ find_break_extra_width (PangoLayout *layout, ensure_hyphen_width (state); if (layout->log_attrs[state->start_offset + pos].break_removes_preceding) - { - PangoItem *item = state->items->data; - gunichar wc; - - wc = g_utf8_get_char (g_utf8_offset_to_pointer (layout->text, state->start_offset + pos - 1)); - - return state->hyphen_width - find_char_width (item, wc); - } + return state->hyphen_width - state->log_widths[state->log_widths_offset + pos - 1]; else return state->hyphen_width; } -- cgit v1.2.1 From e439198c96c34f23bb38d07493b572776f118e01 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 13:56:28 -0500 Subject: Correctly reinstate remaining_width When unsplitting an item, we were sometimes calculating the remaining_width incorrectly. --- pango/pango-layout.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index ebc9ce67..821f767c 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3941,6 +3941,8 @@ process_item (PangoLayout *layout, if (force_fit || break_width + break_extra_width <= state->remaining_width) /* Successfully broke the item */ { + int remaining = state->remaining_width; + if (state->remaining_width >= 0) { state->remaining_width -= break_width; @@ -3971,7 +3973,7 @@ process_item (PangoLayout *layout, new_item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; /* Add the width back, to the line, reshape, subtract the new width */ - state->remaining_width += break_width; + state->remaining_width = remaining; insert_run (line, state, new_item, FALSE); break_width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs); -- cgit v1.2.1 From 86303ad26445ce7f7490f7e7a6690c611d83ea5e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 13:55:22 -0500 Subject: Handle break-after-space correctly When we are breaking after a space, we must not count the width of the space towards the line, since we are zeroing it later. It is a bit annoying that there are multiple places where this has to be taken into account. Another missing bit in this code is that we are only looking at a single whitespace character before the break, when we should really look for a sequence of spaces. --- pango/pango-layout.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 821f767c..b605ded5 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3752,7 +3752,11 @@ find_break_extra_width (PangoLayout *layout, ParaBreakState *state, int pos) { - /* Check whether to insert a hyphen */ + /* 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); @@ -3762,6 +3766,11 @@ find_break_extra_width (PangoLayout *layout, else return state->hyphen_width; } + else if (state->start_offset + pos > 0 && + layout->log_attrs[state->start_offset + pos - 1].is_white) + { + return - state->log_widths[state->log_widths_offset + pos - 1]; + } return 0; } @@ -3977,6 +3986,11 @@ process_item (PangoLayout *layout, insert_run (line, state, new_item, FALSE); break_width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs); + + if (state->start_offset + break_num_chars > 0 && + 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 (break_width > state->remaining_width && !break_disabled[break_num_chars] && break_num_chars > 1) -- cgit v1.2.1 From c435091fad16e00129aef2e15f64c9c8bd768102 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 17:21:44 -0500 Subject: Fix up one more case of break-after-space If the break is at the end of the item, we were forgetting to check for the space before the break. --- pango/pango-layout.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index b605ded5..ad16e918 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3907,6 +3907,17 @@ process_item (PangoLayout *layout, /* See how much of the item we can stuff in the line. */ width = 0; extra_width = 0; + + /* break_extra_width gets normally set from find_break_extra_width inside + * the loop, and that takes a space before the break into account. The + * one case that is not covered by that is if we end up going all the way + * through the loop without ever entering the can_break_at case, and come + * out at the other end with the break_extra_width value untouched. So + * initialize it here, taking space-before-break into account. + */ + if (layout->log_attrs[state->start_offset + break_num_chars - 1].is_white) + break_extra_width = - state->log_widths[state->log_widths_offset + break_num_chars - 1]; + for (num_chars = 0; num_chars < item->num_chars; num_chars++) { extra_width = find_break_extra_width (layout, state, num_chars); @@ -3927,17 +3938,6 @@ process_item (PangoLayout *layout, width += state->log_widths[state->log_widths_offset + num_chars]; } - /* If there's a space at the end of the line, include that also. - * The logic here should match zero_line_final_space(). - * XXX Currently it doesn't quite match the logic there. We don't check - * 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) { retrying_with_char_breaks = TRUE; -- cgit v1.2.1 From d98a4c78c5a57e2dd2d888f489971d8221e4d104 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 18:05:17 -0500 Subject: Fix another corner case of space-handling This keeps spiraling :( --- pango/pango-layout.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index ad16e918..c94617aa 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3904,10 +3904,6 @@ process_item (PangoLayout *layout, retry_break: - /* See how much of the item we can stuff in the line. */ - width = 0; - extra_width = 0; - /* break_extra_width gets normally set from find_break_extra_width inside * the loop, and that takes a space before the break into account. The * one case that is not covered by that is if we end up going all the way @@ -3916,7 +3912,23 @@ process_item (PangoLayout *layout, * initialize it here, taking space-before-break into account. */ if (layout->log_attrs[state->start_offset + break_num_chars - 1].is_white) - break_extra_width = - state->log_widths[state->log_widths_offset + break_num_chars - 1]; + { + break_extra_width = - state->log_widths[state->log_widths_offset + break_num_chars - 1]; + + /* check one more time if the whole item fits after removing the space */ + if (width + break_extra_width <= state->remaining_width && !no_break_at_end) + { + state->remaining_width -= width + break_extra_width; + state->remaining_width = MAX (state->remaining_width, 0); + insert_run (line, state, item, TRUE); + + return BREAK_ALL_FIT; + } + } + + /* See how much of the item we can stuff in the line. */ + width = 0; + extra_width = 0; for (num_chars = 0; num_chars < item->num_chars; num_chars++) { -- cgit v1.2.1 From 9b95dc725c3ebbed22edbe035c9ac0d610c64a30 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 12 Nov 2021 18:31:09 -0500 Subject: Fix a thinko --- pango/pango-layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pango/pango-layout.c b/pango/pango-layout.c index c94617aa..5cdaa531 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3766,7 +3766,7 @@ find_break_extra_width (PangoLayout *layout, else return state->hyphen_width; } - else if (state->start_offset + pos > 0 && + else if (pos > 0 && layout->log_attrs[state->start_offset + pos - 1].is_white) { return - state->log_widths[state->log_widths_offset + pos - 1]; -- cgit v1.2.1