From 6ca0ffd42e0a5cea2adc9efaedf7fc6fd333f9d1 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 16 Aug 2021 14:52:13 +0200 Subject: [PATCH 1/4] [util] Add --unicodes-before/after Parallel to --unicodes for --text-before/after. To be used in tests. --- util/text-options.hh | 160 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 128 insertions(+), 32 deletions(-) diff --git a/util/text-options.hh b/util/text-options.hh index cf780f14b..82ca6c0bd 100644 --- a/util/text-options.hh +++ b/util/text-options.hh @@ -119,6 +119,43 @@ parse_text (const char *name G_GNUC_UNUSED, return true; } +static bool +encode_unicodes (const char *unicodes, + GString *gs, + GError **error) +{ +#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r " + + char *s = (char *) unicodes; + char *p; + + while (s && *s) + { + while (*s && strchr (DELIMITERS, *s)) + s++; + if (!*s) + break; + + errno = 0; + hb_codepoint_t u = strtoul (s, &p, 16); + if (errno || s == p) + { + g_string_free (gs, TRUE); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing Unicode value at: '%s'", s); + return false; + } + + g_string_append_unichar (gs, u); + + s = p; + } + +#undef DELIMITERS + + return true; +} + static gboolean parse_unicodes (const char *name G_GNUC_UNUSED, const char *arg, @@ -136,44 +173,101 @@ parse_unicodes (const char *name G_GNUC_UNUSED, GString *gs = g_string_new (nullptr); if (0 == strcmp (arg, "*")) - { g_string_append_c (gs, '*'); - } else - { -#define DELIMITERS "<+->{},;&#\\xXuUnNiI\n\t\v\f\r " - - char *s = (char *) arg; - char *p; - - while (s && *s) - { - while (*s && strchr (DELIMITERS, *s)) - s++; - if (!*s) - break; - - errno = 0; - hb_codepoint_t u = strtoul (s, &p, 16); - if (errno || s == p) - { - g_string_free (gs, TRUE); - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing Unicode value at: '%s'", s); - return false; - } - - g_string_append_unichar (gs, u); - - s = p; - } - } + if (!encode_unicodes (arg, gs, error)) + return false; text_opts->text_len = gs->len; text_opts->text = g_string_free (gs, FALSE); return true; } +static gboolean +parse_text_before (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) +{ + auto *opts = (shape_text_options_t *) data; + + if (opts->text_before) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text-before or --unicodes-before can be provided but not both"); + return false; + } + + opts->text_before = g_strdup (arg); + fprintf(stderr, "%s\n", opts->text_before); + return true; +} + +static gboolean +parse_unicodes_before (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) +{ + auto *opts = (shape_text_options_t *) data; + + if (opts->text_before) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text-before or --unicodes-before can be provided but not both"); + return false; + } + + GString *gs = g_string_new (nullptr); + if (!encode_unicodes (arg, gs, error)) + return false; + + opts->text_before = g_string_free (gs, FALSE); + return true; +} + +static gboolean +parse_text_after (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) +{ + auto *opts = (shape_text_options_t *) data; + + if (opts->text_after) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text-after or --unicodes-after can be provided but not both"); + return false; + } + + opts->text_after = g_strdup (arg); + return true; +} + +static gboolean +parse_unicodes_after (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error) +{ + auto *opts = (shape_text_options_t *) data; + + if (opts->text_after) + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Either --text-after or --unicodes-after can be provided but not both"); + return false; + } + + GString *gs = g_string_new (nullptr); + if (!encode_unicodes (arg, gs, error)) + return false; + + opts->text_after = g_string_free (gs, FALSE); + return true; +} + const char * text_options_t::get_line (unsigned int *len) { @@ -236,8 +330,10 @@ shape_text_options_t::add_options (option_parser_t *parser) GOptionEntry entries[] = { - {"text-before", 0, 0, G_OPTION_ARG_STRING, &this->text_before, "Set text context before each line", "string"}, - {"text-after", 0, 0, G_OPTION_ARG_STRING, &this->text_after, "Set text context after each line", "string"}, + {"text-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_before, "Set text context before each line", "string"}, + {"text-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_text_after, "Set text context after each line", "string"}, + {"unicodes-before", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_before, "Set Unicode codepoints context before each line", "list of hex numbers"}, + {"unicodes-after", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_unicodes_after, "Set Unicode codepoints context after each line", "list of hex numbers"}, {nullptr} }; parser->add_group (entries, From 430224b1a06c6eef04de9b6e1ee5aa2cb7a9a403 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 16 Aug 2021 15:40:47 +0200 Subject: [PATCH 2/4] [buffer] Handle pre/post-context in buffer_append Fixes https://github.com/harfbuzz/harfbuzz/issues/1843 --- src/hb-buffer.cc | 15 +++++++++++++++ util/shape-options.hh | 1 - 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index 13fe11f18..0632a4abb 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -1755,6 +1755,21 @@ hb_buffer_append (hb_buffer_t *buffer, memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); + + if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) + { + /* pre-context */ + while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH) + buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint; + for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++) + buffer->context[0][buffer->context_len[0]++] = source->context[0][i]; + + /* post-context */ + while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH) + buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint; + for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++) + buffer->context[1][buffer->context_len[1]++] = source->context[1][i]; + } } diff --git a/util/shape-options.hh b/util/shape-options.hh index 89dd8dfc9..a87c9d48c 100644 --- a/util/shape-options.hh +++ b/util/shape-options.hh @@ -235,7 +235,6 @@ struct shape_options_t hb_buffer_clear_contents (fragment); copy_buffer_properties (fragment, buffer); - /* TODO: Add pre/post context text. */ hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); if (0 < text_start) flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); From 33bfe9edd679d61898209281960ec1a8570a11c7 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 16 Aug 2021 17:00:57 +0200 Subject: [PATCH 3/4] [test] Add tests for item context Test pre-context and post-context in Arabic shaper, as well as interaction of pre-context with BOT flag. --- test/shape/data/in-house/Makefile.sources | 1 + .../3105b51976b879032c66aa93a634b3b3672cd344.ttf | Bin 0 -> 2768 bytes .../65984dfce552a785f564422aadf4715fa07795ad.ttf | Bin 0 -> 4020 bytes test/shape/data/in-house/meson.build | 1 + .../shape/data/in-house/tests/item-context.tests | 11 +++++++++++ 5 files changed, 13 insertions(+) create mode 100644 test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf create mode 100644 test/shape/data/in-house/fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf create mode 100644 test/shape/data/in-house/tests/item-context.tests diff --git a/test/shape/data/in-house/Makefile.sources b/test/shape/data/in-house/Makefile.sources index 13066c7ae..dec23cb5e 100644 --- a/test/shape/data/in-house/Makefile.sources +++ b/test/shape/data/in-house/Makefile.sources @@ -31,6 +31,7 @@ TESTS = \ tests/indic-special-cases.tests \ tests/indic-syllable.tests \ tests/indic-vowel-letter-spoofing.tests \ + tests/item-context.tests \ tests/kern-format2.tests \ tests/khmer-mark-order.tests \ tests/khmer-misc.tests \ diff --git a/test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf b/test/shape/data/in-house/fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf new file mode 100644 index 0000000000000000000000000000000000000000..de14336462eaeb6c2501032466a7ba63c673d032 GIT binary patch literal 2768 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 CxYC{g literal 0 HcmV?d00001 diff --git a/test/shape/data/in-house/meson.build b/test/shape/data/in-house/meson.build index b1a282c32..5b6c4f750 100644 --- a/test/shape/data/in-house/meson.build +++ b/test/shape/data/in-house/meson.build @@ -31,6 +31,7 @@ in_house_tests = [ 'indic-special-cases.tests', 'indic-syllable.tests', 'indic-vowel-letter-spoofing.tests', + 'item-context.tests', 'kern-format2.tests', 'khmer-mark-order.tests', 'khmer-misc.tests', diff --git a/test/shape/data/in-house/tests/item-context.tests b/test/shape/data/in-house/tests/item-context.tests new file mode 100644 index 000000000..b9f1b1f1d --- /dev/null +++ b/test/shape/data/in-house/tests/item-context.tests @@ -0,0 +1,11 @@ +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=9+316|uni064E=7@169,-24+0|uniFEE8=7+341|uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643,U+0650;U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=7+316|uni064E=5@169,-24+0|uniFEE8=5+341|uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643;U+062A,U+064E,U+0627,U+0628,U+064F,U+0646,U+064E,U+0627;[uniFE8E=7+316|uni064E=5@169,-24+0|uniFEE8=5+341|uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0646,U+064E,U+0627;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0646;U+0643,U+0650,U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=5@167,-222+0|uniFE91=5+301|uniFE8E=4+316|uni064E=2@196,-28+0|uniFE98=2+391|uni0650=0@288,44+0|uniFEDB=0+576] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643,U+0650 --unicodes-after=U+0646,U+064E,U+0627;U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0643 --unicodes-after=U+0646;U+062A,U+064E,U+0627,U+0628,U+064F;[uni064F=3@167,-222+0|uniFE91=3+301|uniFE8E=2+316|uni064E=0@196,-28+0|uniFE98=0+391] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-before=U+0627;U+0643,U+062A,U+0628;[uniFE90=2+821|uniFE98=1+391|uniFEDB=0+576] +../fonts/65984dfce552a785f564422aadf4715fa07795ad.ttf;--unicodes-after=U+0627;U+0643,U+062A,U+0628,U+0627;[uniFE8E=3+316|uniFE92=2+341|uniFE98=1+391|uniFEDB=0+576] +../fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf;--bot;U+064E;[uni25CC=0+679|uni064E=0@-607,-210+0] +../fonts/3105b51976b879032c66aa93a634b3b3672cd344.ttf;--bot --unicodes-before=0627;U+064E;[uni064E=0+0] From 4b5a81f13c326e26f740ca61752f95a9d2afe89c Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 25 Aug 2021 15:20:54 -0600 Subject: [PATCH 4/4] [buffer] Fix hb_buffer_append() pre/post-context logic Part of https://github.com/harfbuzz/harfbuzz/pull/3150 --- src/hb-buffer.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index 0632a4abb..c6591ca23 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -1758,13 +1758,20 @@ hb_buffer_append (hb_buffer_t *buffer, if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) { + /* See similar logic in add_utf. */ + /* pre-context */ - while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH) - buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint; - for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++) - buffer->context[0][buffer->context_len[0]++] = source->context[0][i]; + if (!orig_len && start + source->context_len[0] > 0) + { + buffer->clear_context (0); + while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH) + buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint; + for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++) + buffer->context[0][buffer->context_len[0]++] = source->context[0][i]; + } /* post-context */ + buffer->clear_context (1); while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH) buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint; for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)