diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh index 4a6c9c5e1..a709c321f 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos-private.hh @@ -261,6 +261,7 @@ struct hb_apply_context_t hb_buffer_t *buffer; hb_direction_t direction; hb_mask_t lookup_mask; + bool auto_joiners; recurse_func_t recurse_func; unsigned int nesting_level_left; unsigned int lookup_props; @@ -272,11 +273,13 @@ struct hb_apply_context_t hb_apply_context_t (unsigned int table_index_, hb_font_t *font_, hb_buffer_t *buffer_, - hb_mask_t lookup_mask_) : + hb_mask_t lookup_mask_, + bool auto_joiners_) : table_index (table_index_), font (font_), face (font->face), buffer (buffer_), direction (buffer_->props.direction), lookup_mask (lookup_mask_), + auto_joiners (auto_joiners_), recurse_func (NULL), nesting_level_left (MAX_NESTING_LEVEL), lookup_props (0), @@ -292,8 +295,8 @@ struct hb_apply_context_t { inline matcher_t (void) : lookup_props (0), - ignore_zwnj (true), - ignore_zwj (true), + ignore_zwnj (false), + ignore_zwj (false), mask (-1), #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ syllable arg1(0), @@ -369,13 +372,16 @@ struct hb_apply_context_t end (c->buffer->len) { matcher.set_lookup_props (c->lookup_props); - /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ - matcher.set_ignore_zwnj (context_match || c->table_index == 1); - matcher.set_ignore_zwj (true); + if (c->auto_joiners) + { + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + matcher.set_ignore_zwnj (context_match || c->table_index == 1); + matcher.set_ignore_zwj (true); + } if (!context_match) { - matcher.set_mask (c->lookup_mask); - matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); + matcher.set_mask (c->lookup_mask); + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } } inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } @@ -439,13 +445,16 @@ struct hb_apply_context_t num_items (num_items_) { matcher.set_lookup_props (c->lookup_props); - /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ - matcher.set_ignore_zwnj (context_match || c->table_index == 1); - matcher.set_ignore_zwj (true); + if (c->auto_joiners) + { + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + matcher.set_ignore_zwnj (context_match || c->table_index == 1); + matcher.set_ignore_zwj (true); + } if (!context_match) { - matcher.set_mask (c->lookup_mask); - matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); + matcher.set_mask (c->lookup_mask); + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } } inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 21a79d691..3c5a1e8c8 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -206,7 +206,8 @@ HB_INTERNAL hb_bool_t hb_ot_layout_substitute_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask); + hb_mask_t mask, + hb_bool_t auto_joiners); /* Should be called after all the substitute_lookup's are done */ HB_INTERNAL void @@ -223,7 +224,8 @@ HB_INTERNAL hb_bool_t hb_ot_layout_position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask); + hb_mask_t mask, + hb_bool_t auto_joiners); /* Should be called after all the position_lookup's are done */ HB_INTERNAL void diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 62988ab09..0349b328d 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -666,11 +666,12 @@ hb_bool_t hb_ot_layout_substitute_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask) + hb_mask_t mask, + hb_bool_t auto_joiners) { if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false; - OT::hb_apply_context_t c (0, font, buffer, mask); + OT::hb_apply_context_t c (0, font, buffer, mask, auto_joiners); const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index); @@ -715,11 +716,12 @@ hb_bool_t hb_ot_layout_position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask) + hb_mask_t mask, + hb_bool_t auto_joiners) { if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false; - OT::hb_apply_context_t c (1, font, buffer, mask); + OT::hb_apply_context_t c (1, font, buffer, mask, auto_joiners); const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index); diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh index 663b7d1ee..942e9f4aa 100644 --- a/src/hb-ot-map-private.hh +++ b/src/hb-ot-map-private.hh @@ -49,14 +49,16 @@ struct hb_ot_map_t unsigned int shift; hb_mask_t mask; hb_mask_t _1_mask; /* mask for value=1, for quick access */ - hb_bool_t needs_fallback; + unsigned int needs_fallback : 1; + unsigned int auto_joiners : 1; static int cmp (const feature_map_t *a, const feature_map_t *b) { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; } }; struct lookup_map_t { - unsigned int index; + unsigned short index; + unsigned short auto_joiners : 1; hb_mask_t mask; static int cmp (const lookup_map_t *a, const lookup_map_t *b) @@ -136,7 +138,8 @@ struct hb_ot_map_t HB_INTERNAL void add_lookups (hb_face_t *face, unsigned int table_index, unsigned int feature_index, - hb_mask_t mask); + hb_mask_t mask, + bool auto_joiners); hb_mask_t global_mask; @@ -148,7 +151,8 @@ struct hb_ot_map_t enum hb_ot_map_feature_flags_t { F_NONE = 0x0000, F_GLOBAL = 0x0001, - F_HAS_FALLBACK = 0x0002 + F_HAS_FALLBACK = 0x0002, + F_MANUAL_JOINERS = 0x0004 }; inline hb_ot_map_feature_flags_t operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r) diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index 784818638..2fbb6ce87 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -33,7 +33,8 @@ void hb_ot_map_t::add_lookups (hb_face_t *face, unsigned int table_index, unsigned int feature_index, - hb_mask_t mask) + hb_mask_t mask, + bool auto_joiners) { unsigned int lookup_indices[32]; unsigned int offset, len; @@ -53,6 +54,7 @@ hb_ot_map_t::add_lookups (hb_face_t *face, return; lookup->mask = mask; lookup->index = lookup_indices[i]; + lookup->auto_joiners = auto_joiners; } offset += len; @@ -108,7 +110,10 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) { const pause_map_t *pause = &pauses[table_index][pause_index]; for (; i < pause->num_lookups; i++) - hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_substitute_lookup (font, buffer, + lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_joiners); buffer->clear_output (); @@ -117,7 +122,9 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h } for (; i < lookups[table_index].len; i++) - hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_joiners); } void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const @@ -128,14 +135,18 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_ for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) { const pause_map_t *pause = &pauses[table_index][pause_index]; for (; i < pause->num_lookups; i++) - hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_joiners); if (pause->callback) pause->callback (plan, font, buffer); } for (; i < lookups[table_index].len; i++) - hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_joiners); } void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const @@ -232,6 +243,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) map->index[1] = feature_index[1]; map->stage[0] = info->stage[0]; map->stage[1] = info->stage[1]; + map->auto_joiners = !(info->flags & F_MANUAL_JOINERS); if ((info->flags & F_GLOBAL) && info->max_value == 1) { /* Uses the global bit */ map->shift = 0; @@ -264,7 +276,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) script_index[table_index], language_index[table_index], &required_feature_index)) - m.add_lookups (face, table_index, required_feature_index, 1); + m.add_lookups (face, table_index, required_feature_index, 1, true); unsigned int pause_index = 0; unsigned int last_num_lookups = 0; @@ -272,7 +284,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) { for (unsigned i = 0; i < m.features.len; i++) if (m.features[i].stage[table_index] == stage) - m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask); + m.add_lookups (face, table_index, + m.features[i].index[table_index], + m.features[i].mask, + m.features[i].auto_joiners); /* Sort lookups and merge duplicates */ if (last_num_lookups < m.lookups[table_index].len) @@ -284,7 +299,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) if (m.lookups[table_index][i].index != m.lookups[table_index][j].index) m.lookups[table_index][++j] = m.lookups[table_index][i]; else + { m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask; + m.lookups[table_index][j].auto_joiners &= m.lookups[table_index][i].auto_joiners; + } m.lookups[table_index].shrink (j + 1); } diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index c0dbff0f8..6f8e9510f 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -244,7 +244,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, { for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) if (fallback_plan->lookup_array[i]) { - OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i]); + OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i], true/*auto_joiners*/); fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]); } } diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index b60e3103a..0beddc819 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -339,18 +339,18 @@ indic_features[] = * Basic features. * These features are applied in order, one at a time, after initial_reordering. */ - {HB_TAG('n','u','k','t'), F_GLOBAL}, - {HB_TAG('a','k','h','n'), F_GLOBAL}, - {HB_TAG('r','p','h','f'), F_NONE}, - {HB_TAG('r','k','r','f'), F_GLOBAL}, - {HB_TAG('p','r','e','f'), F_NONE}, - {HB_TAG('b','l','w','f'), F_NONE}, - {HB_TAG('h','a','l','f'), F_NONE}, - {HB_TAG('a','b','v','f'), F_NONE}, - {HB_TAG('p','s','t','f'), F_NONE}, - {HB_TAG('c','f','a','r'), F_NONE}, - {HB_TAG('v','a','t','u'), F_GLOBAL}, - {HB_TAG('c','j','c','t'), F_GLOBAL}, + {HB_TAG('n','u','k','t'), F_MANUAL_JOINERS | F_GLOBAL}, + {HB_TAG('a','k','h','n'), F_MANUAL_JOINERS | F_GLOBAL}, + {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS}, + {HB_TAG('r','k','r','f'), F_MANUAL_JOINERS | F_GLOBAL}, + {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS}, + {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS}, + {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS}, + {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS}, + {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS}, + {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS}, + {HB_TAG('v','a','t','u'), F_MANUAL_JOINERS | F_GLOBAL}, + {HB_TAG('c','j','c','t'), F_MANUAL_JOINERS | F_GLOBAL}, /* * Other features. * These features are applied all at once, after final_reordering. @@ -1003,8 +1003,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, do { j--; - /* A ZWJ disables CJCT, however, it's mere presence is enough - * to disable ligation. No explicit action needed. */ + /* ZWJ/ZWNJ should disable CJCT. They do that by simply + * being there, since we don't skip them for the CJCT + * feature (ie. F_MANUAL_JOINERS) */ /* A ZWNJ disables HALF. */ if (non_joiner) diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc index 53a9ab44a..e76697389 100644 --- a/src/hb-ot-shape-complex-myanmar.cc +++ b/src/hb-ot-shape-complex-myanmar.cc @@ -107,12 +107,12 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) unsigned int i = 0; map->add_gsub_pause (initial_reordering); for (; i < MYANMAR_BASIC_FEATURES; i++) { - map->add_global_bool_feature (myanmar_features[i]); + map->add_feature (myanmar_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS); map->add_gsub_pause (NULL); } map->add_gsub_pause (final_reordering); for (; i < MYANMAR_NUM_FEATURES; i++) { - map->add_global_bool_feature (myanmar_features[i]); + map->add_feature (myanmar_features[i], 1, F_GLOBAL); } } diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc index 387a4a1f6..c06612e20 100644 --- a/src/hb-ot-shape-complex-sea.cc +++ b/src/hb-ot-shape-complex-sea.cc @@ -109,12 +109,12 @@ collect_features_sea (hb_ot_shape_planner_t *plan) unsigned int i = 0; map->add_gsub_pause (initial_reordering); for (; i < SEA_BASIC_FEATURES; i++) { - map->add_global_bool_feature (sea_features[i]); + map->add_feature (sea_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS); map->add_gsub_pause (NULL); } map->add_gsub_pause (final_reordering); for (; i < SEA_NUM_FEATURES; i++) { - map->add_global_bool_feature (sea_features[i]); + map->add_feature (sea_features[i], 1, F_GLOBAL | F_MANUAL_JOINERS); } }