summaryrefslogtreecommitdiff
path: root/pango/pango-layout.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-11-11 19:58:21 -0500
committerMatthias Clasen <mclasen@redhat.com>2021-11-11 20:23:47 -0500
commit401237f4f19690771b5383a08dd71a638f77b2a0 (patch)
treeb39cd51dd5ac0892348f9c014587d5d7d45bf279 /pango/pango-layout.c
parent0c80c6d0b80cce4443e9a18fad2b4bccabaf4325 (diff)
downloadpango-401237f4f19690771b5383a08dd71a638f77b2a0.tar.gz
Try harder to not produce overlong linesavoid-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.
Diffstat (limited to 'pango/pango-layout.c')
-rw-r--r--pango/pango-layout.c48
1 files changed, 48 insertions, 0 deletions
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);