diff options
-rw-r--r-- | meson.build | 8 | ||||
-rw-r--r-- | pango/break.c | 75 | ||||
-rw-r--r-- | pango/meson.build | 38 | ||||
-rw-r--r-- | pango/pango-break.h | 5 | ||||
-rw-r--r-- | pango/pango-context.c | 9 | ||||
-rw-r--r-- | pango/pango-engine-private.h | 2 | ||||
-rw-r--r-- | pango/pango-layout.c | 109 | ||||
-rw-r--r-- | tests/breaks/one.expected | 10 | ||||
-rw-r--r-- | tests/itemize/one.expected | 7 | ||||
-rw-r--r-- | tests/itemize/one.items | 1 | ||||
-rw-r--r-- | tests/meson.build | 29 | ||||
-rw-r--r-- | tests/test-break.c | 5 | ||||
-rw-r--r-- | tests/test-itemize.c | 269 | ||||
-rw-r--r-- | utils/meson.build | 2 |
14 files changed, 429 insertions, 140 deletions
diff --git a/meson.build b/meson.build index 73b5da2b..d1150907 100644 --- a/meson.build +++ b/meson.build @@ -183,6 +183,8 @@ endif # Dependencies pango_deps = [] +pangoxft_deps = [] +pangocairo_deps = [] glib_req_version = '>= 2.59.2' fribidi_req_version = '>= 0.19.7' @@ -314,8 +316,8 @@ endif xft_dep = dependency('xft', version: xft_req_version, required: false) if xft_dep.found() and fontconfig_dep.found() and freetype_dep.found() pango_conf.set('HAVE_XFT', 1) - pango_deps += dependency('xrender', required: false) - pango_deps += xft_dep + pangoxft_deps += dependency('xrender', required: false) + pangoxft_deps += xft_dep endif if host_system == 'darwin' @@ -488,7 +490,7 @@ endif if cairo_dep.found() pango_conf.set('HAVE_CAIRO', 1) - pango_deps += cairo_dep + pangocairo_deps += cairo_dep pangocairo_requires = '' diff --git a/pango/break.c b/pango/break.c index 13ccbdaf..11a1e34a 100644 --- a/pango/break.c +++ b/pango/break.c @@ -22,7 +22,6 @@ #include "config.h" #include "pango-break.h" -#include "pango-engine-private.h" #include "pango-script-private.h" #include "pango-emoji-private.h" #include "pango-break-table.h" @@ -984,7 +983,6 @@ pango_default_break (const gchar *text, attrs[i].is_char_break = FALSE; attrs[i].is_line_break = FALSE; attrs[i].is_mandatory_break = FALSE; - attrs[i].is_soft_hyphen = FALSE; /* Rule LB1: assign a line breaking class to each code point of the input. */ @@ -1365,15 +1363,9 @@ pango_default_break (const gchar *text, case BREAK_ALLOWED: attrs[i].is_line_break = TRUE; - /* fall through */ + break; case BREAK_ALREADY_HANDLED: - if (attrs[i].is_line_break) - { - /* After Soft Hyphen */ - if (prev_wc == 0x00AD) - attrs[i].is_soft_hyphen = TRUE; - } break; default: @@ -1581,23 +1573,25 @@ pango_default_break (const gchar *text, } static gboolean +break_script (const char *item_text, + unsigned int item_length, + const PangoAnalysis *analysis, + PangoLogAttr *attrs, + int attrs_len); + +static gboolean tailor_break (const gchar *text, gint length, PangoAnalysis *analysis, PangoLogAttr *attrs, int attrs_len) { - if (analysis->lang_engine && PANGO_ENGINE_LANG_GET_CLASS (analysis->lang_engine)->script_break) - { - if (length < 0) - length = strlen (text); - else if (text == NULL) - text = ""; + if (length < 0) + length = strlen (text); + else if (text == NULL) + text = ""; - PANGO_ENGINE_LANG_GET_CLASS (analysis->lang_engine)->script_break (analysis->lang_engine, text, length, analysis, attrs, attrs_len); - return TRUE; - } - return FALSE; + return break_script (text, length, analysis, attrs, attrs_len); } /** @@ -1794,7 +1788,6 @@ pango_get_log_attrs (const char *text, g_return_if_fail (log_attrs != NULL); analysis.level = level; - analysis.lang_engine = _pango_get_language_engine (); pango_default_break (text, length, &analysis, log_attrs, attrs_len); @@ -1824,7 +1817,7 @@ pango_get_log_attrs (const char *text, #include "break-indic.c" #include "break-thai.c" -static void +static gboolean break_script (const char *item_text, unsigned int item_length, const PangoAnalysis *analysis, @@ -1853,43 +1846,9 @@ break_script (const char *item_text, case PANGO_SCRIPT_THAI: break_thai (item_text, item_length, analysis, attrs, attrs_len); break; + default: + return FALSE; } -} - -/* Wrap language breaker in PangoEngineLang to pass it through old API, - * from times when there were modules and engines. */ -typedef PangoEngineLang PangoLanguageEngine; -typedef PangoEngineLangClass PangoLanguageEngineClass; -static GType pango_language_engine_get_type (void) G_GNUC_CONST; -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -G_DEFINE_TYPE (PangoLanguageEngine, pango_language_engine, PANGO_TYPE_ENGINE_LANG); -G_GNUC_END_IGNORE_DEPRECATIONS -static void -_pango_language_engine_break (PangoEngineLang *engine G_GNUC_UNUSED, - const char *item_text, - int item_length, - PangoAnalysis *analysis, - PangoLogAttr *attrs, - int attrs_len) -{ - break_script (item_text, item_length, analysis, attrs, attrs_len); -} -static void -pango_language_engine_class_init (PangoEngineLangClass *class) -{ - class->script_break = _pango_language_engine_break; -} -static void -pango_language_engine_init (PangoEngineLang *object) -{ -} - -PangoEngineLang * -_pango_get_language_engine (void) -{ - static PangoEngineLang *engine; - if (g_once_init_enter (&engine)) - g_once_init_leave (&engine, g_object_new (pango_language_engine_get_type(), NULL)); - return engine; + return TRUE; } diff --git a/pango/meson.build b/pango/meson.build index 4ca062ec..faf38780 100644 --- a/pango/meson.build +++ b/pango/meson.build @@ -56,6 +56,27 @@ pango_headers = [ 'pango-version-macros.h', ] +pango_requires = [ + 'gobject-2.0', +] + +if fontconfig_dep.found() + pango_headers += [ + 'pangofc-font.h', + 'pangofc-fontmap.h', + 'pangofc-decoder.h', + ] + pango_sources += [ + 'pangofc-font.c', + 'pangofc-fontmap.c', + 'pangofc-decoder.c', + 'pangofc-shape.c', + ] + pango_requires += [ + fontconfig_pc, + ] +endif + install_headers(pango_headers, subdir: pango_api_path) # Features header @@ -155,7 +176,7 @@ pkgconfig.generate(libpango, name: 'Pango', description: 'Internationalized text handling', version: meson.project_version(), - requires: ['gobject-2.0'], + requires: pango_requires, filebase: 'pango', subdirs: pango_api_name, install_dir: join_paths(pango_libdir, 'pkgconfig'), @@ -165,17 +186,10 @@ pkgconfig.generate(libpango, if build_pangoft2 pangoft2_headers = [ 'pango-ot.h', - 'pangofc-font.h', - 'pangofc-fontmap.h', - 'pangofc-decoder.h', 'pangoft2.h', ] pangoft2_public_sources = [ - 'pangofc-font.c', - 'pangofc-fontmap.c', - 'pangofc-decoder.c', - 'pangofc-shape.c', 'pangoft2.c', ] @@ -282,7 +296,7 @@ if xft_dep.found() and fontconfig_dep.found() soversion: pango_soversion, darwin_versions : pango_osxversion, install: true, - dependencies: pango_deps + [ libpango_dep, libpangoft2_dep ], + dependencies: pango_deps + pangoxft_deps + [ libpango_dep, libpangoft2_dep ], include_directories: [ root_inc, pango_inc ], c_args: common_cflags + pango_debug_cflags + pango_cflags + [ '-DPANGO_DISABLE_DEPRECATION_WARNINGS', @@ -408,15 +422,13 @@ if cairo_dep.found() 'pangocairo-render.c', ] - pangocairo_deps = pango_deps + [ libpango_dep ] + pangocairo_deps += libpango_dep if pango_font_backends.contains('freetype') pangocairo_sources += [ 'pangocairo-fcfont.c', 'pangocairo-fcfontmap.c', ] - - pangocairo_deps += libpangoft2_dep endif if host_system == 'windows' and pango_font_backends.contains('win32') @@ -486,7 +498,7 @@ if cairo_dep.found() libpangocairo_dep = declare_dependency( link_with: libpangocairo, include_directories: root_inc, - dependencies: pango_deps + [ libpango_dep ], + dependencies: pangocairo_deps + pango_deps + [ libpango_dep ], sources: pangocairo_dep_sources, ) diff --git a/pango/pango-break.h b/pango/pango-break.h index 66d81631..92af390b 100644 --- a/pango/pango-break.h +++ b/pango/pango-break.h @@ -79,9 +79,6 @@ G_BEGIN_DECLS * This flag implements Unicode's * <ulink url="http://www.unicode.org/reports/tr29/">Word * Boundaries</ulink> semantics. (Since: 1.22) - * @is_soft_hyphen: is a line break due to a Soft Hyphen (0x00AD). - * This indicates a position where a hyphen should be inserted - * if the break is taken. * * The #PangoLogAttr structure stores information * about the attributes of a single character. @@ -89,6 +86,7 @@ G_BEGIN_DECLS struct _PangoLogAttr { guint is_line_break : 1; /* Can break line in front of character */ + guint is_mandatory_break : 1; /* Must break line in front of character */ guint is_char_break : 1; /* Can break here when doing char wrap */ @@ -132,7 +130,6 @@ struct _PangoLogAttr /* Word boundary as defined by UAX#29 */ guint is_word_boundary : 1; /* is NOT in the middle of a word */ - guint is_soft_hyphen : 1; /* line break due to a soft hyphen */ }; /* Determine information about cluster/word/line breaks in a string diff --git a/pango/pango-context.c b/pango/pango-context.c index f187a92f..413119f3 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -758,7 +758,6 @@ struct _ItemizeState PangoEmojiIter emoji_iter; PangoLanguage *derived_lang; - PangoEngineLang *lang_engine; PangoFontset *current_fonts; FontCache *cache; @@ -1061,7 +1060,6 @@ itemize_state_init (ItemizeState *state, state->gravity_hint = state->context->gravity_hint; state->resolved_gravity = PANGO_GRAVITY_AUTO; state->derived_lang = NULL; - state->lang_engine = NULL; state->current_fonts = NULL; state->cache = NULL; state->base_font = NULL; @@ -1165,7 +1163,6 @@ itemize_state_add_character (ItemizeState *state, } if (!force_break && - state->item->analysis.lang_engine == state->lang_engine && state->item->analysis.shape_engine == shape_engine && state->item->analysis.font == font) { @@ -1181,7 +1178,6 @@ itemize_state_add_character (ItemizeState *state, state->item->length = 0; state->item->num_chars = 1; state->item->analysis.shape_engine = shape_engine; - state->item->analysis.lang_engine = state->lang_engine; if (font) g_object_ref (font); @@ -1404,11 +1400,6 @@ itemize_state_update_for_new_run (ItemizeState *state) state->changed |= DERIVED_LANG_CHANGED; } - if ((state->changed & DERIVED_LANG_CHANGED) || !state->lang_engine) - { - state->lang_engine = _pango_get_language_engine (); - } - if (state->changed & (EMOJI_CHANGED)) { state->changed |= FONT_CHANGED; diff --git a/pango/pango-engine-private.h b/pango/pango-engine-private.h index de54ee09..cd0b6103 100644 --- a/pango/pango-engine-private.h +++ b/pango/pango-engine-private.h @@ -42,8 +42,6 @@ PangoCoverageLevel _pango_engine_shape_covers (PangoEngineShape *engine, PangoEngineShape *_pango_get_fallback_shaper (void) /* XXX got to go when we switch to harfbuzz-only. */; -PangoEngineLang *_pango_get_language_engine (void); - G_END_DECLS #endif /* __PANGO_ENGINE_PRIVATE_H__ */ diff --git a/pango/pango-layout.c b/pango/pango-layout.c index baf81bd4..2b07954e 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -3297,6 +3297,8 @@ struct _ParaBreakState /* maintained per line */ int line_width; /* Goal width of line currently processing; < 0 is infinite */ int remaining_width; /* Amount of space remaining on line; < 0 is infinite */ + + int hyphen_width; /* How much space a hyphen will take */ }; static gboolean @@ -3436,6 +3438,64 @@ create_hyphen_run (PangoLayout *layout, return hyphen; } +static gboolean +break_needs_hyphen (PangoLayout *layout, + ParaBreakState *state, + int num_chars) +{ + gunichar ch; + + if (state->start_offset + num_chars == 0) + return FALSE; + + ch = g_utf8_get_char (layout->text + state->start_offset + num_chars - 1); + + /* Just look for soft hyphen, for now */ + if (ch == 0xAD) + return TRUE; + + return FALSE; +} + +static int +find_break_extra_width (PangoLayout *layout, + ParaBreakState *state, + int num_chars) +{ + PangoItem *item = state->items->data; + + /* Check whether to insert a hyphen */ + if (break_needs_hyphen (layout, state, num_chars)) + { + if (state->hyphen_width < 0) + { + PangoLayoutRun *run; + + run = create_hyphen_run (layout, item, state->start_offset); + state->hyphen_width = pango_glyph_string_get_width (run->glyphs); + pango_glyph_item_free (run); + } + + return state->hyphen_width; + } + else + return 0; +} + +static void +insert_hyphen (PangoLayoutLine *line, + ParaBreakState *state, + PangoItem *item, + int num_chars) +{ + PangoLayout *layout = line->layout; + PangoLayoutRun *run; + + run = create_hyphen_run (layout, item, state->start_offset + num_chars); + line->runs = g_slist_prepend (line->runs, run); + state->remaining_width -= pango_glyph_string_get_width (run->glyphs); +} + #if 0 # define DEBUG debug void @@ -3507,6 +3567,7 @@ process_item (PangoLayout *layout, { insert_run (line, state, item, TRUE); state->log_widths_offset += item->num_chars; + return BREAK_LINE_SEPARATOR; } @@ -3544,7 +3605,6 @@ process_item (PangoLayout *layout, int break_width = width; int orig_width = width; int break_extra_width; - int hyphen_width; gboolean retrying_with_char_breaks = FALSE; if (processing_new_item) @@ -3554,14 +3614,6 @@ process_item (PangoLayout *layout, pango_glyph_item_get_logical_widths (&glyph_item, layout->text, state->log_widths); } - { - PangoLayoutRun *run; - - run = create_hyphen_run (layout, item, state->start_offset); - hyphen_width = pango_glyph_string_get_width (run->glyphs); - pango_glyph_item_free (run); - } - retry_break: /* See how much of the item we can stuff in the line. */ @@ -3579,11 +3631,7 @@ process_item (PangoLayout *layout, break_num_chars = num_chars; break_width = width; - /* Check whether to insert a hyphen */ - if (layout->log_attrs[state->start_offset + num_chars].is_soft_hyphen) - break_extra_width = hyphen_width; - else - break_extra_width = 0; + break_extra_width = find_break_extra_width (layout, state, num_chars); } width += state->log_widths[state->log_widths_offset + num_chars]; @@ -3620,14 +3668,8 @@ process_item (PangoLayout *layout, if (break_num_chars == item->num_chars) { insert_run (line, state, item, TRUE); - if (layout->log_attrs[state->start_offset + break_num_chars].is_soft_hyphen) - { - PangoLayoutRun *run; - - run = create_hyphen_run (layout, item, state->start_offset + break_num_chars); - line->runs = g_slist_prepend (line->runs, run); - state->remaining_width -= pango_glyph_string_get_width (run->glyphs); - } + if (break_needs_hyphen (layout, state, break_num_chars)) + insert_hyphen (line, state, item, break_num_chars); return BREAK_ALL_FIT; } @@ -3654,14 +3696,8 @@ process_item (PangoLayout *layout, /* Shaped items should never be broken */ g_assert (!shape_set); - if (layout->log_attrs[state->start_offset + break_num_chars].is_soft_hyphen) - { - PangoLayoutRun *run; - - run = create_hyphen_run (layout, item, state->start_offset + break_num_chars); - line->runs = g_slist_prepend (line->runs, run); - state->remaining_width -= pango_glyph_string_get_width (run->glyphs); - } + if (break_needs_hyphen (layout, state, break_num_chars)) + insert_hyphen (line, state, new_item, break_num_chars); return BREAK_SOME_FIT; } @@ -3912,13 +3948,8 @@ get_items_log_attrs (const char *text, PangoItem *next_item = items->next->data; /* FIXME: Handle language tags */ - if (next_item->analysis.lang_engine != tmp_item.analysis.lang_engine) - break; - else - { - tmp_item.length += next_item->length; - tmp_item.num_chars += next_item->num_chars; - } + tmp_item.length += next_item->length; + tmp_item.num_chars += next_item->num_chars; items = items->next; } @@ -3931,7 +3962,7 @@ get_items_log_attrs (const char *text, } /* XXX This is wrong. we should call pango_default_break on the entire - * layout text and then tailor_break on each lang_engine change, like + * layout text and then tailor_break on each language change, like * pango_get_log_attrs does. */ pango_break (text + index, tmp_item.length, &tmp_item.analysis, @@ -4154,6 +4185,8 @@ pango_layout_check_lines (PangoLayout *layout) state.remaining_width = -1; state.log_widths_offset = 0; + state.hyphen_width = -1; + if (state.items) { while (state.items) diff --git a/tests/breaks/one.expected b/tests/breaks/one.expected index 7fb600e6..d474c6e4 100644 --- a/tests/breaks/one.expected +++ b/tests/breaks/one.expected @@ -1,5 +1,5 @@ -Text: a b c / d e f [ ] g h i [0xad] j k l . [ ] B l a [0x0a] -Breaks: c c c c lc c c c lc c c c lhc c c c c lc c c c Lc -Whitespace: x x w w -Words: bs be bs be bs be b bs be b -Sentences: bs e bs e b +Text: a b c / d e f [ ] g h i [0xad] j k l . [ ] B l a [0x0a] +Breaks: c c c c lc c c c lc c c c lc c c c c lc c c c Lc +Whitespace: x x w w +Words: bs be bs be bs be b bs be b +Sentences: bs e bs e b diff --git a/tests/itemize/one.expected b/tests/itemize/one.expected new file mode 100644 index 00000000..1fe2824d --- /dev/null +++ b/tests/itemize/one.expected @@ -0,0 +1,7 @@ +<span font="Cantarell 11" fallback="false">a b
c</span> + +Items: a b |[0x2028] |c +Font: Cantarell 11|Cantarell 11|Cantarell 11 +Script: Latn |Latn |Latn +Lang: en-us |en-us |en-us +Bidi: 0 |0 |0 diff --git a/tests/itemize/one.items b/tests/itemize/one.items new file mode 100644 index 00000000..45b9c149 --- /dev/null +++ b/tests/itemize/one.items @@ -0,0 +1 @@ +<span font="Cantarell 11" fallback="false">a b
c</span> diff --git a/tests/meson.build b/tests/meson.build index 6357cd8a..b2d2d3e1 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -21,8 +21,8 @@ tests = [ [ 'testboundaries_ucd' ], [ 'testcolor' ], [ 'testscript' ], - [ 'cxx-test', [ 'cxx-test.cpp' ] ], - [ 'test-break', [ 'test-break.c', 'test-common.c' ] ], + [ 'cxx-test', [ 'cxx-test.cpp' ], [ libpangocairo_dep ] ], + [ 'test-break', [ 'test-break.c', 'test-common.c' ], [libpangocairo_dep ] ], ] if build_pangoft2 @@ -38,6 +38,7 @@ if cairo_dep.found() [ 'testiter', [ 'testiter.c' ], [ libpangocairo_dep ] ], [ 'markup-parse', [ 'markup-parse.c' , 'test-common.c' ], [ libpangocairo_dep ] ], [ 'test-layout', [ 'test-layout.c', 'test-common.c' ], [ libpangocairo_dep ] ], + [ 'test-itemize', [ 'test-itemize.c', 'test-common.c' ], [ libpangocairo_dep ] ], [ 'test-font', [ 'test-font.c' ], [ libpangocairo_dep ] ], [ 'testattributes', [ 'testattributes.c', 'test-common.c' ], [ libpangocairo_dep ] ], ] @@ -80,6 +81,16 @@ test_markups_data = [ 'markups/valid-9', ] +test_breaks_data = [ + 'breaks/one', + 'breaks/two', + 'breaks/three', +] + +test_items_data = [ + 'itemize/one', +] + installed_test_layouts_data = [] foreach d: test_layouts_data installed_test_layouts_data += d + '.markup' @@ -92,6 +103,18 @@ foreach d: test_markups_data installed_test_markups_data += d + '.expected' endforeach +installed_test_breaks_data = [] +foreach d: test_breaks_data + installed_test_breaks_data += d + '.break' + installed_test_breaks_data += d + '.expected' +endforeach + +installed_test_items_data = [] +foreach d: test_items_data + installed_test_items_data += d + '.items' + installed_test_items_data += d + '.expected' +endforeach + installed_test_datadir = join_paths(pango_datadir, 'installed-tests', 'pango') installed_test_bindir = join_paths(pango_libexecdir, 'installed-tests', 'pango') @@ -99,6 +122,8 @@ if get_option('install-tests') install_data(installed_test_data, install_dir: installed_test_bindir) install_data(installed_test_layouts_data, install_dir: join_paths(installed_test_bindir, 'layouts')) install_data(installed_test_markups_data, install_dir: join_paths(installed_test_bindir, 'markups')) + install_data(installed_test_breaks_data, install_dir: join_paths(installed_test_bindir, 'breaks')) + install_data(installed_test_items_data, install_dir: join_paths(installed_test_bindir, 'itemize')) endif python = import('python3').find_python() diff --git a/tests/test-break.c b/tests/test-break.c index e4c5bd28..00bc7be0 100644 --- a/tests/test-break.c +++ b/tests/test-break.c @@ -103,11 +103,6 @@ test_file (const gchar *filename, GString *string) g_string_append (s1, "l"); b++; } - if (log.is_soft_hyphen) - { - g_string_append (s1, "h"); - b++; - } if (log.is_char_break) { g_string_append (s1, "c"); diff --git a/tests/test-itemize.c b/tests/test-itemize.c new file mode 100644 index 00000000..c9fb4c53 --- /dev/null +++ b/tests/test-itemize.c @@ -0,0 +1,269 @@ +/* Pango + * test-break.c: Test Pango line breaking + * + * Copyright (C) 2019 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 <string.h> +#include <locale.h> + +#ifndef G_OS_WIN32 +#include <unistd.h> +#endif + +#include "config.h" +#include <pango/pangocairo.h> +#include "test-common.h" + + +static PangoContext *context; + +static const char * +script_name (GUnicodeScript s) +{ + const char *names[] = { + "Zyyy", "Zinh", "Arab", "Armn", "Beng", "Bopo", "Cher", + "Copt", "Cyrl", "Dsrt", "Deva", "Ethi", "Geor", "Goth", + "Grek", "Gujr", "Guru", "Hani", "Hang", "Hebr", "Hira", + "Knda", "Kana", "Khmr", "Laoo", "Latn", "Mlym", "Mong", + "Mymr", "Ogam", "Ital", "Orya", "Runr", "Sinh", "Syrc", + "Taml", "Telu", "Thaa", "Thai", "Tibt", "Cans", "Yiii", + "Tglg", "Hano", "Buhd", "Tagb", "Brai", "Cprt", "Limb", + "Osma", "Shaw", "Linb", "Tale", "Ugar", "Talu", "Bugi", + "Glag", "Tfng", "Sylo", "Xpeo", "Khar", "Zzzz", "Bali", + "Xsux", "Phnx", "Phag", "Nkoo", "Kali", "Lepc", "Rjng", + "Sund", "Saur", "Cham", "Olck", "Vaii", "Cari", "Lyci", + "Lydi", "Avst", "Bamu", "Egyp", "Armi", "Phli", "Prti", + "Java", "Kthi", "Lisu", "Mtei", "Sarb", "Orkh", "Samr", + "Lana", "Tavt", "Batk", "Brah", "Mand", "Cakm", "Merc", + "Mero", "Plrd", "Shrd", "Sora", "Takr", "Bass", "Aghb", + "Dupl", "Elba", "Gran", "Khoj", "Sind", "Lina", "Mahj", + "Mani", "Mend", "Modi", "Mroo", "Nbat", "Narb", "Perm", + "Hmng", "Palm", "Pauc", "Phlp", "Sidd", "Tirh", "Wara", + "Ahom", "Hluw", "Hatr", "Mult", "Hung", "Sgnw", "Adlm", + "Bhks", "Marc", "Newa", "Osge", "Tang", "Gonm", "Nshu", + "Soyo", "Zanb", "Dogr", "Gong", "Rohg", "Maka", "Medf", + "Sogo", "Sogd", "Elym", "Nand", "Rohg", "Wcho" + }; + return names[s]; +} + +static void +append_text (GString *s, + const char *text, + int len) +{ + char *p; + + for (p = text; p < text + len; p = g_utf8_next_char (p)) + { + gunichar ch = g_utf8_get_char (p); + if (ch == 0x0A || ch == 0x2028 || !g_unichar_isprint (ch)) + g_string_append_printf (s, "[%#04x]", ch); + else + g_string_append_unichar (s, ch); + } +} +static void +test_file (const gchar *filename, GString *string) +{ + gchar *contents; + gsize length; + GError *error = NULL; + GString *s1, *s2, *s3, *s4, *s5; + char *test; + char *text; + PangoAttrList *attrs; + GList *items, *l; + const char *sep = ""; + + if (!g_file_get_contents (filename, &contents, &length, &error)) + { + fprintf (stderr, "%s\n", error->message); + g_error_free (error); + return; + } + + test = contents; + + /* Skip initial comments */ + while (test[0] == '#') + test = strchr (test, '\n') + 1; + + + if (!pango_parse_markup (test, -1, 0, &attrs, &text, NULL, &error)) + { + fprintf (stderr, "%s\n", error->message); + g_error_free (error); + return; + } + + s1 = g_string_new ("Items: "); + s2 = g_string_new ("Font: "); + s3 = g_string_new ("Script: "); + s4 = g_string_new ("Lang: "); + s5 = g_string_new ("Bidi: "); + + length = strlen (text); + if (text[length - 1] == '\n') + length--; + + items = pango_itemize (context, text, 0, length, attrs, NULL); + + for (l = items; l; l = l->next) + { + PangoItem *item = l->data; + PangoFontDescription *desc; + char *font; + int m; + + desc = pango_font_describe (item->analysis.font); + font = pango_font_description_to_string (desc); + + if (l != items) + sep = "|"; + g_string_append (s1, sep); + append_text (s1, text + item->offset, item->length); + + g_string_append_printf (s2, "%s%s", sep, font); + g_string_append_printf (s3, "%s%s", sep, script_name (item->analysis.script)); + g_string_append_printf (s4, "%s%s", sep, pango_language_to_string (item->analysis.language)); + g_string_append_printf (s5, "%s%d", sep, item->analysis.level); + + g_free (font); + pango_font_description_free (desc); + + m = MAX (MAX (MAX (s1->len, s2->len), MAX (s3->len, s4->len)), s5->len); + + g_string_append_printf (s1, "%*s", (int)(m - s1->len), ""); + g_string_append_printf (s2, "%*s", (int)(m - s2->len), ""); + g_string_append_printf (s3, "%*s", (int)(m - s3->len), ""); + g_string_append_printf (s4, "%*s", (int)(m - s4->len), ""); + g_string_append_printf (s5, "%*s", (int)(m - s5->len), ""); + } + + g_string_append_printf (string, "%s\n", test); + g_string_append_printf (string, "%s\n", s1->str); + g_string_append_printf (string, "%s\n", s2->str); + g_string_append_printf (string, "%s\n", s3->str); + g_string_append_printf (string, "%s\n", s4->str); + g_string_append_printf (string, "%s\n", s5->str); + + g_string_free (s1, TRUE); + g_string_free (s2, TRUE); + g_string_free (s3, TRUE); + g_string_free (s4, TRUE); + g_string_free (s5, TRUE); + + g_list_free_full (items, (GDestroyNotify)pango_item_free); + pango_attr_list_unref (attrs); + g_free (text); + g_free (contents); +} + +static gchar * +get_expected_filename (const gchar *filename) +{ + gchar *f, *p, *expected; + + f = g_strdup (filename); + p = strstr (f, ".items"); + if (p) + *p = 0; + expected = g_strconcat (f, ".expected", NULL); + + g_free (f); + + return expected; +} + +static void +test_itemize (gconstpointer d) +{ + const gchar *filename = d; + gchar *expected_file; + GError *error = NULL; + GString *dump; + gchar *diff; + + expected_file = get_expected_filename (filename); + + dump = g_string_sized_new (0); + + test_file (filename, dump); + + diff = diff_with_file (expected_file, dump->str, dump->len, &error); + g_assert_no_error (error); + + if (diff && diff[0]) + { + g_printerr ("Contents don't match expected contents:\n%s", diff); + g_test_fail (); + g_free (diff); + } + + g_string_free (dump, TRUE); + g_free (expected_file); +} + +int +main (int argc, char *argv[]) +{ + GDir *dir; + GError *error = NULL; + const gchar *name; + gchar *path; + + g_setenv ("LC_ALL", "en_US.UTF-8", TRUE); + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + context = pango_font_map_create_context (pango_cairo_font_map_get_default ()); + + /* allow to easily generate expected output for new test cases */ + if (argc > 1) + { + GString *string; + + string = g_string_sized_new (0); + test_file (argv[1], string); + printf ("%s", string->str); + + return 0; + } + + path = g_test_build_filename (G_TEST_DIST, "itemize", NULL); + dir = g_dir_open (path, 0, &error); + g_free (path); + g_assert_no_error (error); + while ((name = g_dir_read_name (dir)) != NULL) + { + if (!strstr (name, "items")) + continue; + + path = g_strdup_printf ("/itemize/%s", name); + g_test_add_data_func_full (path, g_test_build_filename (G_TEST_DIST, "itemize", name, NULL), + test_itemize, g_free); + g_free (path); + } + g_dir_close (dir); + + return g_test_run (); +} diff --git a/utils/meson.build b/utils/meson.build index 510d1b7e..855f6e36 100644 --- a/utils/meson.build +++ b/utils/meson.build @@ -19,7 +19,7 @@ if xft_dep.found() and build_pangoft2 'viewer-pangoxft.c', 'viewer-x.c', ] - pango_view_deps += [ libpangoft2_dep, libpangoxft_dep, ] + pango_view_deps += pangoxft_deps + [ libpangoft2_dep, libpangoxft_dep, ] endif if cairo_dep.found() |