From c3f590bb1eb5e2451b80aa3d10a29c62b32b860d Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Thu, 16 Jun 2022 11:04:13 -0600 Subject: [PATCH] [arabic] Support legacy PUA shaping Support legacy pre-OpenType Windows 3.1-era fonts, by remapping PUA code points in cmap table and letting our fallback shaper build the GSUB table. Uniscribe applies also mset-like substitution, but our fallback mark positioning gives better results, so this is not implemented. --- src/Makefile.sources | 1 + src/gen-arabic-table.py | 27 +- src/hb-ot-cmap-table.hh | 45 ++- src/hb-ot-os2-table.hh | 4 +- src/hb-ot-shaper-arabic-pua.hh | 289 ++++++++++++++++++ src/hb-ot-shaper-arabic-table.hh | 89 +++++- src/meson.build | 1 + .../data/in-house/fonts/SimpArabicTest.ttf | Bin 0 -> 17168 bytes .../data/in-house/fonts/TradArabicTest.ttf | Bin 0 -> 58132 bytes .../tests/arabic-fallback-shaping.tests | 10 + 10 files changed, 449 insertions(+), 17 deletions(-) create mode 100644 src/hb-ot-shaper-arabic-pua.hh create mode 100644 test/shape/data/in-house/fonts/SimpArabicTest.ttf create mode 100644 test/shape/data/in-house/fonts/TradArabicTest.ttf diff --git a/src/Makefile.sources b/src/Makefile.sources index 5ec46bac1..1be0800a1 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -133,6 +133,7 @@ HB_BASE_sources = \ hb-ot-post-table.hh \ hb-ot-shaper-arabic-fallback.hh \ hb-ot-shaper-arabic-joining-list.hh \ + hb-ot-shaper-arabic-pua.hh \ hb-ot-shaper-arabic-table.hh \ hb-ot-shaper-arabic-win1256.hh \ hb-ot-shaper-arabic.cc \ diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py index 1a1123abe..3ea2b850d 100755 --- a/src/gen-arabic-table.py +++ b/src/gen-arabic-table.py @@ -153,6 +153,16 @@ def print_joining_table(f): print ("#undef %s" % (short)) print () +LIGATURES = ( + 0xF2EE, 0xFC08, 0xFC0E, 0xFC12, 0xFC32, 0xFC3F, 0xFC40, 0xFC41, 0xFC42, + 0xFC44, 0xFC4E, 0xFC5E, 0xFC60, 0xFC61, 0xFC62, 0xFC6A, 0xFC6D, 0xFC6F, + 0xFC70, 0xFC73, 0xFC75, 0xFC86, 0xFC8F, 0xFC91, 0xFC94, 0xFC9C, 0xFC9D, + 0xFC9E, 0xFC9F, 0xFCA1, 0xFCA2, 0xFCA3, 0xFCA4, 0xFCA8, 0xFCAA, 0xFCAC, + 0xFCB0, 0xFCC9, 0xFCCA, 0xFCCB, 0xFCCC, 0xFCCD, 0xFCCE, 0xFCCF, 0xFCD0, + 0xFCD1, 0xFCD2, 0xFCD3, 0xFCD5, 0xFCDA, 0xFCDB, 0xFCDC, 0xFCDD, 0xFD30, + 0xFD88, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, +) + def print_shaping_table(f): shapes = {} @@ -166,14 +176,19 @@ def print_shaping_table(f): items = fields[5].split (' ') shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:]) + c = int (fields[0], 16) if not shape in ['initial', 'medial', 'isolated', 'final']: continue - c = int (fields[0], 16) if len (items) != 1: - # We only care about lam-alef ligatures - if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]: + # Mark ligatures start with space and are in visual order, so we + # remove the space and reverse the items. + if items[0] == 0x0020: + items = items[:0:-1] + shape = None + # We only care about a subset of ligatures + if c not in LIGATURES or len (items) != 2: continue # Save ligature @@ -213,10 +228,14 @@ def print_shaping_table(f): for pair in ligatures.keys (): for shape in ligatures[pair]: c = ligatures[pair][shape] - if shape == 'isolated': + if shape is None: + liga = pair + elif shape == 'isolated': liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final']) elif shape == 'final': liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final']) + elif shape == 'initial': + liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['medial']) else: raise Exception ("Unexpected shape", shape) if liga[0] not in ligas: diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 4fd2b9be4..ac96f9c84 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -27,6 +27,8 @@ #ifndef HB_OT_CMAP_TABLE_HH #define HB_OT_CMAP_TABLE_HH +#include "hb-ot-os2-table.hh" +#include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" #include "hb-set.hh" @@ -1502,6 +1504,21 @@ struct SubtableUnicodesCache { }; +static inline hb_codepoint_t +_hb_remap_symbol_pua (hb_codepoint_t codepoint) +{ + if (codepoint <= 0x00FFu) + { + /* For symbol-encoded OpenType fonts, we duplicate the + * U+F000..F0FF range at U+0000..U+00FF. That's what + * Windows seems to do, and that's hinted about at: + * https://docs.microsoft.com/en-us/typography/opentype/spec/recom + * under "Non-Standard (Symbol) Fonts". */ + return 0xF000u + codepoint; + } + return 0; +} + struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; @@ -1725,7 +1742,19 @@ struct cmap this->get_glyph_data = subtable; if (unlikely (symbol)) - this->get_glyph_funcZ = get_glyph_from_symbol; + { + switch ((unsigned) face->table.OS2->get_font_page ()) { + default: + this->get_glyph_funcZ = get_glyph_from_symbol; + break; + case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC: + this->get_glyph_funcZ = get_glyph_from_symbol; + break; + case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC: + this->get_glyph_funcZ = get_glyph_from_symbol; + break; + } + } else { switch (subtable->u.format) { @@ -1807,6 +1836,7 @@ struct cmap typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph); + typedef hb_codepoint_t (*hb_pua_remap_func_t) (hb_codepoint_t); template HB_INTERNAL static bool get_glyph_from (const void *obj, @@ -1817,7 +1847,7 @@ struct cmap return typed_obj->get_glyph (codepoint, glyph); } - template + template HB_INTERNAL static bool get_glyph_from_symbol (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) @@ -1826,15 +1856,8 @@ struct cmap if (likely (typed_obj->get_glyph (codepoint, glyph))) return true; - if (codepoint <= 0x00FFu) - { - /* For symbol-encoded OpenType fonts, we duplicate the - * U+F000..F0FF range at U+0000..U+00FF. That's what - * Windows seems to do, and that's hinted about at: - * https://docs.microsoft.com/en-us/typography/opentype/spec/recom - * under "Non-Standard (Symbol) Fonts". */ - return typed_obj->get_glyph (0xF000u + codepoint, glyph); - } + if (hb_codepoint_t c = remap (codepoint)) + return typed_obj->get_glyph (c, glyph); return false; } diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh index f0035e2f0..3473afef5 100644 --- a/src/hb-ot-os2-table.hh +++ b/src/hb-ot-os2-table.hh @@ -224,9 +224,11 @@ struct OS2 *max_cp = hb_min (0xFFFFu, codepoints->get_max ()); } - /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */ + /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 + * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */ enum font_page_t { + FONT_PAGE_NONE = 0, FONT_PAGE_HEBREW = 0xB100, /* Hebrew Windows 3.1 font page */ FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */ FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */ diff --git a/src/hb-ot-shaper-arabic-pua.hh b/src/hb-ot-shaper-arabic-pua.hh new file mode 100644 index 000000000..98cd266e9 --- /dev/null +++ b/src/hb-ot-shaper-arabic-pua.hh @@ -0,0 +1,289 @@ + +#ifndef HB_OT_SHAPER_ARABIC_PUA_HH +#define HB_OT_SHAPER_ARABIC_PUA_HH + +static const uint16_t _arabic_table_pua1[][128] = { + { /* 0x0000u..0x007Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF120u, 0xF121u, 0xF122u, 0x0000u, 0x0000u, 0xF125u, 0x0000u, 0x0000u, + 0xF128u, 0xF129u, 0xF12Au, 0xF12Bu, 0xF15Eu, 0xF12Du, 0xF12Eu, 0xF12Fu, + 0xF1B0u, 0xF1B1u, 0xF1B2u, 0xF1B3u, 0xF1B4u, 0xF1B5u, 0xF1B6u, 0xF1B7u, + 0xF1B8u, 0xF1B9u, 0xF13Au, 0xF13Bu, 0x0000u, 0xF13Du, 0x0000u, 0xF13Fu, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF15Bu, 0xF15Cu, 0xF15Du, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x0080u..0x00FFu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF123u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF124u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF126u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF127u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x0600u..0x067Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF12Cu, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF13Bu, 0x0000u, 0x0000u, 0x0000u, 0xF13Fu, + 0x0000u, 0xF1ADu, 0xF145u, 0xF143u, 0xF1BBu, 0xF147u, 0xF1BAu, 0xF141u, + 0xF14Au, 0xF1A9u, 0xF14Cu, 0xF14Eu, 0xF151u, 0xF154u, 0xF157u, 0xF158u, + 0xF159u, 0xF15Au, 0xF160u, 0xF162u, 0xF164u, 0xF166u, 0xF168u, 0xF169u, + 0xF16Au, 0xF16Eu, 0xF172u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, + 0xF15Fu, 0xF175u, 0xF178u, 0xF17Au, 0xF17Cu, 0xF17Eu, 0xF1E1u, 0xF1A4u, + 0xF1A5u, 0xF1ACu, 0xF1A8u, 0xF1C7u, 0xF1C8u, 0xF1CBu, 0xF1C4u, 0xF1C5u, + 0xF1CAu, 0xF1C9u, 0xF1C6u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, + 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0xF100u, 0x0000u, + 0xF130u, 0xF131u, 0xF132u, 0xF133u, 0xF134u, 0xF135u, 0xF136u, 0xF137u, + 0xF138u, 0xF139u, 0x0000u, 0xF15Eu, 0xF15Eu, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x2000u..0x207Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF10Cu, 0xF10Du, 0xF10Eu, 0xF10Fu, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF13Cu, 0xF13Eu, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0xFE80u..0xFEFFu */ + 0x0000u, 0xF145u, 0xF146u, 0xF143u, 0xF144u, 0xF1BBu, 0xF1BBu, 0xF147u, + 0xF148u, 0xF1BAu, 0xF1AFu, 0xF1AEu, 0xF1AEu, 0xF141u, 0xF142u, 0xF14Au, + 0xF14Au, 0xF149u, 0xF149u, 0xF1A9u, 0xF1AAu, 0xF14Cu, 0xF14Cu, 0xF14Bu, + 0xF14Bu, 0xF14Eu, 0xF14Eu, 0xF14Du, 0xF14Du, 0xF151u, 0xF150u, 0xF14Fu, + 0xF14Fu, 0xF154u, 0xF153u, 0xF152u, 0xF152u, 0xF157u, 0xF156u, 0xF155u, + 0xF155u, 0xF158u, 0xF158u, 0xF159u, 0xF159u, 0xF15Au, 0xF15Au, 0xF160u, + 0xF160u, 0xF162u, 0xF162u, 0xF161u, 0xF161u, 0xF164u, 0xF164u, 0xF163u, + 0xF163u, 0xF166u, 0xF166u, 0xF165u, 0xF165u, 0xF168u, 0xF168u, 0xF167u, + 0xF167u, 0xF169u, 0xF169u, 0xF169u, 0xF169u, 0xF16Au, 0xF16Au, 0xF16Au, + 0xF16Au, 0xF16Eu, 0xF16Du, 0xF16Bu, 0xF16Cu, 0xF172u, 0xF171u, 0xF16Fu, + 0xF170u, 0xF175u, 0xF175u, 0xF173u, 0xF174u, 0xF178u, 0xF178u, 0xF176u, + 0xF177u, 0xF17Au, 0xF17Au, 0xF179u, 0xF179u, 0xF17Cu, 0xF17Cu, 0xF17Bu, + 0xF17Bu, 0xF17Eu, 0xF17Eu, 0xF17Du, 0xF17Du, 0xF1E1u, 0xF1E1u, 0xF17Fu, + 0xF17Fu, 0xF1A4u, 0xF1A3u, 0xF1A1u, 0xF1A2u, 0xF1A5u, 0xF1A5u, 0xF1ACu, + 0xF1ABu, 0xF1A8u, 0xF1A7u, 0xF1A6u, 0xF1A6u, 0xF1C0u, 0xF1C1u, 0xF1BEu, + 0xF1BFu, 0xF1C2u, 0xF1C3u, 0xF1BDu, 0xF1BCu, 0x0000u, 0x0000u, 0x0000u, + }, +}; + +static inline hb_codepoint_t +_hb_remap_arabic_pua1(hb_codepoint_t codepoint) +{ + if (hb_in_range (codepoint, 0x0000u, 0x007Fu)) return _arabic_table_pua1[0][codepoint]; + if (hb_in_range (codepoint, 0x0080u, 0x00FFu)) return _arabic_table_pua1[1][codepoint - 0x0080u]; + if (hb_in_range (codepoint, 0x0600u, 0x067Fu)) return _arabic_table_pua1[2][codepoint - 0x0600u]; + if (hb_in_range (codepoint, 0x2000u, 0x207Fu)) return _arabic_table_pua1[3][codepoint - 0x2000u]; + if (hb_in_range (codepoint, 0xFE80u, 0xFEFFu)) return _arabic_table_pua1[4][codepoint - 0xFE80u]; + return 0; +} + +static const uint16_t _arabic_table_pua2[][128] = { + { /* 0x0000u..0x007Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF220u, 0xF221u, 0xF222u, 0x0000u, 0x0000u, 0xF225u, 0x0000u, 0x0000u, + 0xF228u, 0xF229u, 0xF22Au, 0xF22Bu, 0xF25Eu, 0xF22Du, 0xF22Eu, 0xF22Fu, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0xF23Au, 0xF23Bu, 0x0000u, 0xF23Du, 0x0000u, 0xF23Fu, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF25Bu, 0x0000u, 0xF25Du, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x0080u..0x00FFu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF223u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF224u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF226u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF227u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x0600u..0x067Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF22Cu, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0xF23Bu, 0x0000u, 0x0000u, 0x0000u, 0xF23Fu, + 0x0000u, 0xF2D5u, 0xF245u, 0xF243u, 0xF2DAu, 0xF247u, 0xF2D9u, 0xF241u, + 0xF24Cu, 0xF2D1u, 0xF250u, 0xF254u, 0xF258u, 0xF260u, 0xF264u, 0xF265u, + 0xF267u, 0xF269u, 0xF26Bu, 0xF270u, 0xF274u, 0xF278u, 0xF27Eu, 0xF2A2u, + 0xF2A3u, 0xF2AAu, 0xF2AEu, 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, + 0xF25Fu, 0xF2B2u, 0xF2B6u, 0xF2BAu, 0xF2BEu, 0xF2C2u, 0xF2C6u, 0xF2CAu, + 0xF2CBu, 0xF2D4u, 0xF2D0u, 0xF2E7u, 0xF2E8u, 0xF2EBu, 0xF2E4u, 0xF2E5u, + 0xF2EAu, 0xF2E9u, 0xF2E6u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, + 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0xF200u, 0x0000u, + 0xF230u, 0xF231u, 0xF232u, 0xF233u, 0xF234u, 0xF235u, 0xF236u, 0xF237u, + 0xF238u, 0xF239u, 0x0000u, 0xF25Eu, 0xF25Eu, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0x2000u..0x207Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF20Cu, 0xF20Du, 0xF20Eu, 0xF20Fu, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF23Cu, 0xF23Eu, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0xFBD0u..0xFC4Fu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF202u, 0x0000u, 0xF21Du, 0x0000u, 0x0000u, 0x0000u, 0xF203u, 0x0000u, + 0xF21Eu, 0x0000u, 0xF204u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0xF29Fu, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF212u, + 0xF213u, 0xF214u, 0xF205u, 0x0000u, 0xF21Cu, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF206u, 0x0000u, + }, + { /* 0xFC50u..0xFCCFu */ + 0xF21Fu, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF2EFu, 0x0000u, + 0xF2ECu, 0xF2EDu, 0xF2F0u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0xF215u, 0x0000u, 0x0000u, 0xF292u, 0x0000u, 0x0000u, + 0xF216u, 0x0000u, 0x0000u, 0xF293u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF295u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0xF217u, 0x0000u, 0x0000u, 0xF294u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF280u, 0xF281u, 0xF282u, 0xF296u, + 0x0000u, 0xF283u, 0xF284u, 0xF285u, 0xF297u, 0x0000u, 0x0000u, 0x0000u, + 0xF29Au, 0x0000u, 0xF29Bu, 0x0000u, 0xF29Cu, 0x0000u, 0x0000u, 0x0000u, + 0xF218u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0xF286u, 0xF287u, 0xF288u, 0xF29Du, 0xF21Au, 0xF289u, 0xF28Au, + }, + { /* 0xFCD0u..0xFD4Fu */ + 0xF28Bu, 0xF29Eu, 0xF28Du, 0xF28Eu, 0x0000u, 0xF298u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0xF28Fu, 0xF290u, 0xF291u, 0xF299u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF219u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0xF27Bu, 0xF27Du, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0xFD50u..0xFDCFu */ + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0xF210u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, 0x0000u, + }, + { /* 0xFE80u..0xFEFFu */ + 0x0000u, 0xF245u, 0xF246u, 0xF243u, 0xF244u, 0xF2DAu, 0xF2DBu, 0xF247u, + 0xF248u, 0xF2D9u, 0xF2D8u, 0xF2D6u, 0xF2D7u, 0xF241u, 0xF242u, 0xF24Cu, + 0xF24Bu, 0xF249u, 0xF24Au, 0xF2D1u, 0xF2D2u, 0xF250u, 0xF24Fu, 0xF24Du, + 0xF24Eu, 0xF254u, 0xF253u, 0xF251u, 0xF252u, 0xF258u, 0xF257u, 0xF255u, + 0xF256u, 0xF260u, 0xF25Cu, 0xF259u, 0xF25Au, 0xF264u, 0xF263u, 0xF261u, + 0xF262u, 0xF265u, 0xF266u, 0xF267u, 0xF268u, 0xF269u, 0xF26Au, 0xF26Bu, + 0xF26Cu, 0xF270u, 0xF26Fu, 0xF26Du, 0xF26Eu, 0xF274u, 0xF273u, 0xF271u, + 0xF272u, 0xF278u, 0xF277u, 0xF275u, 0xF276u, 0xF27Eu, 0xF27Cu, 0xF279u, + 0xF27Au, 0xF2A2u, 0xF2A1u, 0xF27Fu, 0xF2F1u, 0xF2A6u, 0xF2A5u, 0xF2A3u, + 0xF2A4u, 0xF2AAu, 0xF2A9u, 0xF2A7u, 0xF2A8u, 0xF2AEu, 0xF2ADu, 0xF2ABu, + 0xF2ACu, 0xF2B2u, 0xF2B1u, 0xF2AFu, 0xF2B0u, 0xF2B6u, 0xF2B5u, 0xF2B3u, + 0xF2B4u, 0xF2BAu, 0xF2B9u, 0xF2B7u, 0xF2B8u, 0xF2BEu, 0xF2BDu, 0xF2BBu, + 0xF2BCu, 0xF2C2u, 0xF2C1u, 0xF2BFu, 0xF2C0u, 0xF2C6u, 0xF2C5u, 0xF2C3u, + 0xF2C4u, 0xF2CAu, 0xF2C9u, 0xF2C7u, 0xF2C8u, 0xF2CBu, 0xF2CCu, 0xF2D4u, + 0xF2D3u, 0xF2D0u, 0xF2CFu, 0xF2CDu, 0xF2CEu, 0xF2E0u, 0xF2E1u, 0xF2DEu, + 0xF2DFu, 0xF2E2u, 0xF2E3u, 0xF2DCu, 0xF2DDu, 0x0000u, 0x0000u, 0x0000u, + }, +}; + +static inline hb_codepoint_t +_hb_remap_arabic_pua2(hb_codepoint_t codepoint) +{ + if (hb_in_range (codepoint, 0x0000u, 0x007Fu)) return _arabic_table_pua2[0][codepoint]; + if (hb_in_range (codepoint, 0x0080u, 0x00FFu)) return _arabic_table_pua2[1][codepoint - 0x0080u]; + if (hb_in_range (codepoint, 0x0600u, 0x067Fu)) return _arabic_table_pua2[2][codepoint - 0x0600u]; + if (hb_in_range (codepoint, 0x2000u, 0x207Fu)) return _arabic_table_pua2[3][codepoint - 0x2000u]; + if (hb_in_range (codepoint, 0xFBD0u, 0xFC4Fu)) return _arabic_table_pua2[4][codepoint - 0xFBD0u]; + if (hb_in_range (codepoint, 0xFC50u, 0xFCCFu)) return _arabic_table_pua2[5][codepoint - 0xFC50u]; + if (hb_in_range (codepoint, 0xFCD0u, 0xFD4Fu)) return _arabic_table_pua2[6][codepoint - 0xFCD0u]; + if (hb_in_range (codepoint, 0xFD50u, 0xFDCFu)) return _arabic_table_pua2[7][codepoint - 0xFD50u]; + if (hb_in_range (codepoint, 0xFE80u, 0xFEFFu)) return _arabic_table_pua2[8][codepoint - 0xFE80u]; + return 0; +} + +#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */ diff --git a/src/hb-ot-shaper-arabic-table.hh b/src/hb-ot-shaper-arabic-table.hh index 73b4b84fc..4c6aecfd8 100644 --- a/src/hb-ot-shaper-arabic-table.hh +++ b/src/hb-ot-shaper-arabic-table.hh @@ -418,21 +418,108 @@ static const struct ligature_set_t { struct ligature_pairs_t { uint16_t second; uint16_t ligature; - } ligatures[4]; + } ligatures[14]; } ligature_table[] = { + { 0x0651u, { + { 0x064Cu, 0xFC5Eu }, /* ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM */ + { 0x064Eu, 0xFC60u }, /* ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM */ + { 0x064Fu, 0xFC61u }, /* ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM */ + { 0x0650u, 0xFC62u }, /* ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM */ + }}, + { 0xFE91u, { + { 0xFEE2u, 0xFC08u }, /* ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM */ + { 0xFEE4u, 0xFC9Fu }, /* ARABIC LIGATURE BEH WITH MEEM INITIAL FORM */ + { 0xFEA0u, 0xFC9Cu }, /* ARABIC LIGATURE BEH WITH JEEM INITIAL FORM */ + { 0xFEA4u, 0xFC9Du }, /* ARABIC LIGATURE BEH WITH HAH INITIAL FORM */ + { 0xFEA8u, 0xFC9Eu }, /* ARABIC LIGATURE BEH WITH KHAH INITIAL FORM */ + }}, + { 0xFE92u, { + { 0xFEAEu, 0xFC6Au }, /* ARABIC LIGATURE BEH WITH REH FINAL FORM */ + { 0xFEE6u, 0xFC6Du }, /* ARABIC LIGATURE BEH WITH NOON FINAL FORM */ + { 0xFEF2u, 0xFC6Fu }, /* ARABIC LIGATURE BEH WITH YEH FINAL FORM */ + }}, + { 0xFE97u, { + { 0xFEE2u, 0xFC0Eu }, /* ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM */ + { 0xFEE4u, 0xFCA4u }, /* ARABIC LIGATURE TEH WITH MEEM INITIAL FORM */ + { 0xFEA0u, 0xFCA1u }, /* ARABIC LIGATURE TEH WITH JEEM INITIAL FORM */ + { 0xFEA4u, 0xFCA2u }, /* ARABIC LIGATURE TEH WITH HAH INITIAL FORM */ + { 0xFEA8u, 0xFCA3u }, /* ARABIC LIGATURE TEH WITH KHAH INITIAL FORM */ + }}, + { 0xFE98u, { + { 0xFEAEu, 0xFC70u }, /* ARABIC LIGATURE TEH WITH REH FINAL FORM */ + { 0xFEE6u, 0xFC73u }, /* ARABIC LIGATURE TEH WITH NOON FINAL FORM */ + { 0xFEF2u, 0xFC75u }, /* ARABIC LIGATURE TEH WITH YEH FINAL FORM */ + }}, + { 0xFE9Bu, { + { 0xFEE2u, 0xFC12u }, /* ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM */ + }}, + { 0xFE9Fu, { + { 0xFEE4u, 0xFCA8u }, /* ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM */ + }}, + { 0xFEA3u, { + { 0xFEE4u, 0xFCAAu }, /* ARABIC LIGATURE HAH WITH MEEM INITIAL FORM */ + }}, + { 0xFEA7u, { + { 0xFEE4u, 0xFCACu }, /* ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM */ + }}, + { 0xFEB3u, { + { 0xFEE4u, 0xFCB0u }, /* ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM */ + }}, + { 0xFEB7u, { + { 0xFEE4u, 0xFD30u }, /* ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM */ + }}, + { 0xFED3u, { + { 0xFEF2u, 0xFC32u }, /* ARABIC LIGATURE FEH WITH YEH ISOLATED FORM */ + }}, { 0xFEDFu, { + { 0xFE9Eu, 0xFC3Fu }, /* ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM */ + { 0xFEA0u, 0xFCC9u }, /* ARABIC LIGATURE LAM WITH JEEM INITIAL FORM */ + { 0xFEA2u, 0xFC40u }, /* ARABIC LIGATURE LAM WITH HAH ISOLATED FORM */ + { 0xFEA4u, 0xFCCAu }, /* ARABIC LIGATURE LAM WITH HAH INITIAL FORM */ + { 0xFEA6u, 0xFC41u }, /* ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM */ + { 0xFEA8u, 0xFCCBu }, /* ARABIC LIGATURE LAM WITH KHAH INITIAL FORM */ + { 0xFEE2u, 0xFC42u }, /* ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM */ + { 0xFEE4u, 0xFCCCu }, /* ARABIC LIGATURE LAM WITH MEEM INITIAL FORM */ + { 0xFEF2u, 0xFC44u }, /* ARABIC LIGATURE LAM WITH YEH ISOLATED FORM */ + { 0xFEECu, 0xFCCDu }, /* ARABIC LIGATURE LAM WITH HEH INITIAL FORM */ { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */ { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */ { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ }}, { 0xFEE0u, { + { 0xFEF0u, 0xFC86u }, /* ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM */ { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */ { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */ { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ }}, + { 0xFEE3u, { + { 0xFEA0u, 0xFCCEu }, /* ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM */ + { 0xFEA4u, 0xFCCFu }, /* ARABIC LIGATURE MEEM WITH HAH INITIAL FORM */ + { 0xFEA8u, 0xFCD0u }, /* ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM */ + { 0xFEE4u, 0xFCD1u }, /* ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM */ + }}, + { 0xFEE7u, { + { 0xFEE2u, 0xFC4Eu }, /* ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM */ + { 0xFEE4u, 0xFCD5u }, /* ARABIC LIGATURE NOON WITH MEEM INITIAL FORM */ + { 0xFEA0u, 0xFCD2u }, /* ARABIC LIGATURE NOON WITH JEEM INITIAL FORM */ + { 0xFEA4u, 0xFCD3u }, /* ARABIC LIGATURE NOON WITH HAH INITIAL FORM */ + }}, + { 0xFEE8u, { + { 0xFEF2u, 0xFC8Fu }, /* ARABIC LIGATURE NOON WITH YEH FINAL FORM */ + }}, + { 0xFEF3u, { + { 0xFEA0u, 0xFCDAu }, /* ARABIC LIGATURE YEH WITH JEEM INITIAL FORM */ + { 0xFEA4u, 0xFCDBu }, /* ARABIC LIGATURE YEH WITH HAH INITIAL FORM */ + { 0xFEA8u, 0xFCDCu }, /* ARABIC LIGATURE YEH WITH KHAH INITIAL FORM */ + { 0xFEE4u, 0xFCDDu }, /* ARABIC LIGATURE YEH WITH MEEM INITIAL FORM */ + }}, + { 0xFEF4u, { + { 0xFEAEu, 0xFC91u }, /* ARABIC LIGATURE YEH WITH REH FINAL FORM */ + { 0xFEE6u, 0xFC94u }, /* ARABIC LIGATURE YEH WITH NOON FINAL FORM */ + }}, }; diff --git a/src/meson.build b/src/meson.build index bca289dc5..b7c11cdf6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -137,6 +137,7 @@ hb_base_sources = files( 'hb-ot-post-table.hh', 'hb-ot-shaper-arabic-fallback.hh', 'hb-ot-shaper-arabic-joining-list.hh', + 'hb-ot-shaper-arabic-pua.hh', 'hb-ot-shaper-arabic-table.hh', 'hb-ot-shaper-arabic-win1256.hh', 'hb-ot-shaper-arabic.cc', diff --git a/test/shape/data/in-house/fonts/SimpArabicTest.ttf b/test/shape/data/in-house/fonts/SimpArabicTest.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d560f6a385fedbb4ea2a8251802cd3cd8eece445 GIT binary patch literal 17168 zcmbt+2Yj2w-T&RAnMIcDxcN&TtYZapJ^D?2tHNBqWRiZOR^P zXR04;5ylT}(uDK7yU0>twBy?Z1_cI*)N+de(dbI;xV_V0f8 zyORkegd~syL_#cGy(R9Up3gLd&|K7ZuHQDiBe8b)c|xRkru#OHO>Nw-x(v?>ye_NX zJTkoDy@yL)z{7ng{>`X}e?$5S?*E38vw7R(-r-x*j-c;eLWBp$#@7#D_R^kv2$9`| zx)s}o_wJw`)|SShy=D9Gwvn>8L#c$+G@^a-j`4}fTiPyZAf&DjZ5}2JSCsub$(A+B zs{fEI){T(+-(Blw*S{FAXqzdXUMlOAOYs;-1Xhb5^pUNe&SX_H#WTgSUOtlePW-%& z*W5?e5-F(xF9bBL1z!l+iXxzf2+Qc#i3}roWVd3-Oz|ptnQRn*@!~(BuCCAzYEO_8 zuZuXyRts-nl>5mF)`u2}g;Bx^y@J)wyoYjQ?GQg<>ThJbTF7Gbe?I&{jM5DoF6W5pWNq zEOJj@1WqXA{h3#QYj*@^BLyAg*vv`t$;>Mf`? zW}TqN`}xl;csDq6Qu1xQV^_4H|3MvaC$HezhUaNqoALZ6-p8So;&~a`GoJk!MT5Gh zflElNWACER^c}pf65oS|E|fu(Qj{VTElLea0HqLxy?3*5*to(SX!CQFGglp+b>f5%HT&WdbR=3lFHjRqsV`OtA@n>T1hqOhi78HSCZSwqvVg|KU7Jp=m6bGzfSL_ z|3iOH|3v>qKNh5dRtO4*g~x^Gg?~z^Zqi9+F=#e_m0fIG{MHI2BhFw>R$P_=5Og{EqmmU&p_d zph~DsIGFHyVo&0p#P21(l~k0}n{;*3gGnDH2a^vcKa!$K*_HCsl#i7j<%IGvRhp_s zb&2X))kCWH)DCrv`ZD!1>i1F&sm-ZVsh_5eru`u8Q_Ya(KFw=dt@c*!&$NHm#p#-K zTXf&h{aN>(zD9pg|DmDDFl@NU@UY>OF<{(d{IT(rNoMky22C4Gx0!xwI&ON&^s4D! zrjN}MbBftywwVjfK6AA>WbQT(n%9}PnkUT{nJ+gVG2deTce<5p6#THP7yeknrZtb+ zs&=BRkbbh_vqxn2f7*+?&+vl6Cl8WTNioyjs5}dVOyXyYK1M*GINx?POFjIvK@Dp8@Ep8n2dJ2(UkKGfliOvGc)Zu77MemI{F-4 z#(RS7G>J`OMfr{qm(pL@j~&ZFXMO=qnD2!| z_(UeNM6kv~ZD}5@jk5B1M|iTMbaa#^jgAU;Os^K!j)s3W${a~8IZQtls(BACo(Qz( z+(++qAN#KN-lN`og=){yqn>;3^&Gv|dyGSx65@pr`Y4GRgJe5=QAWyqR;?oDnP%v% zR=wV00e4=0H*!y(&#+{hOxc!H!>1_^2Zm7Mt zDHIC!w1;TwzBgB{eq+z%tE-p4iawd>BNh8lja*^#`+Z)A)1%W-X{fy?7z#D@vQAU4 zE?@oXz;kK8GrO}==tYE2m&deCE$rzAQSL& ziWIiGl*04|r6FNB(YL#{c3&lHmrLHFCPaR)q=3((&Hdo5&Q4a(b(TyqNP#Gmp{>n1 zMw8ucGUoVawUjc8pV=;q`<( z#x)1^YTJgvL8c?D2aCiW#T(2yX^^Zn%~nK@gn#{;wZh8K(&-1p7J>yWve=k}Lo!T2PNF;}S^Z0@bJ>CEZLH>?rvxLM|Kc6nM%a$8P+ z%C1d%T|&5mVbDKwl0Ggx0R9kJw$s5h%^z^$!nmoID^dh#hz>VgRRCTqr|D%S#qQ#6 zk7vYc-4QZp=V^UTOKbHWt;SeevOZ9qpj3LZ46S|6yzb1*{QNe3dxAd6o*gH*RD1Rr zbonV7v$j>o?6D3Jjz&0!na0lGGw6WpaqBYymcewop>06RmMvmJ^Y(35sjORS>%BQ1 zb8?bleScehT3Vem#{%v(BwTSt*{FNNj&jHDtD8$YGONlu)(x-gUOG^exn`njcpak{ zKlBJViny9ueO9%N`oqWRkwIbUQV4|t7Xr<_gCxN-OFU^H-s2CXc_c4BIy9A_l+mQr zsa23>*l(|~)HTrKq9kK_rFqh95{JWSlPe^)7snr4H5IRt(FD!Z5EDB+ZfndaZwvbw z{a7E+XNCI!3+$lKyNIEyZ4xgd8s_Pt6Fax<*}7uySRd6bsq$5QjV5m&SvCHRqv2cW z%C5=UhN{CDN%XxA=&_#L_N?DkFQnB`?WS)yGBX`;!r{HMdd{Un{w{or#FI3P#jGkt zP}tJ4qh6>(RbXz2OH<2+3#xNWrX2di%H0*#p%t0o&PI%t(+Dmm(ch6fVHWW*BP6Ai z8tURTD%l$Pn(u(mv8>+)%*)6h1cCm8`&DiQ%*U0{<6%ENPQMchJsS$m8&3`|R4oKN zcP6_GbqQ%IEN`Ch9*mAxH}e7giSS$S7CIdO8=b`h$6T+7uoNPNeraub#&3@snl_!3 zW3w0QHm&Mkot533@2g15&9LUAG-jA`s;ez8r91Potbrv3ed}BywXw`)E6q2hy8@2X zS3qo|C5LNO3D!B+GTXO9tLUp?l#+FLvjGbC7(5~O3ZnI&nufdLZ)g+VfJb(>R;#gL zCRWornd~ovozkF8I5j;0{uHABza@_l14#!j1EPw67OovSJSqP9w z3-N?ck&hrXGxN#%0C$=2SP_Bfs|AlX8}`CHy{9Ba>o1K+BvVmPC{OfO2a;WbgMU=S zTXgxQTqYK!AeXshad8qUfno>@0@n*O^NNc@ptCx&2ppQiRB2&QbYND)W=_tOkyo+e zjwf0|Y}q~-g$J4#8)wL5vcrQeQ)Z^goRJ|5O6kpE^K)4l8Ch1d86hq68D+vl7(>Oh z)FXOw4~s55RtzP&cF`xD9vDeU>{fd7>8AehyOAL`udpu5Yz_q)=MIcjG&E<2@F@3d z0F*ZCA~kXmia02p#rkR%1Yy+cBO{0Jk;$GM6dKblmUM=26zSk;MDP_{b!T`AIoI)e!EE-C=0gR3YNR8 z^7BiQQ|yLWt$hyicU-$Hm>W#j>U8}*gTuOZrpZO&CxjgwDzqY2aqaL^@U)RYh($+; zyWoxyvA_#BnM01n#Ur{JS{T8IW(AgJRIawvSGRTlkRZjX5?0M6Yl`}t1!V~)EGWW- z1cz8UA~zo))-NR~VdEDQ(0PkR#EnU%AY$L=Cx_|tWPkXH^I|*ZNzQlfO<_^7o<{U2 z3rgYRs73vA5pf8OQBCDOby1t*aA8w(;eHvLilRjOzL>;fF+FeTi5{VWV-K5(#h&}X z^OI#1W$k&&^bD$}_n)71#nt4CLN;5u1h^=j0p=2|MYJP9pFZ4bnYh*zUe(!B+kLUC zz3ScXwKIPKZ~vlj57DDM0rbBhyfdH3M=$GK9if6k7V)Ygb)$ zyJU0obS_%375G+h1)hc#_*$B{EPOJu0H?$_vyOZs_GjU+55;)ZRj<7^AiUCi`W6PE zZsro?EhkyTjX*8nfeTmE#igZ6hZV{BSqHOMuE##wyMc~B;M zNG4;^Ih+uj7^n0Tt{d=WbNDxx?w>|Dc>5XpV?_L`IjrFRQDOxD5b=n<%x0Ypa2P9* z!9a8jwz4=)xT2^%SJ&bRe^(|u(mz(}@2AGf;wAl=xmivYZ(l}{hHphU+Jrd(=+!KUwV&?b7Vh->ZGw`{1 zLI1c&5K_4?kA!nYNQ*KMyAO3U;NUF&yYe>D}Eu zZHIgioNzR(W6WfNyW}8NMbWVmvDRITlj?aR)3>9X)SU(63>BQ2^Wbr>hs^%}B1;g} zx5(mJ$5+?fD=~$;&EmXtte{12uJM1ZG4KPRZeCr!^I~;Uo9XV(wVe^&9TH@~x;WzD z;N1AS)*V2k?%+!Xou21W#W3B@f_P*Zk=A}Af4F#Xcv2>t2$eeWa?9caUkTM5C|%oE z7MPOB!Y_5S$(maG`<1;$qZ_a_=|10--&2`u-TdPUEoO!z-ivzd6~T*`=Cha-coY#t z4tgjG@8%=9xM+Wiyu`Fj~^VY8*dV2(A;TF?^|wI-qaLq>trh%tO!_0 zx}(2iU-O8ciKQdt9WdsZTXi`(J%x3ZSjMn*0FOuM@459L(-AuZL@ady`BQ6D!Jarv z6Xq${T&)m2!;tVd%;}|sCBI{496qyr0UgPRAaV43bwwDPjg@ZrJiUQe;d;X`Ehi0g zF~y$Rm(U^_&E35BMb#+=am^RdEUx?X9WGm}$YOadM$ODOex9C1k*@q)eLEw07A}9T z=81Wwk2rQ_f}CM2ezCgeM}*}>9LX~A)F0KnqcYhoMsvgdzC%A;T`;)*3~=t(GJ0}5 zCu+jxPTI1n?-nBJ-FgnoI%{X#ZEECV4lfeiiMua=h>cb;^b{%Btd`{49BwwrpHE}V++>{v?2G^w-iQF6o|#SF1oat= z;(4&AADzwGn0oVL>EAkwXe2ZR>H#>bvm>*EpjVqExSUXBfXIGYz|rP>zc36I+( zdd?F)@scHTxe|*L*NB+O+b2fHOd&M3G?7m_k6@gKT)1QVC3(Hs16{}04GfL%ZoIJP z(DXeJS7Y$(6y)h&T{?cz_?j!0E^qHr>>lr)s19r2q18-$oh{-Tg#HJ6@5q^pvlpMf zZ9Ys4_|vCI6fAC1voy)wD^?#>6{VM7Q*S9=)l;KhcIYZ7#829qda~=SbsLTCspY{| z+t`Nizu2rqShkbJ2*^ipnj>_wR4qMghk<3Z0qgY2wZ=B3ub8E6N7+7rBVDP@U^@+Q zdHM00%F2?sRRh8LrV4k3aCAD3j$qdzlHta#150sJMVwrStgT)V_dRCgN=C)uLEy~# ziYpYM4Q;S57TFh!jTo_zw9O3>_a2N53x&_7lcx5AOrBp2(?4MxWIQ6!#GDETA&wc^+P1-_teoVO^bPgq zH)%rg3h(!8y7j4AY}GKo_oUDah(???U~|656AMpUsx7rfnOmWia|lNhG8Lxs0mi^R_>J`Gb9g0 zm=Tw#^U#{Tm%{E2uD^5NwyvGkHQ{`W2wy+c+t$V9&-SztQ7PGYTz6ru z*dWregD_6F$WJz%l-e72Y-SLyY&2^}0@84|f#JL9p$AwtpMtp`ICSB()BY?Bu^TY`8%exjAb!R+={tv45=I zs!r`yB{kGMT-sXD>T1cg*~S7kqp3K%+OD*uff`wUXI?^HNrow1Tbyew&ak_cOTshZ z=J~Wdcj>sduQ0#Mw{*EN&*0Q4GhBJ)0bfH>Qi*># zUCZ+H?!u&;WWQQlm{wHXX7{SpGo$@~X?enz)#~@Zqz;QT zFdd%VTZ*yN^VHKbSbx4=#vpn=TFCJGm_9{sWj+iJgHI=--6jq`|}b-ovv7$ zj?*ivszYv_yQE@?EnU~XN~P&ov$jK1D~pq)wH8(u78GZ+nU+*KmZV4$;+HBClatsk z8;>fgBrL~ru5%M-CgA-GoSQhn_oc@dIGZv3M8uPdo*!ECDIl$ZO`R2+F=~**7L6@N z7+=P1-n0OclV4WH=!%61``ee)Jb}0{t0v;)Yck6Y;T)no8jiblGQM#s&Z|OV>E?l{ ziIUCzdoKuI+_1De80=o!KsQd@z5HkQPu{icr{BB&x@&K^?z-zR2pPo3dh8cqzr980CmH8NN>yw-m`b`h|1 z1L`Cgm#xx}l)`>A8;i|vK5_2^p(*w=*kL&C`o$y?{dafcKwrhwnzFTpMVm|4_K&U! zHZ5P-R8`TFTjkofyM?zp3kz8pj0)UXrPj(^DPV@5FP_Jc^AgD3 zvNpNAxO+3?vvc!~1C7^QzO=uw+gW8P=nsHK7T_mBW8_#jvBQH}dL^}oFTrWAzY6=h z8>jbSo@bhxz;z^-t$8U&O0M818Y4;@iF5UAkW#G^*-@!f%)N7Sy`Zw7w?SiqVmku4Zp)W`BL4 zEjQ$I+ub&muG;VRg>${ZV89zR$lf_hiXy;QPDhZY>7eO5hPit;p7-X z@0j8_ggA5P;E2YjcDkBY`VE3y*IPHVvwUN)aeM6t)m;rurJRwsGDgZ|ZOO%5qZQe% zotxUmDuP#E-qY9EFCi?9~R?fme@P z+^Mx$i(Wgp>Y#bc;7DKi_D;bz{g+9>KmB;`dhW5%>jm^uM$axU*M2&!fR2; zk%ZhVF$;kfE;~cuBB0rlkb&o93oMHvAo|DL#b9$!#g;Mi&p*y1Tes*@NL?)PkIp|6 zIepz+${F+*ICNzB7l%Hd^u@soSHv)20r2yvFABfNHO$QBH*lV%9v3(|?U#m!X z=N(DSGXHYeLxLoUmP-DOlh!y3p2k-8IAbp|2$LDscnDa@}VAYs;;mkRbx)`4q$kR zW4OkjX)IpeXihU_wDt~Xx(TBv{2uve=0cT%(ev5gdCf(Unrl(B8#O9G?2_IBny;4= z-qKA4)=~)57U?fpJ$VK7M}Xa5S-m6<^{?>yH&A~q;>BM_+HaBmYPS7#X#Xm&zZw*M z%IlLDPko1Ytp}s%cx^5prEsQz)l0qPBk5Bd4?+uhO&Kkf894^gnj!KJSutw94wi{+ z&`ajw<3wx9=qT^Sf?%;t4{ec|(B}GR&Gb{`qi{EBz@1MYX0WE0Mry#FPg_ufALD$Cnww{9ytG9wMa?a=bI)H<~$g$&b;?ftuT9Yu2Eq9yQ-! zH7vV;qq2vkS+E~VBx{e;K`b}5s2Yfi{m7yolM?&2&t~oaP+snG7I;;LsG<}b4B^$0 zwf(z;rw6CiJi{l=y8B&sNsZr}4*fA{jG0`2rgueG_=0BoU6k9S=|3LVAaBi15@Tf; zn{klf+ck(<&dOppM{=`+9iA3!95mFh!!&yj(zj;!3k!;B5AWI7cWCKy9Hn_XoW&B` z_(>t(gC2=LII|nMr>OTv?ggBr!Z-eS6A9MD*i+#5(wH_fV7etzFX#0VLZvt#MK+V& z;5WOcIMe-?$i09zpG58@q@F4w_tKa)GNQxxsl~o>R^KqbV`|svrp=QUcd4tq$X)7o zSwiFEo5n^g?d=W4mb$SqOAmWLVd)u}7}<5f$cEzH(QP~Gb`7r^UEen{G1)V+Y4_Oh zuDY?&jg|__+;^yOl@$f}umdBzCPv4%TU^DZ*f zzPpR3^`sB)CIGPq*G*vL7~bsSBaV`d7^MQ`T>ZorE`*Kj=)f6l2RP&jz!)dnF@_89 zu_$Gpp8tdk$XfAk-sgRIrf4OBHOYva3RFU+lu17cYw8rlaVliMQ!x)|up-nUXJ$aO zVuH6#$Np0$^3E1$P&W2TbC9cdAbQJ1RxKYhY9Y`oMuf{4>&7?oy;$}5fpi(zTtO;H z6?WOG@gELqL4G}0+em_>2~2N>KDLrJu)722?7B!dSqgUbf_435fGorJy9e?A3RaRK zvI-gFHK1#l%As#hlm8|^C&$R8)<7om-q)FsQk$4g$%xRUx0m-DYmbh*fG3*gpmIONQR}x literal 0 HcmV?d00001 diff --git a/test/shape/data/in-house/fonts/TradArabicTest.ttf b/test/shape/data/in-house/fonts/TradArabicTest.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a82ed35759c35a0c6a8e6cf25274d260d7d4ea84 GIT binary patch literal 58132 zcmdqK4}25XkvP8lcJ;Jguh*;9O6x_)Ldfz)Q4}GBEQBxy;~3*Oj^jFx<2sIU9LIq; z4l%AnsY_jsa+Fd^2??cyq$%Yn$8nTWN(rG!C`T#HaWu!5UoIuNG);49{xnBZnlG_e zzj-S=!44P~OqpeRcN9IL+XfyJ#o-rh!v;&xHgzy4R-z4KZ=p0sQsT)P9df;Ko{_gJ5S z@4tsFudRL2Bk~XPUWMO2LQ%}`9_YAdp1+^ZSu`IljrgGZ$Q;5YpKbMH}9)^X!SL&#Wf-f7^Z`EkZPlA>Osu(^-m z*E4}G6t#QsGIlQgEy@D4h+4h_VC1GhnNw6Nk_WH3(C4g*xurjzd4@WZO2feKx7Y!@ zx2Y0xHT_|Fv%F0`$UaAf1~+C!`a1`dAR9%cUWctK{b{^wkyD4vZ5`EY8Q9p?RL$UK zc|3KDY|OsY?yTbg^+BrD^6ymV;70#DJoj~K846RC%xzQ)Y)zKAR5kM?)xqwd7BhEH z^I`i9vxq8YlT;!4Gqn%>H`Rq!QmfE&l!x6(e;>9j>`v-5Y`yT^4WH*=I{@1z*q(yz zEd2ufhWz#~R2|z!Er-uC<`zn|{3-PeeSqo)II8H^fF8F}H_-=-7ts@`b~s)K$2od= z>KOg!)N!jsEwHvxwXnZy*#5KU?^_B}C)w9iM=ay12LP98gZti5lLSg!g zsb|hVKX^U!9jb@<1y%9MXCzgN4yLM^flqc->P6U&bKj#DS^q>W8oqB?pZcZcUsAuw zc$k`(v771{+_&tdb#lzImue!%*_EjmEqTy>7urNPKCrQ;Qile&3tkJq$4;tla3gKZ z^g^4Tw^?3J?Hb(B%c-r=DZ>q<+bUsC$?vsLsJQX5XQ{$gZQl$UKpHn#oN)&u~-^@J%}tP1T?m zQca&+x0C9^e_?!lx zGt$RX@1R;5qgu*5t@>Re4{gTCH`3>&2GS+R}B<|N4 z_hr1x@5{V3^HzZsex3CXVh6l_AikRI%f2uB$JzZ-Olp!=*>Y^9wlCNowe7UMWcxr? zz_MaQ&97x+atF>TC3K!*6y$U=#IPZI97LO-Me=_RL|Bw zSpWOauWp##aP+RvH?ocU8~@MU>fOb6FS`3oQ>5vZrln0U&AWNtp5{B7|LLBbd#2pe zb`=~|KMrtcaoZabEolYzEP0WuMsLptPz7DT= z0RxBOD26?Zt?(iTqm$#4@^zhD6DLy5C!`%ixqfQ#WG3Hq~ zZ=an0g`OY# z`~v*hYYOAjJh7ZuMOf3arJ{8=VlE`wSS%)$EH;ZPo-}zb);tLN0_EYL7*L~;?gl=a z<5kXAR2kw`msN0yN{R6U-gRgOvP-PHSHics$-P~>0;pu-p1XZ^e`{MO>ysTwWf4Lc z3k5m9Ql|OK74L&_6=CLt;fa;2%H;89cldQdkhHJf|Kgf>gSYPwcv@m=0>vWjWp$zl zv5EMUSnG|Ux5}DaG39P|flx8SXuPf35(=}dKEI+4qo~U-xEzu9RR*!VZ!yR1^kJ-( zIe8kL^>|-4_Q)2boq9@keY86kD~KWaB*raPZ?P8buBjb&uT<^}vi_Muc~Q|95)1R} zFR`lZ*EI{9!%qX#lL~$OHoFWRryNusRYP>}K+{+Tny)~GCL#?B4MmzXA6ktjtwRo^ zFD4D{R896tH#!3i50{YUGJn9%MPq@Cm}8~B+5vb$lIY^8a;kFDY?Cyv!ztBlWIuIA-xP?n$mFo;|}jUGpV< zdxyrL*fRR{-HVfV<$59x#3B~6+yGtXS)4$Z2sLjcx)3^~36uUmC=X*rq-R+nP&R?X z&8�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