diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-11-15 15:37:44 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-11-15 15:37:44 +0000 |
commit | 9f82d3e4a6d4a628f306301fa8461810ba0446f6 (patch) | |
tree | e76f1c625774d3ef358166de891fd165f4376e43 /pango/pango-layout.c | |
parent | 82599ca5ee42291ec824a1865c454e8dbc38ec80 (diff) | |
parent | eab03caa361fd821c3b569ee9773fa26817d5522 (diff) | |
download | pango-9f82d3e4a6d4a628f306301fa8461810ba0446f6.tar.gz |
Merge branch 'line-breaking-fixes3' into 'main'
More line breaking fixes
See merge request GNOME/pango!507
Diffstat (limited to 'pango/pango-layout.c')
-rw-r--r-- | pango/pango-layout.c | 104 |
1 files changed, 72 insertions, 32 deletions
diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 5cdaa531..471cbb64 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3872,16 +3872,27 @@ process_item (PangoLayout *layout, if ((width <= state->remaining_width || (item->num_chars == 1 && !line->runs)) && !no_break_at_end) { - state->remaining_width -= width; - state->remaining_width = MAX (state->remaining_width, 0); - insert_run (line, state, item, TRUE); + insert_run (line, state, item, FALSE); + width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs); - return BREAK_ALL_FIT; + if (width <= state->remaining_width || (item->num_chars == 1 && !line->runs)) + { + state->remaining_width -= width; + state->remaining_width = MAX (state->remaining_width, 0); + + pango_glyph_string_free (state->glyphs); + state->glyphs = NULL; + + return BREAK_ALL_FIT; + } + + /* if it doesn't fit after shaping, revert and proceed to break the item */ + uninsert_run (line); } - else + { - int num_chars = item->num_chars; - int break_num_chars = num_chars; + int num_chars; + int break_num_chars = item->num_chars; int break_width = width; int orig_width = width; int break_extra_width = 0; @@ -3918,33 +3929,62 @@ process_item (PangoLayout *layout, /* 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); + insert_run (line, state, item, FALSE); + width = pango_glyph_string_get_width (((PangoGlyphItem *)(line->runs->data))->glyphs); - return BREAK_ALL_FIT; + if (width + break_extra_width <= state->remaining_width) + { + state->remaining_width -= width + break_extra_width; + state->remaining_width = MAX (state->remaining_width, 0); + + pango_glyph_string_free (state->glyphs); + state->glyphs = NULL; + + return BREAK_ALL_FIT; + } + + uninsert_run (line); } } /* 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++) { extra_width = find_break_extra_width (layout, state, num_chars); - if (width + extra_width > state->remaining_width && break_num_chars < item->num_chars) - break; + /* 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 && + break_num_chars < item->num_chars && + (break_width + break_extra_width <= state->remaining_width || + MIN (width + extra_width, width) > break_width + break_extra_width)) + { + break; + } /* If there are no previous runs we have to take care to grab at least one char. */ 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; - break_width = width; - break_extra_width = extra_width; + /* If we had a breakpoint already, we only want to replace it with a better one. */ + if (width + extra_width <= state->remaining_width || + width + extra_width < break_width + break_extra_width || + (width + extra_width == break_width + break_extra_width && + num_chars > break_num_chars)) + { + break_num_chars = num_chars; + break_width = width; + break_extra_width = extra_width; + } } width += state->log_widths[state->log_widths_offset + num_chars]; @@ -3953,9 +3993,8 @@ process_item (PangoLayout *layout, 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; - num_chars = item->num_chars; + break_num_chars = item->num_chars; width = orig_width; - break_num_chars = num_chars; break_width = width; goto retry_break; } @@ -3992,6 +4031,8 @@ process_item (PangoLayout *layout, if (break_needs_hyphen (layout, state, break_num_chars)) new_item->analysis.flags |= PANGO_ANALYSIS_FLAG_NEED_HYPHEN; + else + new_item->analysis.flags &= ~PANGO_ANALYSIS_FLAG_NEED_HYPHEN; /* Add the width back, to the line, reshape, subtract the new width */ state->remaining_width = remaining; @@ -3999,27 +4040,26 @@ process_item (PangoLayout *layout, 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]; + /* After the shaping, break_width includes a possible hyphen. + * We subtract break_extra_width to account for that. + */ + if (new_item->analysis.flags & PANGO_ANALYSIS_FLAG_NEED_HYPHEN) + break_width -= break_extra_width; - if (break_width > state->remaining_width && - !break_disabled[break_num_chars] && - break_num_chars > 1) + if (break_width + break_extra_width > state->remaining_width && + !break_disabled[break_num_chars]) { - /* Unsplit the item, disable the breakpoint, try again */ - + /* Unsplit the item, disable the breakpoint, try find a better one. + * + * If we can't find a different breakpoint that works better, we'll + * end up here again, with break_disabled being set, and take the break + */ uninsert_run (line); pango_item_free (new_item); pango_item_unsplit (item, length, break_num_chars); break_disabled[break_num_chars] = TRUE; - num_chars = item->num_chars; - width = orig_width; - break_num_chars = num_chars; - break_width = width; - goto retry_break; } |