diff options
-rw-r--r-- | pango/pango-break.h | 2 | ||||
-rw-r--r-- | pango/pango-item-private.h | 4 | ||||
-rw-r--r-- | pango/pango-item.c | 27 | ||||
-rw-r--r-- | pango/pango-layout.c | 65 | ||||
-rw-r--r-- | tests/layouts/valid-4.expected | 14 | ||||
-rw-r--r-- | tests/layouts/valid-4.markup | 2 | ||||
-rw-r--r-- | tests/testmisc.c | 26 | ||||
-rw-r--r-- | utils/viewer-render.c | 36 |
8 files changed, 151 insertions, 25 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 9e8ce248..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) @@ -3792,7 +3817,8 @@ find_break_extra_width (PangoLayout *layout, #if 0 # define DEBUG debug -void +static int pango_layout_line_get_width (PangoLayoutLine *line); +static void debug (const char *where, PangoLayoutLine *line, ParaBreakState *state) { int line_width = pango_layout_line_get_width (line); @@ -3919,10 +3945,10 @@ process_item (PangoLayout *layout, 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; - } + 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) && @@ -3931,11 +3957,7 @@ process_item (PangoLayout *layout, break_num_chars = num_chars; break_width = width; break_extra_width = extra_width; - - extra_width = find_break_extra_width (layout, state, num_chars); } - else - extra_width = 0; width += state->log_widths[state->log_widths_offset + num_chars]; } @@ -3946,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) { @@ -3993,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; @@ -4601,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/tests/layouts/valid-4.expected b/tests/layouts/valid-4.expected index f1c6934b..4e69d61d 100644 --- a/tests/layouts/valid-4.expected +++ b/tests/layouts/valid-4.expected @@ -5,7 +5,7 @@ This paragraph should actually have multiple lines, unlike all the other wan wrapped: 1 ellipsized: 0 lines: 6 -width: 192512 +width: 198656 --- attributes @@ -17,15 +17,15 @@ range 0 2147483647 --- cursor positions -0(0) 1(0) 2(0) 3(0) 4(0) 5(0) 6(0) 7(0) 8(0) 9(0) 10(0) 11(0) 12(0) 13(0) 14(0) 15(0) 16(0) 17(0) 18(0) 19(0) 20(0) 21(0) 22(0) 23(0) 24(0) 27(0) 28(0) 29(0) 30(0) 30(1) 33(0) 34(0) 35(0) 36(0) 37(0) 38(0) 39(0) 40(0) 41(0) 42(0) 43(0) 44(0) 45(0) 46(0) 47(0) 48(0) 49(0) 50(0) 51(0) 52(0) 53(0) 54(0) 55(0) 56(0) 57(0) 58(0) 59(0) 60(0) 61(0) 62(0) 62(1) 64(0) 65(0) 66(0) 67(0) 68(0) 69(0) 70(0) 71(0) 72(0) 73(0) 74(0) 75(0) 76(0) 77(0) 78(0) 79(0) 80(0) 81(0) 82(0) 83(0) 84(0) 85(0) 87(0) 89(0) 91(0) 92(0) 93(0) 94(0) 94(1) 97(0) 98(0) 101(0) 102(0) 103(0) 104(0) 105(0) 106(0) 107(0) 108(0) 109(0) 110(0) 111(0) 112(0) 113(0) 114(0) 115(0) 116(0) 117(0) 118(0) 119(0) 120(0) 121(0) 122(0) 123(0) 123(1) 125(0) 126(0) 127(0) 128(0) 129(0) 130(0) 131(0) 132(0) 133(0) 134(0) 135(0) 136(0) 137(0) 138(0) 139(0) 140(0) 141(0) 142(0) 143(0) 144(0) 145(0) 146(0) 147(0) 148(0) 149(0) 150(0) 150(1) 152(0) +0(0) 1(0) 2(0) 3(0) 4(0) 5(0) 6(0) 7(0) 8(0) 9(0) 10(0) 11(0) 12(0) 13(0) 14(0) 15(0) 16(0) 17(0) 18(0) 19(0) 20(0) 21(0) 22(0) 23(0) 24(0) 27(0) 28(0) 29(0) 30(0) 30(1) 33(0) 34(0) 35(0) 36(0) 37(0) 38(0) 39(0) 40(0) 41(0) 42(0) 43(0) 44(0) 45(0) 46(0) 47(0) 48(0) 49(0) 50(0) 51(0) 52(0) 53(0) 54(0) 55(0) 56(0) 57(0) 58(0) 59(0) 60(0) 61(0) 62(0) 62(1) 64(0) 65(0) 66(0) 67(0) 68(0) 69(0) 70(0) 71(0) 72(0) 73(0) 74(0) 75(0) 76(0) 77(0) 78(0) 79(0) 80(0) 81(0) 82(0) 83(0) 84(0) 85(0) 87(0) 89(0) 91(0) 92(0) 93(0) 94(0) 94(1) 97(0) 98(0) 101(0) 102(0) 103(0) 104(0) 105(0) 106(0) 107(0) 108(0) 109(0) 110(0) 111(0) 112(0) 113(0) 114(0) 115(0) 116(0) 117(0) 118(0) 119(0) 120(0) 121(0) 122(0) 123(0) 124(0) 125(0) 126(0) 127(0) 128(0) 128(1) 130(0) 131(0) 132(0) 133(0) 134(0) 135(0) 136(0) 137(0) 138(0) 139(0) 140(0) 141(0) 142(0) 143(0) 144(0) 145(0) 146(0) 147(0) 148(0) 149(0) 150(0) 150(1) 152(0) --- lines i=1, index=0, paragraph-start=1, dir=ltr 'This paragraph should actual' i=2, index=32, paragraph-start=0, dir=ltr 'ly have multiple lines, unlike ' i=3, index=63, paragraph-start=0, dir=ltr 'all the other wannabe äöü pa' -i=4, index=96, paragraph-start=0, dir=ltr 'ragraph tests in this ugh ' -i=5, index=124, paragraph-start=0, dir=ltr 'test-case. Grow some lines! +i=4, index=96, paragraph-start=0, dir=ltr 'ragraph tests in this ugh test-' +i=5, index=129, paragraph-start=0, dir=ltr 'case. Grow some lines! ' i=6, index=152, paragraph-start=1, dir=ltr '' @@ -37,8 +37,8 @@ i=3, index=32, chars=31, level=0, gravity=south, flags=0, font=OMITTED, script=l i=4, index=63, no run, line end i=5, index=63, chars=29, level=0, gravity=south, flags=4, font=OMITTED, script=latin, language=en-us, 'all the other wannabe äöü pa' i=6, index=96, no run, line end -i=7, index=96, chars=27, level=0, gravity=south, flags=0, font=OMITTED, script=latin, language=en-us, 'ragraph tests in this ugh ' -i=8, index=124, no run, line end -i=9, index=124, chars=27, level=0, gravity=south, flags=0, font=OMITTED, script=latin, language=en-us, 'test-case. Grow some lines!' +i=7, index=96, chars=32, level=0, gravity=south, flags=0, font=OMITTED, script=latin, language=en-us, 'ragraph tests in this ugh test-' +i=8, index=129, no run, line end +i=9, index=129, chars=22, level=0, gravity=south, flags=0, font=OMITTED, script=latin, language=en-us, 'case. Grow some lines!' i=10, index=151, no run, line end i=11, index=152, no run, line end diff --git a/tests/layouts/valid-4.markup b/tests/layouts/valid-4.markup index 0b2bb51a..d8890baf 100644 --- a/tests/layouts/valid-4.markup +++ b/tests/layouts/valid-4.markup @@ -1,2 +1,2 @@ -width=188 +width=194 This paragraph should actually have multiple lines, unlike all the other wannabe äöü paragraph tests in this ugh test-case. Grow some lines! diff --git a/tests/testmisc.c b/tests/testmisc.c index 355e8ed0..a91dcbb3 100644 --- a/tests/testmisc.c +++ b/tests/testmisc.c @@ -754,6 +754,31 @@ test_transform_rectangle (void) g_assert_cmpint (rect2.height, ==, rect.width); } +static void +test_wrap_char (void) +{ + PangoContext *context; + PangoLayout *layout; + int w, h, w0, h0; + + context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "Rows can have suffix widgets", -1); + pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); + + pango_layout_set_width (layout, 0); + pango_layout_get_size (layout, &w0, &h0); + + pango_layout_set_width (layout, w0); + pango_layout_get_size (layout, &w, &h); + + g_assert_cmpint (w0, ==, w); + g_assert_cmpint (h0, >=, h); + + g_object_unref (layout); + g_object_unref (context); +} + int main (int argc, char *argv[]) { @@ -786,6 +811,7 @@ main (int argc, char *argv[]) g_test_add_func ("/layout/extents", test_extents); g_test_add_func ("/layout/empty-line-height", test_empty_line_height); g_test_add_func ("/layout/gravity-metrics", test_gravity_metrics); + g_test_add_func ("/layout/wrap-char", test_wrap_char); g_test_add_func ("/matrix/transform-rectangle", test_transform_rectangle); return g_test_run (); 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, |