summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-11-12 01:31:05 +0000
committerMatthias Clasen <mclasen@redhat.com>2021-11-12 01:31:05 +0000
commitae15885600be2e3ac3fe48aff821881a0feb018b (patch)
treeb39cd51dd5ac0892348f9c014587d5d7d45bf279
parent907b6e21fcb846995cc5b03d2cb1b68fbbc2a2b5 (diff)
parent401237f4f19690771b5383a08dd71a638f77b2a0 (diff)
downloadpango-ae15885600be2e3ac3fe48aff821881a0feb018b.tar.gz
Merge branch 'avoid-overlong-lines' into 'main'
layout: Try harder to not produce overlong lines See merge request GNOME/pango!501
-rw-r--r--pango/pango-break.h2
-rw-r--r--pango/pango-item-private.h4
-rw-r--r--pango/pango-item.c27
-rw-r--r--pango/pango-layout.c52
-rw-r--r--utils/viewer-render.c36
5 files changed, 112 insertions, 9 deletions
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
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)
{
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 1a460d4c..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)
@@ -3943,9 +3968,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)
{
@@ -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);
diff --git a/utils/viewer-render.c b/utils/viewer-render.c
index 6f7e96c5..d4b3f0f4 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;
@@ -119,20 +120,38 @@ make_layout(PangoContext *context,
if (size > 0)
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_width >= 0)
+ {
+ 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_height >= 0)
+ {
+ 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,