TODO | 4 + src/hb-ot-shape-complex-arabic.cc | 110 +++++++++++++++++++++++++------------ src/hb-ot-shape-complex-indic.cc | 1 src/hb-ot-shape-complex-misc.cc | 12 ++-- src/hb-ot-shape-complex-private.hh | 15 ++++- src/hb-ot-shape-fallback.cc | 22 ++++++- src/hb-ot-shape.cc | 3 + 7 files changed, 123 insertions(+), 44 deletions(-)
New commits: commit 9f9f04c2229227bb0712166e824157bbbf5cef80 Author: Behdad Esfahbod <[email protected]> Date: Sat Aug 11 18:34:13 2012 -0400 [OT] Unbreak Thai shaping and fallback Arabic shaping The merger of normalizer and glyph-mapping broke shapers that modified text stream. Unbreak them by adding a new preprocess_text shaping stage that happens before normalizing/cmap and disallow setup_mask modification of actual text. diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index e0db41c..e1a2791 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -274,12 +274,8 @@ arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer) } static void -setup_masks_arabic (const hb_ot_shape_plan_t *plan, - hb_buffer_t *buffer, - hb_font_t *font) +arabic_joining (hb_buffer_t *buffer) { - const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; - unsigned int count = buffer->len; unsigned int prev = 0, state = 0; @@ -305,14 +301,37 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, state = entry->next_state; } - if (likely (!arabic_plan->do_fallback)) { - /* Has OpenType tables */ - for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()]; - } else + HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); +} + +static void +preprocess_text_arabic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; + + if (unlikely (arabic_plan->do_fallback)) + { + arabic_joining (buffer); arabic_fallback_shape (font, buffer); + } +} - HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); +static void +setup_masks_arabic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; + + if (likely (!arabic_plan->do_fallback)) + { + arabic_joining (buffer); + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()]; + } } const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = @@ -322,6 +341,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = NULL, /* override_features */ data_create_arabic, data_destroy_arabic, + preprocess_text_arabic, NULL, /* normalization_preference */ setup_masks_arabic, true, /* zero_width_attached_marks */ diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 4f9a5af..6fbd5c8 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -1134,6 +1134,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = override_features_indic, data_create_indic, data_destroy_indic, + NULL, /* preprocess_text */ NULL, /* normalization_preference */ setup_masks_indic, false, /* zero_width_attached_marks */ diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc index 4f1dd5b..13bc22b 100644 --- a/src/hb-ot-shape-complex-misc.cc +++ b/src/hb-ot-shape-complex-misc.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -90,6 +90,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = NULL, /* override_features */ NULL, /* data_create */ NULL, /* data_destroy */ + NULL, /* preprocess_text */ normalization_preference_default, NULL, /* setup_masks */ true, /* zero_width_attached_marks */ @@ -99,9 +100,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = /* Thai / Lao shaper */ static void -setup_masks_thai (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_buffer_t *buffer, - hb_font_t *font HB_UNUSED) +preprocess_text_thai (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_buffer_t *buffer, + hb_font_t *font HB_UNUSED) { /* The following is NOT specified in the MS OT Thai spec, however, it seems * to be what Uniscribe and other engines implement. According to Eric Muller: @@ -200,7 +201,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = NULL, /* override_features */ NULL, /* data_create */ NULL, /* data_destroy */ + preprocess_text_thai, NULL, /* normalization_preference */ - setup_masks_thai, + NULL, /* setup_masks */ true, /* zero_width_attached_marks */ }; diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh index efff325..e84c490 100644 --- a/src/hb-ot-shape-complex-private.hh +++ b/src/hb-ot-shape-complex-private.hh @@ -56,7 +56,6 @@ struct hb_ot_complex_shaper_t /* collect_features() * Called during shape_plan(). * Shapers should use plan->map to add their features and callbacks. - * May be NULL. */ void (*collect_features) (hb_ot_shape_planner_t *plan); @@ -64,7 +63,6 @@ struct hb_ot_complex_shaper_t * Called during shape_plan(). * Shapers should use plan->map to override features and add callbacks after * common features are added. - * May be NULL. */ void (*override_features) (hb_ot_shape_planner_t *plan); @@ -73,7 +71,7 @@ struct hb_ot_complex_shaper_t * Called at the end of shape_plan(). * Whatever shapers return will be accessible through plan->data later. * If NULL is returned, means a plan failure. - * May be NULL. */ + */ void *(*data_create) (const hb_ot_shape_plan_t *plan); /* data_destroy() @@ -83,6 +81,16 @@ struct hb_ot_complex_shaper_t * May be NULL. */ void (*data_destroy) (void *data); + + /* preprocess_text() + * Called during shape(). + * Shapers can use to modify text before shaping starts. + */ + void (*preprocess_text) (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font); + + /* normalization_preference() * Called during shape(). */ @@ -92,6 +100,7 @@ struct hb_ot_complex_shaper_t /* setup_masks() * Called during shape(). * Shapers should use map to get feature masks and set on buffer. + * Shapers may NOT modify characters. */ void (*setup_masks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 823eced..29076cf 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -319,6 +319,9 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer) static inline void hb_ot_substitute_default (hb_ot_shape_context_t *c) { + if (c->plan->shaper->preprocess_text) + c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font); + hb_ot_mirror_chars (c); HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index); commit e9f28a38f54b98fa59f9159ccaaa3be6027e1378 Author: Behdad Esfahbod <[email protected]> Date: Sat Aug 11 18:20:28 2012 -0400 [OT] Add shape_plan to Arabic shaper diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index 2a96b7d..e0db41c 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -99,7 +99,7 @@ static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second) return 0; } -static const hb_tag_t arabic_syriac_features[] = +static const hb_tag_t arabic_features[] = { HB_TAG('i','n','i','t'), HB_TAG('m','e','d','i'), @@ -127,9 +127,7 @@ enum { NONE, - COMMON_NUM_FEATURES = 4, - SYRIAC_NUM_FEATURES = 7, - TOTAL_NUM_FEATURES = NONE + ARABIC_NUM_FEATURES = NONE }; static const struct arabic_state_table_entry { @@ -184,9 +182,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) map->add_gsub_pause (NULL); - unsigned int num_features = plan->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; - for (unsigned int i = 0; i < num_features; i++) - map->add_bool_feature (arabic_syriac_features[i], false); + for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) + map->add_bool_feature (arabic_features[i], false); map->add_gsub_pause (NULL); @@ -200,10 +197,51 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) map->add_bool_feature (HB_TAG('c','s','w','h')); } +struct arabic_shape_plan_t +{ + ASSERT_POD (); + + bool do_fallback; + hb_mask_t mask_array[ARABIC_NUM_FEATURES]; +}; + +static void * +data_create_arabic (const hb_ot_shape_plan_t *plan) +{ + arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t)); + if (unlikely (!arabic_plan)) + return NULL; + + hb_mask_t total_masks = 0; + for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { + arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); + total_masks |= arabic_plan->mask_array[i]; + } + + /* Pitfalls: + * - This path fires if user force-set init/medi/fina/isol off, + * - If font does not declare script 'arab', well, what to do? + * Most probably it's safe to assume that init/medi/fina/isol + * still mean Arabic shaping, although they do not have to. + */ + arabic_plan->do_fallback = 0 == total_masks; + + return arabic_plan; +} + +static void +data_destroy_arabic (void *data) +{ + free (data); +} static void arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer) { + /* Only Arabic has presentation forms encoded in Unicode. */ + if (buffer->props.script != HB_SCRIPT_ARABIC) + return; + unsigned int count = buffer->len; hb_codepoint_t glyph; @@ -240,6 +278,8 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font) { + const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; + unsigned int count = buffer->len; unsigned int prev = 0, state = 0; @@ -265,28 +305,12 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan, state = entry->next_state; } - hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0}; - hb_mask_t total_masks = 0; - unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; - for (unsigned int i = 0; i < num_masks; i++) { - mask_array[i] = plan->map.get_1_mask (arabic_syriac_features[i]); - total_masks |= mask_array[i]; - } - - if (total_masks) { + if (likely (!arabic_plan->do_fallback)) { /* Has OpenType tables */ for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()]; - } else if (buffer->props.script == HB_SCRIPT_ARABIC) { - /* Fallback Arabic shaping to Presentation Forms */ - /* Pitfalls: - * - This path fires if user force-set init/medi/fina/isol off, - * - If font does not declare script 'arab', well, what to do? - * Most probably it's safe to assume that init/medi/fina/isol - * still mean Arabic shaping, although they do not have to. - */ + buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()]; + } else arabic_fallback_shape (font, buffer); - } HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } @@ -296,8 +320,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = "arabic", collect_features_arabic, NULL, /* override_features */ - NULL, /* data_create */ - NULL, /* data_destroy */ + data_create_arabic, + data_destroy_arabic, NULL, /* normalization_preference */ setup_masks_arabic, true, /* zero_width_attached_marks */ commit 344cc56698a8c84c4c1a05a71d829e5171aa3a60 Author: Behdad Esfahbod <[email protected]> Date: Sat Aug 11 17:36:23 2012 -0400 Add TODO diff --git a/TODO b/TODO index 71e5b4d..0c09f00 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,10 @@ General fixes: ============= +- Ligature matching and match_input() of (Chain)Context should use the + same logic. Right now the Ligature logic is more involved. Possibly + merge, or duplicate. + - mask propagation? (when ligation, "or" the masks). - Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font commit daf13afb0801740dcc7900c4af190e24b80a05c0 Author: Behdad Esfahbod <[email protected]> Date: Fri Aug 10 16:38:44 2012 -0400 [OT] Implement fallback mark positioning for "double" combining marks diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index a6e5b16..56a3e7a 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -162,7 +162,14 @@ position_mark (const hb_ot_shape_plan_t *plan, { case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: - /* TODO Do something... For now, fall through. */ + if (buffer->props.direction == HB_DIRECTION_LTR) { + pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing; + break; + } else if (buffer->props.direction == HB_DIRECTION_RTL) { + pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing; + break; + } + /* Fall through */ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: commit d345313104d9e3c8a8533ccdebd74e0648d0bee3 Author: Behdad Esfahbod <[email protected]> Date: Fri Aug 10 16:34:04 2012 -0400 [OT] Fix fallback mark positioning with left-to-right text Ouch! diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index abc7e2b..a6e5b16 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -242,6 +242,10 @@ position_around_base (const hb_ot_shape_plan_t *plan, HB_UNUSED bool is_ligature = is_a_ligature (buffer->info[base]); hb_position_t x_offset = 0, y_offset = 0; + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { + x_offset -= buffer->pos[base].x_advance; + y_offset -= buffer->pos[base].y_advance; + } unsigned int last_combining_class = 255; hb_glyph_extents_t cluster_extents; for (unsigned int i = base + 1; i < end; i++) @@ -262,8 +266,13 @@ position_around_base (const hb_ot_shape_plan_t *plan, last_combining_class = this_combining_class; } else { - x_offset -= buffer->pos[i].x_advance; - y_offset -= buffer->pos[i].y_advance; + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { + x_offset -= buffer->pos[i].x_advance; + y_offset -= buffer->pos[i].y_advance; + } else { + x_offset += buffer->pos[i].x_advance; + y_offset += buffer->pos[i].y_advance; + } }
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
