Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 3 +++ dlls/dwrite/opentype.c | 2 +- dlls/dwrite/shape.c | 3 ++- dlls/dwrite/shapers/arabic.c | 25 +++++++++++++++++++++++-- 4 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 76d49ae5104..4a4229e1dc0 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -543,6 +543,7 @@ enum shaping_feature_flags FEATURE_MANUAL_ZWNJ = 0x4, FEATURE_MANUAL_ZWJ = 0x8, FEATURE_MANUAL_JOINERS = FEATURE_MANUAL_ZWNJ | FEATURE_MANUAL_ZWJ, + FEATURE_HAS_FALLBACK = 0x10, };
struct shaping_feature @@ -575,6 +576,8 @@ extern const struct shaper arabic_shaper DECLSPEC_HIDDEN;
extern void shape_enable_feature(struct shaping_features *features, unsigned int tag, unsigned int flags) DECLSPEC_HIDDEN; +extern void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, + unsigned int value) DECLSPEC_HIDDEN; extern void shape_start_next_stage(struct shaping_features *features) DECLSPEC_HIDDEN;
struct scriptshaping_context diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 20534460d09..256218663fb 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4553,7 +4553,7 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex } }
- if (!found) + if (!found && !(features->features[i].flags & FEATURE_HAS_FALLBACK)) continue;
if (feature->flags & FEATURE_GLOBAL && feature->max_value == 1) diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 53b392c88e2..2dbea825216 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -115,7 +115,7 @@ static DWORD shape_select_language(const struct scriptshaping_cache *cache, DWOR return 0; }
-static void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, unsigned int value) +void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, unsigned int value) { unsigned int i = features->count;
@@ -193,6 +193,7 @@ static void shape_merge_features(struct scriptshaping_context *context, struct s features->features[j].flags ^= FEATURE_GLOBAL; features->features[j].max_value = max(features->features[j].max_value, features->features[i].max_value); } + features->features[j].flags |= features->features[i].flags & FEATURE_HAS_FALLBACK; features->features[j].stage = min(features->features[j].stage, features->features[i].stage); } } diff --git a/dlls/dwrite/shapers/arabic.c b/dlls/dwrite/shapers/arabic.c index d8c6c9495c0..32588b9c796 100644 --- a/dlls/dwrite/shapers/arabic.c +++ b/dlls/dwrite/shapers/arabic.c @@ -18,6 +18,7 @@ */
#include "dwrite_private.h" +#include "scripts.h"
static const unsigned int arabic_features[] = { @@ -30,6 +31,24 @@ static const unsigned int arabic_features[] = DWRITE_MAKE_OPENTYPE_TAG('i','n','i','t'), };
+enum arabic_shaping_action +{ + ISOL, + FINA, + FIN2, + FIN3, + MEDI, + MED2, + INIT, + NONE, +}; + +static BOOL feature_is_syriac(unsigned int tag) +{ + return tag == arabic_features[FIN2] || tag == arabic_features[FIN3] || + tag == arabic_features[MED2]; +} + static void arabic_collect_features(struct scriptshaping_context *context, struct shaping_features *features) { @@ -41,11 +60,13 @@ static void arabic_collect_features(struct scriptshaping_context *context,
for (i = 0; i < ARRAY_SIZE(arabic_features); ++i) { - shape_enable_feature(features, arabic_features[i], 0); + unsigned int flags = context->script == Script_Arabic && !feature_is_syriac(arabic_features[i]) ? + FEATURE_HAS_FALLBACK : 0; + shape_add_feature_full(features, arabic_features[i], flags, 1); shape_start_next_stage(features); }
- shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','l','i','g'), FEATURE_MANUAL_ZWJ); + shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','l','i','g'), FEATURE_MANUAL_ZWJ | FEATURE_HAS_FALLBACK);
shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','c','l','t'), FEATURE_MANUAL_ZWJ); shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('c','a','l','t'), FEATURE_MANUAL_ZWJ);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/opentype.c | 2 ++ 2 files changed, 3 insertions(+)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 4a4229e1dc0..57641680db5 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -544,6 +544,7 @@ enum shaping_feature_flags FEATURE_MANUAL_ZWJ = 0x8, FEATURE_MANUAL_JOINERS = FEATURE_MANUAL_ZWNJ | FEATURE_MANUAL_ZWJ, FEATURE_HAS_FALLBACK = 0x10, + FEATURE_NEEDS_FALLBACK = 0x20, };
struct shaping_feature diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 256218663fb..03b74eae591 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4568,6 +4568,8 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex next_bit += bits_needed; context->global_mask |= (feature->default_value << feature->shift) & feature->mask; } + if (!found) + feature->flags |= FEATURE_NEEDS_FALLBACK; }
for (stage = 0; stage <= features->stage; ++stage)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 21 ++++++++++++++++----- dlls/dwrite/opentype.c | 7 ++++--- dlls/dwrite/shape.c | 3 ++- dlls/dwrite/shapers/arabic.c | 6 +++--- 4 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 57641680db5..3f48c189a13 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -559,12 +559,23 @@ struct shaping_feature unsigned int stage; };
+#define MAX_SHAPING_STAGE 16 + +typedef void (*stage_func)(struct scriptshaping_context *context); + +struct shaping_stage +{ + stage_func func; + unsigned int last_lookup; +}; + struct shaping_features { struct shaping_feature *features; size_t count; size_t capacity; unsigned int stage; + struct shaping_stage stages[MAX_SHAPING_STAGE]; };
struct shaper @@ -577,9 +588,9 @@ extern const struct shaper arabic_shaper DECLSPEC_HIDDEN;
extern void shape_enable_feature(struct shaping_features *features, unsigned int tag, unsigned int flags) DECLSPEC_HIDDEN; -extern void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, - unsigned int value) DECLSPEC_HIDDEN; -extern void shape_start_next_stage(struct shaping_features *features) DECLSPEC_HIDDEN; +extern void shape_add_feature_full(struct shaping_features *features, unsigned int tag, + unsigned int flags, unsigned int value) DECLSPEC_HIDDEN; +extern void shape_start_next_stage(struct shaping_features *features, stage_func func) DECLSPEC_HIDDEN;
struct scriptshaping_context { @@ -667,9 +678,9 @@ extern DWORD opentype_layout_find_script(const struct scriptshaping_cache *cache extern DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWORD kind, DWORD tag, unsigned int script_index, unsigned int *language_index) DECLSPEC_HIDDEN; extern void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN; + unsigned int language_index, struct shaping_features *features) DECLSPEC_HIDDEN; extern void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN; + unsigned int language_index, struct shaping_features *features) DECLSPEC_HIDDEN; extern BOOL opentype_layout_check_feature(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, struct shaping_feature *feature, unsigned int glyph_count, const UINT16 *glyphs, UINT8 *feature_applies) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 03b74eae591..b446e7450b7 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4442,7 +4442,7 @@ static void opentype_layout_add_lookups(const struct ot_feature_list *feature_li }
static void opentype_layout_collect_lookups(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features, const struct ot_gsubgpos_table *table, + unsigned int language_index, struct shaping_features *features, const struct ot_gsubgpos_table *table, struct lookups *lookups) { unsigned int last_num_lookups = 0, stage, script_feature_count = 0; @@ -4607,6 +4607,7 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex }
last_num_lookups = lookups->count; + features->stages[stage].last_lookup = last_num_lookups; } }
@@ -4688,7 +4689,7 @@ static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_conte }
void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features) + unsigned int language_index, struct shaping_features *features) { struct lookups lookups = { 0 }; unsigned int i; @@ -5791,7 +5792,7 @@ static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_conte }
void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features) + unsigned int language_index, struct shaping_features *features) { struct lookups lookups = { 0 }; unsigned int i, j, start_idx; diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 2dbea825216..6428bf6ceb0 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -142,8 +142,9 @@ void shape_enable_feature(struct shaping_features *features, unsigned int tag, shape_add_feature_full(features, tag, FEATURE_GLOBAL | flags, 1); }
-void shape_start_next_stage(struct shaping_features *features) +void shape_start_next_stage(struct shaping_features *features, stage_func func) { + features->stages[features->stage].func = func; features->stage++; }
diff --git a/dlls/dwrite/shapers/arabic.c b/dlls/dwrite/shapers/arabic.c index 32588b9c796..0b456dadc11 100644 --- a/dlls/dwrite/shapers/arabic.c +++ b/dlls/dwrite/shapers/arabic.c @@ -56,21 +56,21 @@ static void arabic_collect_features(struct scriptshaping_context *context,
shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('c','c','m','p'), 0); shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('l','o','c','l'), 0); - shape_start_next_stage(features); + shape_start_next_stage(features, NULL);
for (i = 0; i < ARRAY_SIZE(arabic_features); ++i) { unsigned int flags = context->script == Script_Arabic && !feature_is_syriac(arabic_features[i]) ? FEATURE_HAS_FALLBACK : 0; shape_add_feature_full(features, arabic_features[i], flags, 1); - shape_start_next_stage(features); + shape_start_next_stage(features, NULL); }
shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','l','i','g'), FEATURE_MANUAL_ZWJ | FEATURE_HAS_FALLBACK);
shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('r','c','l','t'), FEATURE_MANUAL_ZWJ); shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('c','a','l','t'), FEATURE_MANUAL_ZWJ); - shape_start_next_stage(features); + shape_start_next_stage(features, NULL);
shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('m','s','e','t'), 0); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 66 +++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 30 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index b446e7450b7..6fe85dd4991 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -5795,7 +5795,7 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int language_index, struct shaping_features *features) { struct lookups lookups = { 0 }; - unsigned int i, j, start_idx; + unsigned int i = 0, j, start_idx; BOOL ret;
context->nesting_level_left = SHAPE_MAX_NESTING_LEVEL; @@ -5805,47 +5805,53 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, opentype_get_nominal_glyphs(context, features); opentype_layout_set_glyph_masks(context, features);
- for (i = 0; i < lookups.count; ++i) + for (j = 0; j <= features->stage; ++j) { - const struct lookup *lookup = &lookups.lookups[i]; + for (; i < features->stages[j].last_lookup; ++i) + { + const struct lookup *lookup = &lookups.lookups[i];
- context->lookup_mask = lookup->mask; - context->auto_zwnj = lookup->auto_zwnj; - context->auto_zwj = lookup->auto_zwj; + context->lookup_mask = lookup->mask; + context->auto_zwnj = lookup->auto_zwnj; + context->auto_zwj = lookup->auto_zwj;
- if (!opentype_is_gsub_lookup_reversed(context, lookup)) - { - context->cur = 0; - while (context->cur < context->glyph_count) + if (!opentype_is_gsub_lookup_reversed(context, lookup)) { - ret = FALSE; - - if ((context->glyph_infos[context->cur].mask & lookup->mask) && - lookup_is_glyph_match(context, context->cur, lookup->flags)) + context->cur = 0; + while (context->cur < context->glyph_count) { - ret = opentype_layout_apply_gsub_lookup(context, lookup); - } + ret = FALSE;
- if (!ret) - context->cur++; - } - } - else - { - context->cur = context->glyph_count - 1; + if ((context->glyph_infos[context->cur].mask & lookup->mask) && + lookup_is_glyph_match(context, context->cur, lookup->flags)) + { + ret = opentype_layout_apply_gsub_lookup(context, lookup); + }
- for (;;) + if (!ret) + context->cur++; + } + } + else { - if ((context->glyph_infos[context->cur].mask & lookup->mask) && - lookup_is_glyph_match(context, context->cur, lookup->flags)) + context->cur = context->glyph_count - 1; + + for (;;) { - opentype_layout_apply_gsub_lookup(context, lookup); - } + if ((context->glyph_infos[context->cur].mask & lookup->mask) && + lookup_is_glyph_match(context, context->cur, lookup->flags)) + { + opentype_layout_apply_gsub_lookup(context, lookup); + }
- if (context->cur == 0) break; - --context->cur; + if (context->cur == 0) break; + --context->cur; + } } } + + if (features->stages[j].func) + features->stages[j].func(context); }
/* For every glyph range of [<last>.isClusterStart, <next>.isClusterStart) set corresponding
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/Makefile.in | 3 +- dlls/dwrite/shapers/arabic.c | 82 +++++++++ dlls/dwrite/shapers/arabic_table.c | 275 +++++++++++++++++++++++++++++ tools/make_unicode | 54 +++++- 4 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 dlls/dwrite/shapers/arabic_table.c
diff --git a/dlls/dwrite/Makefile.in b/dlls/dwrite/Makefile.in index feac36f3cb2..8b612989386 100644 --- a/dlls/dwrite/Makefile.in +++ b/dlls/dwrite/Makefile.in @@ -18,4 +18,5 @@ C_SRCS = \ opentype.c \ scripts.c \ shape.c \ - shapers/arabic.c + shapers/arabic.c \ + shapers/arabic_table.c diff --git a/dlls/dwrite/shapers/arabic.c b/dlls/dwrite/shapers/arabic.c index 0b456dadc11..aaf57da42e4 100644 --- a/dlls/dwrite/shapers/arabic.c +++ b/dlls/dwrite/shapers/arabic.c @@ -75,9 +75,91 @@ static void arabic_collect_features(struct scriptshaping_context *context, shape_enable_feature(features, DWRITE_MAKE_OPENTYPE_TAG('m','s','e','t'), 0); }
+enum arabic_joining_type +{ + JOINING_TYPE_U = 0, + JOINING_TYPE_L = 1, + JOINING_TYPE_R = 2, + JOINING_TYPE_D = 3, + JOINING_TYPE_C = JOINING_TYPE_D, + JOINING_GROUP_ALAPH = 4, + JOINING_GROUP_DALATH_RISH = 5, + JOINING_TYPES = 6, + JOINING_TYPE_T = 6, +}; + +static const struct arabic_state_table_entry +{ + unsigned char prev_action; + unsigned char curr_action; + unsigned char next_state; +} +arabic_state_table[][JOINING_TYPES] = +{ + /* U, L, R, D, ALAPH, DALATH_RISH */ + /* State 0: prev was U, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, + + /* State 1: prev was R or ISOL/ALAPH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, + + /* State 2: prev was D/L in ISOL form, willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, + + /* State 3: prev was D in FINA form, willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, + + /* State 4: prev was FINA ALAPH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, + + /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, + + /* State 6: prev was DALATH/RISH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } +}; + +extern const unsigned short arabic_shaping_table[] DECLSPEC_HIDDEN; + +static unsigned short arabic_get_joining_type(WCHAR ch) +{ + const unsigned short *table = arabic_shaping_table; + return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)]; +} + +static void arabic_set_shaping_action(struct scriptshaping_context *context, + unsigned int idx, enum arabic_shaping_action action) +{ + context->glyph_infos[idx].props &= ~(0xf << 16); + context->glyph_infos[idx].props |= (action & 0xf) << 16; +} + static void arabic_setup_masks(struct scriptshaping_context *context, const struct shaping_features *features) { + unsigned int i, prev = ~0u, state = 0; + + for (i = 0; i < context->length; ++i) + { + unsigned short this_type = arabic_get_joining_type(context->text[i]); + const struct arabic_state_table_entry *entry; + + if (this_type == JOINING_TYPE_T) + { + arabic_set_shaping_action(context, i, NONE); + continue; + } + + entry = &arabic_state_table[state][this_type]; + + if (entry->prev_action != NONE && prev != ~0u) + arabic_set_shaping_action(context, prev, entry->prev_action); + + arabic_set_shaping_action(context, i, entry->curr_action); + + prev = i; + state = entry->next_state; + } }
const struct shaper arabic_shaper = diff --git a/dlls/dwrite/shapers/arabic_table.c b/dlls/dwrite/shapers/arabic_table.c new file mode 100644 index 00000000000..a0c677e02f9 --- /dev/null +++ b/dlls/dwrite/shapers/arabic_table.c @@ -0,0 +1,275 @@ +/* Unicode Arabic shaping */ +/* generated from https://www.unicode.org/Public/13.0.0/ucd/UCD.zip:ArabicShaping.txt */ +/* DO NOT EDIT!! */ + +#include "windef.h" + +const unsigned short DECLSPEC_HIDDEN arabic_shaping_table[2099] = +{ + /* level 1 offsets */ + 0x0100, 0x010b, 0x010b, 0x011b, 0x0123, 0x012c, 0x013b, 0x014b, + 0x015b, 0x016b, 0x017b, 0x018b, 0x019b, 0x01ab, 0x01b9, 0x01c8, + 0x01d6, 0x010b, 0x010b, 0x01e1, 0x010b, 0x010b, 0x010b, 0x01f0, + 0x0200, 0x020e, 0x021d, 0x022d, 0x023d, 0x024d, 0x010b, 0x010b, + 0x025d, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x026d, 0x027d, 0x010b, 0x010b, + 0x028d, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x0297, 0x010b, + 0x02a7, 0x02b7, 0x02c6, 0x02d6, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, 0x010b, + 0x010b, 0x010b, 0x010b, 0x02e5, 0x010b, 0x010b, 0x02f5, 0x0305, + /* level 2 offsets */ + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0318, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0328, 0x0328, 0x0328, 0x0328, 0x0328, + 0x0328, 0x0328, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0338, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0327, 0x0328, 0x0348, + 0x0356, 0x0315, 0x0315, 0x0315, 0x0366, 0x0376, 0x0385, 0x038d, + 0x0328, 0x039d, 0x03ad, 0x03b5, 0x03bd, 0x03c7, 0x03c7, 0x03d7, + 0x03e7, 0x03ef, 0x03ff, 0x0316, 0x040f, 0x041e, 0x0328, 0x042e, + 0x043c, 0x0448, 0x0457, 0x0315, 0x0315, 0x0342, 0x0467, 0x046d, + 0x03c7, 0x0477, 0x0483, 0x0315, 0x0491, 0x049d, 0x0315, 0x04ad, + 0x04b9, 0x04c9, 0x0315, 0x0315, 0x0315, 0x04d9, 0x04e8, 0x04f2, + 0x0345, 0x0502, 0x0328, 0x039a, 0x0315, 0x0315, 0x0512, 0x0521, + 0x0530, 0x053e, 0x0315, 0x054d, 0x0315, 0x0315, 0x0542, 0x055c, + 0x0315, 0x053e, 0x0317, 0x056b, 0x0315, 0x0315, 0x0542, 0x057a, + 0x054d, 0x0315, 0x0586, 0x056b, 0x0315, 0x0315, 0x0542, 0x0595, + 0x0315, 0x053e, 0x05a3, 0x054d, 0x0315, 0x0315, 0x0319, 0x055c, + 0x053b, 0x053e, 0x0315, 0x054c, 0x0315, 0x0315, 0x0315, 0x0541, + 0x0315, 0x0315, 0x0315, 0x05b2, 0x0315, 0x0315, 0x054f, 0x05c2, + 0x053b, 0x053e, 0x0315, 0x054d, 0x0315, 0x0315, 0x0319, 0x05d0, + 0x0315, 0x053e, 0x0315, 0x039b, 0x0315, 0x0315, 0x0570, 0x055c, + 0x0315, 0x053e, 0x0315, 0x054d, 0x0315, 0x0315, 0x0315, 0x0544, + 0x05de, 0x0315, 0x0315, 0x0315, 0x052d, 0x05e7, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x05f6, 0x05a5, 0x0315, 0x0315, + 0x0315, 0x0538, 0x0315, 0x0603, 0x0315, 0x0315, 0x0315, 0x0347, + 0x0613, 0x0620, 0x0328, 0x032b, 0x0548, 0x0315, 0x0315, 0x0315, + 0x0550, 0x062f, 0x0315, 0x0573, 0x0467, 0x063e, 0x064c, 0x0318, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0550, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x065a, 0x0315, 0x065a, 0x0315, 0x053e, 0x0315, 0x053e, + 0x0315, 0x0315, 0x0315, 0x0666, 0x031f, 0x0670, 0x0315, 0x0315, + 0x067e, 0x0315, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x068e, + 0x0699, 0x03c7, 0x06a0, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x06b0, 0x06be, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x06ca, 0x0315, + 0x0315, 0x0315, 0x06d6, 0x06e4, 0x06f1, 0x0315, 0x0315, 0x0315, + 0x0328, 0x0467, 0x0315, 0x0315, 0x0315, 0x0399, 0x0315, 0x0315, + 0x0701, 0x054c, 0x0315, 0x070e, 0x0399, 0x039b, 0x0315, 0x071e, + 0x0315, 0x0315, 0x0315, 0x072c, 0x039b, 0x0315, 0x0315, 0x0551, + 0x073b, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x074b, 0x075a, 0x0763, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0328, 0x0328, 0x0328, 0x0751, 0x076d, 0x0315, 0x058c, + 0x0315, 0x0315, 0x0315, 0x077b, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0328, 0x0328, 0x0467, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0316, 0x039b, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0316, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0328, 0x0328, 0x0315, 0x0315, 0x0553, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x078b, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0316, 0x079b, 0x0315, + 0x054f, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x039b, 0x07a9, + 0x0315, 0x07b5, 0x0315, 0x03c7, 0x03c7, 0x03c7, 0x07c5, 0x0315, + 0x0315, 0x0315, 0x0315, 0x053c, 0x0315, 0x0328, 0x056c, 0x0315, + 0x0315, 0x07cf, 0x0315, 0x035f, 0x039b, 0x0315, 0x0315, 0x039a, + 0x0315, 0x0315, 0x07dd, 0x0315, 0x0315, 0x0549, 0x0315, 0x0315, + 0x05a4, 0x07e8, 0x07f5, 0x0315, 0x0315, 0x0542, 0x0315, 0x0315, + 0x0315, 0x0805, 0x054d, 0x0315, 0x056f, 0x0548, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0815, 0x0315, 0x0317, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0328, 0x0315, 0x0328, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0316, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, 0x0315, + 0x0315, 0x0315, 0x0315, 0x0315, 0x0823, + /* values */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0003, 0x0000, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, + 0x0002, 0x0003, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0003, 0x0003, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0003, + 0x0006, 0x0002, 0x0002, 0x0002, 0x0000, 0x0002, 0x0002, 0x0002, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0002, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0002, + 0x0003, 0x0002, 0x0003, 0x0003, 0x0002, 0x0002, 0x0000, 0x0002, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0002, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0003, 0x0003, 0x0000, + 0x0000, 0x0003, 0x0004, 0x0006, 0x0003, 0x0003, 0x0003, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0002, 0x0003, 0x0002, 0x0003, 0x0002, 0x0003, 0x0003, + 0x0002, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0002, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, 0x0002, + 0x0003, 0x0003, 0x0003, 0x0002, 0x0003, 0x0002, 0x0002, 0x0003, + 0x0003, 0x0003, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, + 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, 0x0002, + 0x0003, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0002, 0x0003, 0x0002, 0x0002, 0x0002, 0x0006, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0000, 0x0002, 0x0003, 0x0002, 0x0002, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, 0x0002, + 0x0002, 0x0000, 0x0002, 0x0003, 0x0002, 0x0002, 0x0003, 0x0003, + 0x0000, 0x0003, 0x0003, 0x0003, 0x0002, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0006, 0x0000, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0000, 0x0000, 0x0003, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0006, 0x0003, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0006, 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0003, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0006, 0x0000, + 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0003, 0x0003, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0006, 0x0006, 0x0000, 0x0000, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0006, 0x0006, 0x0006, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0006, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, + 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, + 0x0006, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000 +}; diff --git a/tools/make_unicode b/tools/make_unicode index 5d180310b48..93d6a9346c2 100755 --- a/tools/make_unicode +++ b/tools/make_unicode @@ -435,7 +435,7 @@ my @tolower_table = (); my @toupper_table = (); my @digitmap_table = (); my @category_table = (); -my @joining_table = (); +my @initial_joining_table = (); my @direction_table = (); my @decomp_table = (); my @combining_class_table = (); @@ -645,11 +645,11 @@ sub load_data() $direction_table[$src] = $bidi; if ($cat eq "Mn" || $cat eq "Me" || $cat eq "Cf") { - $joining_table[$src] = $joining_types{"T"}; + $initial_joining_table[$src] = $joining_types{"T"}; } else { - $joining_table[$src] = $joining_types{"U"}; + $initial_joining_table[$src] = $joining_types{"U"}; }
if ($lower ne "") @@ -1609,6 +1609,7 @@ sub dump_bracket($) sub dump_shaping($) { my $filename = shift; + my @joining_table = @initial_joining_table;
my $INPUT = open_data_file( $UNIDATA, "ArabicShaping.txt" ); while (<$INPUT>) @@ -1650,6 +1651,52 @@ sub dump_shaping($) save_file($filename); }
+################################################################ +# dump the Arabic shaping table +sub dump_arabic_shaping($) +{ + my $filename = shift; + my @joining_table = @initial_joining_table; + + my $INPUT = open_data_file( $UNIDATA, "ArabicShaping.txt" ); + while (<$INPUT>) + { + next if /^#/; # skip comments + next if /^\s*$/; # skip empty lines + next if /\x1a/; # skip ^Z + if (/^\s*([0-9a-fA-F]+)\s*;.*;\s*([RLDCUT])\s*;\s*(\w+)/) + { + my $type = $2; + my $group = $3; + + if ($group eq "ALAPH" || $group eq "DALATH RISH") + { + $joining_table[hex $1] = $joining_types{$group}; + } + else + { + $joining_table[hex $1] = $joining_types{$type}; + } + + next; + } + die "malformed line $_"; + } + close $INPUT; + + open OUTPUT,">$filename.new" or die "Cannot create $filename"; + print "Building $filename\n"; + print OUTPUT "/* Unicode Arabic shaping */\n"; + print OUTPUT "/* generated from $UNIDATA:ArabicShaping.txt */\n"; + print OUTPUT "/* DO NOT EDIT!! */\n\n"; + print OUTPUT "#include "windef.h"\n\n"; + + dump_two_level_mapping( "arabic_shaping_table", 0, 16, @joining_table ); + + close OUTPUT; + save_file($filename); +} + ################################################################ # dump the Vertical Orientation table sub dump_vertical($) @@ -2710,6 +2757,7 @@ dump_mirroring( "dlls/dwrite/mirror.c" ); dump_bracket( "dlls/gdi32/uniscribe/bracket.c" ); dump_bracket( "dlls/dwrite/bracket.c" ); dump_shaping( "dlls/gdi32/uniscribe/shaping.c" ); +dump_arabic_shaping( "dlls/dwrite/shapers/arabic_table.c" ); dump_linebreak( "dlls/gdi32/uniscribe/linebreak.c" ); dump_linebreak( "dlls/dwrite/linebreak.c" ); dump_scripts( "dlls/dwrite/scripts" );
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 2 ++ dlls/dwrite/opentype.c | 6 ++++++ dlls/dwrite/shapers/arabic.c | 15 +++++++++++++++ 3 files changed, 23 insertions(+)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 3f48c189a13..ac870fd215c 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -590,6 +590,8 @@ extern void shape_enable_feature(struct shaping_features *features, unsigned int unsigned int flags) DECLSPEC_HIDDEN; extern void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, unsigned int value) DECLSPEC_HIDDEN; +extern unsigned int shape_get_feature_1_mask(const struct shaping_features *features, + unsigned int tag) DECLSPEC_HIDDEN; extern void shape_start_next_stage(struct shaping_features *features, stage_func func) DECLSPEC_HIDDEN;
struct scriptshaping_context diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 6fe85dd4991..7d89851bbaa 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4632,6 +4632,12 @@ static unsigned int shaping_features_get_mask(const struct shaping_features *fea return feature->mask; }
+unsigned int shape_get_feature_1_mask(const struct shaping_features *features, unsigned int tag) +{ + unsigned int shift, mask = shaping_features_get_mask(features, tag, &shift); + return (1 << shift) & mask; +} + static void opentype_layout_get_glyph_range_for_text(struct scriptshaping_context *context, unsigned int start_char, unsigned int end_char, unsigned int *start_glyph, unsigned int *end_glyph) { diff --git a/dlls/dwrite/shapers/arabic.c b/dlls/dwrite/shapers/arabic.c index aaf57da42e4..cc701150a56 100644 --- a/dlls/dwrite/shapers/arabic.c +++ b/dlls/dwrite/shapers/arabic.c @@ -41,6 +41,7 @@ enum arabic_shaping_action MED2, INIT, NONE, + NUM_FEATURES = NONE, };
static BOOL feature_is_syriac(unsigned int tag) @@ -134,10 +135,17 @@ static void arabic_set_shaping_action(struct scriptshaping_context *context, context->glyph_infos[idx].props |= (action & 0xf) << 16; }
+static enum arabic_shaping_action arabic_get_shaping_action(const struct scriptshaping_context *context, + unsigned int idx) +{ + return (context->glyph_infos[idx].props >> 16) & 0xf; +} + static void arabic_setup_masks(struct scriptshaping_context *context, const struct shaping_features *features) { unsigned int i, prev = ~0u, state = 0; + unsigned int masks[NUM_FEATURES];
for (i = 0; i < context->length; ++i) { @@ -160,6 +168,13 @@ static void arabic_setup_masks(struct scriptshaping_context *context, prev = i; state = entry->next_state; } + + for (i = 0; i < ARRAY_SIZE(masks); ++i) + masks[i] = shape_get_feature_1_mask(features, arabic_features[i]); + + /* Unaffected glyphs get action NONE with zero mask. */ + for (i = 0; i < context->length; ++i) + context->glyph_infos[i].mask |= masks[arabic_get_shaping_action(context, i)]; }
const struct shaper arabic_shaper =
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 82 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 9 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 7d89851bbaa..ae9a88a876c 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -483,6 +483,8 @@ enum glyph_prop_flags GLYPH_PROP_MARK = LOOKUP_FLAG_IGNORE_MARKS, GLYPH_PROP_ZWNJ = 0x10, GLYPH_PROP_ZWJ = 0x20, + GLYPH_PROP_IGNORABLE = 0x40, + GLYPH_PROP_HIDDEN = 0x80, };
enum gpos_lookup_type @@ -3691,12 +3693,17 @@ static BOOL lookup_is_glyph_match(const struct scriptshaping_context *context, u
static enum iterator_match glyph_iterator_may_skip(const struct glyph_iterator *iter) { + unsigned int glyph_props = iter->context->glyph_infos[iter->pos].props & (GLYPH_PROP_IGNORABLE | GLYPH_PROP_HIDDEN); + if (!lookup_is_glyph_match(iter->context, iter->pos, iter->flags)) return ITER_YES;
- if ((iter->ignore_zwnj || !(iter->context->glyph_infos[iter->pos].props & GLYPH_PROP_ZWNJ)) && + if (glyph_props == GLYPH_PROP_IGNORABLE && !iter->context->u.buffer.glyph_props[iter->pos].components && + (iter->ignore_zwnj || !(iter->context->glyph_infos[iter->pos].props & GLYPH_PROP_ZWNJ)) && (iter->ignore_zwj || !(iter->context->glyph_infos[iter->pos].props & GLYPH_PROP_ZWJ))) + { return ITER_MAYBE; + }
return ITER_NO; } @@ -5687,17 +5694,63 @@ static unsigned int unicode_get_mirrored_char(unsigned int codepoint) }
/* + * 034F # Mn COMBINING GRAPHEME JOINER + * 061C # Cf ARABIC LETTER MARK + * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE + * 180E # Cf MONGOLIAN VOWEL SEPARATOR + * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK + * FEFF # Cf ZERO WIDTH NO-BREAK SPACE +*/ +static unsigned int opentype_is_zero_width(unsigned int codepoint) +{ + return codepoint == 0x34f || codepoint == 0x61c || codepoint == 0xfeff || + (codepoint >= 0x180b && codepoint <= 0x180e) || (codepoint >= 0x200b && codepoint <= 0x200f); +} + +/* + * 00AD # Cf SOFT HYPHEN * 034F # Mn COMBINING GRAPHEME JOINER * 061C # Cf ARABIC LETTER MARK + * 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER + * 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE * 180E # Cf MONGOLIAN VOWEL SEPARATOR * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK + * 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE + * 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS + * 2065 # Cn <reserved-2065> + * 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES + * 3164 # Lo HANGUL FILLER + * FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 * FEFF # Cf ZERO WIDTH NO-BREAK SPACE + * FFA0 # Lo HALFWIDTH HANGUL FILLER + * FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8> + * 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP + * 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE + * E0000 # Cn <reserved-E0000> + * E0001 # Cf LANGUAGE TAG + * E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F> + * E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG + * E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF> + * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 + * E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> */ static unsigned int opentype_is_default_ignorable(unsigned int codepoint) { - return codepoint == 0x34f || codepoint == 0x61c || codepoint == 0xfeff || - (codepoint >= 0x180b && codepoint <= 0x180e) || (codepoint >= 0x200b && codepoint <= 0x200f); + if (codepoint < 0x80) return 0; + return codepoint == 0xad || + codepoint == 0x34f || + codepoint == 0x61c || + (codepoint >= 0x17b4 && codepoint <= 0x17b5) || + (codepoint >= 0x180b && codepoint <= 0x180e) || + (codepoint >= 0x200b && codepoint <= 0x200f) || + (codepoint >= 0x202a && codepoint <= 0x202e) || + (codepoint >= 0x2060 && codepoint <= 0x206f) || + (codepoint >= 0xfe00 && codepoint <= 0xfe0f) || + codepoint == 0xfeff || + (codepoint >= 0xfff0 && codepoint <= 0xfff8) || + (codepoint >= 0x1d173 && codepoint <= 0x1d17a) || + (codepoint >= 0xe0000 && codepoint <= 0xe0fff); }
static unsigned int opentype_is_diacritic(unsigned int codepoint) @@ -5751,10 +5804,21 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c context->u.buffer.glyphs[g] = font->get_glyph(context->cache->context, codepoint); context->u.buffer.glyph_props[g].justification = SCRIPT_JUSTIFY_CHARACTER; opentype_set_subst_glyph_props(context, g); - if (codepoint == 0x200d) - context->glyph_infos[g].props |= GLYPH_PROP_ZWJ; - else if (codepoint == 0x200c) - context->glyph_infos[g].props |= GLYPH_PROP_ZWNJ; + if (opentype_is_default_ignorable(codepoint)) + { + context->glyph_infos[g].props |= GLYPH_PROP_IGNORABLE; + if (codepoint == 0x200d) + context->glyph_infos[g].props |= GLYPH_PROP_ZWJ; + else if (codepoint == 0x200c) + context->glyph_infos[g].props |= GLYPH_PROP_ZWNJ; + /* Mongolian FVSs, TAGs, COMBINING GRAPHEME JOINER */ + else if ((codepoint >= 0x180b && codepoint <= 0x180d) || + (codepoint >= 0xe0020 && codepoint <= 0xe007f) || + codepoint == 0x34f) + { + context->glyph_infos[g].props |= GLYPH_PROP_HIDDEN; + } + }
/* Group diacritics with preceding base. Glyph class is ignored here. */ if (!g || !opentype_is_diacritic(codepoint)) @@ -5763,9 +5827,9 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c context->glyph_infos[g].start_text_idx = i; cluster_start_idx = g; } - - if (opentype_is_default_ignorable(codepoint)) + if (opentype_is_zero_width(codepoint)) context->u.buffer.glyph_props[g].isZeroWidthSpace = 1; + context->u.buffer.glyph_props[g].components = 1; context->glyph_count++;