diff options
-rw-r--r-- | pango/ellipsize.c | 7 | ||||
-rw-r--r-- | pango/pango-context.c | 8 | ||||
-rw-r--r-- | pango/pango-layout.c | 15 | ||||
-rw-r--r-- | pango/pangocoretext-fontmap.c | 3 | ||||
-rw-r--r-- | pango/pangofc-fontmap.c | 3 | ||||
-rw-r--r-- | pango/pangowin32-fontmap.c | 3 | ||||
-rw-r--r-- | tests/testmisc.c | 21 | ||||
-rw-r--r-- | utils/meson.build | 7 | ||||
-rw-r--r-- | utils/pango-segmentation.c | 182 |
9 files changed, 236 insertions, 13 deletions
diff --git a/pango/ellipsize.c b/pango/ellipsize.c index 4eb98a1a..0d54483e 100644 --- a/pango/ellipsize.c +++ b/pango/ellipsize.c @@ -634,7 +634,8 @@ remove_one_span (EllipsizeState *state) * of the gap */ static void -fixup_ellipsis_run (EllipsizeState *state) +fixup_ellipsis_run (EllipsizeState *state, + int extra_width) { PangoGlyphString *glyphs = state->ellipsis_run->glyphs; PangoItem *item = state->ellipsis_run->item; @@ -650,6 +651,8 @@ fixup_ellipsis_run (EllipsizeState *state) glyphs->glyphs[0].attr.is_cluster_start = TRUE; + glyphs->glyphs[glyphs->num_glyphs - 1].geometry.width += extra_width; + /* Fix up the item to point to the entire elided text */ item->offset = state->gap_start_iter.run_iter.start_index; item->length = state->gap_end_iter.run_iter.end_index - item->offset; @@ -765,7 +768,7 @@ _pango_layout_line_ellipsize (PangoLayoutLine *line, break; } - fixup_ellipsis_run (&state); + fixup_ellipsis_run (&state, MAX (goal_width - current_width (&state), 0)); g_slist_free (line->runs); line->runs = get_run_list (&state); diff --git a/pango/pango-context.c b/pango/pango-context.c index 90952add..d1e447f7 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -1413,10 +1413,10 @@ itemize_state_update_for_new_run (ItemizeState *state) { gboolean is_emoji = state->emoji_iter.is_emoji; if (is_emoji && !state->emoji_font_desc) - { - state->emoji_font_desc = pango_font_description_copy_static (state->font_desc); - pango_font_description_set_family_static (state->emoji_font_desc, "emoji"); - } + { + state->emoji_font_desc = pango_font_description_copy_static (state->font_desc); + pango_font_description_set_family_static (state->emoji_font_desc, "emoji"); + } state->current_fonts = pango_font_map_load_fontset (state->context->font_map, state->context, is_emoji ? state->emoji_font_desc : state->font_desc, diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 57ec7606..2fe6c9dc 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -4982,7 +4982,7 @@ pango_layout_run_get_extents_and_height (PangoLayoutRun *run, gboolean has_underline; gboolean has_overline; - if (G_UNLIKELY (!run_ink && !run_logical)) + if (G_UNLIKELY (!run_ink && !run_logical && !height)) return; pango_layout_get_item_properties (run->item, &properties); @@ -5107,7 +5107,7 @@ pango_layout_line_get_extents_and_height (PangoLayoutLine *line, g_return_if_fail (LINE_IS_VALID (line)); - if (G_UNLIKELY (!ink_rect && !logical_rect)) + if (G_UNLIKELY (!ink_rect && !logical_rect && !height)) return; switch (private->cache_status) @@ -5213,8 +5213,15 @@ pango_layout_line_get_extents_and_height (PangoLayoutLine *line, tmp_list = tmp_list->next; } - if (logical_rect && !line->runs) - pango_layout_line_get_empty_extents (line, logical_rect); + if (!line->runs) + { + PangoRectangle r, *rect; + + rect = logical_rect ? logical_rect : &r; + pango_layout_line_get_empty_extents (line, rect); + if (height) + *height = rect->height; + } if (caching) { diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c index 09437b4a..81bf7bf7 100644 --- a/pango/pangocoretext-fontmap.c +++ b/pango/pangocoretext-fontmap.c @@ -529,7 +529,8 @@ pango_core_text_face_list_sizes (PangoFontFace *face, int *n_sizes) { *n_sizes = 0; - *sizes = NULL; + if (sizes) + *sizes = NULL; } G_DEFINE_TYPE (PangoCoreTextFace, pango_core_text_face, PANGO_TYPE_FONT_FACE); diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index 7966a8cd..f74b2c15 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -2904,7 +2904,8 @@ pango_fc_face_list_sizes (PangoFontFace *face, FcObjectSet *objectset; FcFontSet *fonts; - *sizes = NULL; + if (sizes) + *sizes = NULL; *n_sizes = 0; if (G_UNLIKELY (!fcface->family || !fcface->family->fontmap)) return; diff --git a/pango/pangowin32-fontmap.c b/pango/pangowin32-fontmap.c index e5e81bba..18d4544e 100644 --- a/pango/pangowin32-fontmap.c +++ b/pango/pangowin32-fontmap.c @@ -1794,7 +1794,8 @@ pango_win32_face_list_sizes (PangoFontFace *face, * for scalable fonts it's simple, and currently we only have such * see : pango_win32_enum_proc(), TRUETYPE_FONTTYPE */ - *sizes = NULL; + if (sizes) + *sizes = NULL; *n_sizes = 0; } diff --git a/tests/testmisc.c b/tests/testmisc.c index 1697b7cd..06b39a7a 100644 --- a/tests/testmisc.c +++ b/tests/testmisc.c @@ -101,6 +101,26 @@ test_language_emoji_crash (void) g_assert (scripts == NULL || num > 0); } +static void +test_line_height (void) +{ + PangoContext *context; + PangoLayout *layout; + PangoLayoutLine *line; + int height = 0; + + context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); + layout = pango_layout_new (context); + pango_layout_set_text (layout, "one\ttwo", -1); + line = pango_layout_get_line_readonly (layout, 0); + pango_layout_line_get_height (line, &height); + + g_assert_cmpint (height, >, 0); + + g_object_unref (layout); + g_object_unref (context); +} + int main (int argc, char *argv[]) { @@ -111,6 +131,7 @@ main (int argc, char *argv[]) g_test_add_func ("/layout/itemize-utf8", test_itemize_utf8); g_test_add_func ("/layout/short-string-crash", test_short_string_crash); g_test_add_func ("/language/emoji-crash", test_language_emoji_crash); + g_test_add_func ("/layout/line-height", test_line_height); return g_test_run (); } diff --git a/utils/meson.build b/utils/meson.build index b71cfe2a..12968ef7 100644 --- a/utils/meson.build +++ b/utils/meson.build @@ -80,3 +80,10 @@ if cairo_dep.found() ]) endif + +pango_segmentation = executable('pango-segmentation', + 'pango-segmentation.c', + dependencies: [ libpango_dep, libpangocairo_dep ], + include_directories: [ root_inc ], + install: false, + ) diff --git a/utils/pango-segmentation.c b/utils/pango-segmentation.c new file mode 100644 index 00000000..3e774167 --- /dev/null +++ b/utils/pango-segmentation.c @@ -0,0 +1,182 @@ +/* Pango + * pango-segmentation.c: Test Pango line breaking + * + * Copyright (C) 2021 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <glib.h> +#include <pango/pangocairo.h> +#include <string.h> +#include <locale.h> + +#ifndef G_OS_WIN32 +#include <unistd.h> +#endif + +typedef enum { + GRAPHEME, + WORD, + LINE, + SENTENCE +} BreakKind; + +static BreakKind +kind_from_string (const char *str) +{ + if (strcmp (str, "grapheme") == 0) + return GRAPHEME; + else if (strcmp (str, "word") == 0) + return WORD; + else if (strcmp (str, "line") == 0) + return LINE; + else if (strcmp (str, "sentence") == 0) + return SENTENCE; + else + { + g_printerr ("Not a segmentation: %s", str); + return 0; + } +} + +static gboolean +show_segmentation (const char *input, + BreakKind kind) +{ + GString *string; + PangoContext *context; + gsize length; + GError *error = NULL; + PangoLogAttr *attrs; + int len; + char *p; + int i; + char *text; + PangoAttrList *attributes; + PangoLayout *layout; + + context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); + + string = g_string_new (""); + + length = strlen (input); + len = g_utf8_strlen (input, -1) + 1; + + pango_parse_markup (input, -1, 0, &attributes, &text, NULL, &error); + g_assert_no_error (error); + + layout = pango_layout_new (context); + pango_layout_set_text (layout, text, length); + pango_layout_set_attributes (layout, attributes); + + if (pango_layout_get_unknown_glyphs_count (layout) > 0) + { + char *msg = g_strdup_printf ("Missing glyphs - skipping. Maybe fonts are missing?"); + g_test_skip (msg); + g_free (msg); + g_object_unref (layout); + pango_attr_list_unref (attributes); + g_free (text); + return FALSE; + } + + pango_layout_get_log_attrs (layout, &attrs, &len); + + for (i = 0, p = text; i < len; i++, p = g_utf8_next_char (p)) + { + PangoLogAttr log = attrs[i]; + gboolean is_break = FALSE; + + switch (kind) + { + case GRAPHEME: + is_break = log.is_cursor_position; + break; + case WORD: + is_break = log.is_word_boundary; + break; + case LINE: + is_break = log.is_line_break; + break; + case SENTENCE: + is_break = log.is_sentence_boundary; + break; + default: + g_assert_not_reached (); + } + + if (is_break) + g_string_append (string, "|"); + + if (i < len - 1) + { + gunichar ch = g_utf8_get_char (p); + if (ch == 0x20) + g_string_append (string, " "); + else if (g_unichar_isgraph (ch) && + !(g_unichar_type (ch) == G_UNICODE_LINE_SEPARATOR || + g_unichar_type (ch) == G_UNICODE_PARAGRAPH_SEPARATOR)) + g_string_append_unichar (string, ch); + else + g_string_append_printf (string, "[%#04x]", ch); + } + } + + g_object_unref (layout); + g_free (attrs); + g_free (text); + pango_attr_list_unref (attributes); + + g_print ("%s\n", string->str); + + g_string_free (string, TRUE); + + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + setlocale (LC_ALL, ""); + char *opt_kind = "grapheme"; + GOptionEntry entries[] = { + { "kind", 0, 0, G_OPTION_ARG_STRING, &opt_kind, "Kind of boundary (grapheme/word/line/sentence)", "KIND" }, + { NULL, }, + }; + GOptionContext *context; + GError *error = NULL; + + context = g_option_context_new ("TEXT"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_set_description (context, + "Show text segmentation as determined by Pango."); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_printerr ("%s\n", error->message); + exit (1); + } + + if (argc < 2) + { + g_printerr ("Usage: pango-segmentation [OPTIONS…] TEXT"); + exit (1); + } + + show_segmentation (argv[1], kind_from_string (opt_kind)); + + return 0; +} |