From b39b5f2f31d69d5fbe24659d294fd22f099f5956 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 3 Jun 2022 04:10:28 -0600 Subject: [PATCH] [name] Implement approximate language matching Very rudimentary. Fixes https://github.com/harfbuzz/harfbuzz/issues/3354 --- src/hb-ot-name-table.hh | 36 +++++++++++++++++++++++++++++++----- test/api/test-ot-name.c | 7 +++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index d52367e9b..01107aad6 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -156,7 +156,7 @@ struct NameRecord }; static int -_hb_ot_name_entry_cmp_key (const void *pa, const void *pb) +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) { const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; @@ -169,8 +169,23 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb) if (a->language == b->language) return 0; if (!a->language) return -1; if (!b->language) return +1; - return strcmp (hb_language_to_string (a->language), - hb_language_to_string (b->language)); + + const char *astr = hb_language_to_string (a->language); + const char *bstr = hb_language_to_string (b->language); + + signed c = strcmp (astr, bstr); + + if (!exact && c) + { + unsigned la = strlen (astr); + unsigned lb = strlen (bstr); + // 'a' is the user request, and 'b' is string in the font. + // If eg. user asks for "en-us" and font has "en", approve. + if (la > lb && astr[lb] == '-' && !strncmp (astr, bstr, lb)) + return 0; + } + + return c; } static int @@ -178,7 +193,7 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb) { /* Compare by name_id, then language, then score, then index. */ - int v = _hb_ot_name_entry_cmp_key (pa, pb); + int v = _hb_ot_name_entry_cmp_key (pa, pb, true); if (v) return v; @@ -330,7 +345,18 @@ struct name const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, this->names.length, sizeof (hb_ot_name_entry_t), - _hb_ot_name_entry_cmp_key); + _hb_ot_name_entry_cmp_key, + true); + + if (!entry) + { + entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + false); + } + if (!entry) return -1; diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c index d688eb3fb..f3989f788 100644 --- a/test/api/test-ot-name.c +++ b/test/api/test-ot-name.c @@ -93,10 +93,17 @@ test_ot_name (void) name_id = entries[3].name_id; g_assert_cmpuint (3, ==, name_id); lang = entries[3].language; + g_assert_cmpstr (hb_language_to_string (lang), ==, "en"); g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, lang, &text_size, text)); g_assert_cmpuint (9, ==, text_size); g_assert_cmpstr (text, ==, "FontForge"); + + g_assert_cmpuint (27, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("en_US", -1), &text_size, text)); + g_assert_cmpuint (8, ==, text_size); + g_assert_cmpstr (text, ==, "FontForg"); + + g_assert_cmpuint (0, ==, hb_ot_name_get_utf8 (face, name_id, hb_language_from_string ("fa_IR", -1), &text_size, text)); } int