diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh index ec617080d..359e859cf 100644 --- a/src/hb-aat-layout-feat-table.hh +++ b/src/hb-aat-layout-feat-table.hh @@ -129,6 +129,8 @@ struct FeatureName hb_ot_name_id_t get_feature_name_id () const { return nameIndex; } + bool is_exclusive () const { return featureFlags & Exclusive; } + /* A FeatureName with no settings is meaningless */ bool has_data () const { return nSettings; } diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index d8df579f5..c6b5aa53f 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -948,8 +948,10 @@ struct Chain hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; retry: - const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type); - if (info && info->setting == setting) + // Check whether this type/setting pair was requested in the map, and if so, apply its flags. + // (The search here only looks at the type and setting fields of feature_info_t.) + hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; + if (map->features.bsearch (info)) { flags &= feature.disableFlags; flags |= feature.enableFlags; diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc index 65df85d36..255684231 100644 --- a/src/hb-aat-map.cc +++ b/src/hb-aat-map.cc @@ -48,12 +48,15 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; info->setting = (hb_aat_layout_feature_selector_t) value; info->seq = features.length; + info->is_exclusive = true; return; } const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); if (!mapping) return; - if (!face->table.feat->exposes_feature (mapping->aatFeatureType)) + + const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); + if (!feature->has_data ()) { /* Special case: Chain::compile_flags will fall back to the deprecated version of * small-caps if necessary, so we need to check for that possibility. @@ -61,7 +64,8 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) { - if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE)) return; + feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); + if (!feature->has_data ()) return; } else return; } @@ -70,6 +74,7 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) info->type = mapping->aatFeatureType; info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; info->seq = features.length; + info->is_exclusive = feature->is_exclusive (); } void @@ -81,7 +86,11 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m) features.qsort (); unsigned int j = 0; for (unsigned int i = 1; i < features.length; i++) - if (features[i].type != features[j].type) + if (features[i].type != features[j].type || + /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off + * respectively, so we mask out the low-order bit when checking for "duplicates" + * (selectors referring to the same feature setting) here. */ + (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) features[++j] = features[i]; features.shrink (j + 1); } diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh index 0065207cc..1cf5a8a13 100644 --- a/src/hb-aat-map.hh +++ b/src/hb-aat-map.hh @@ -64,19 +64,24 @@ struct hb_aat_map_builder_t { hb_aat_layout_feature_type_t type; hb_aat_layout_feature_selector_t setting; + bool is_exclusive; unsigned seq; /* For stable sorting only. */ HB_INTERNAL static int cmp (const void *pa, const void *pb) { const feature_info_t *a = (const feature_info_t *) pa; const feature_info_t *b = (const feature_info_t *) pb; - return (a->type != b->type) ? (a->type < b->type ? -1 : 1) : - (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); + if (a->type != b->type) return (a->type < b->type ? -1 : 1); + if (!a->is_exclusive && + (a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1); + return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); } - int cmp (hb_aat_layout_feature_type_t ty) const + /* compares type & setting only, not is_exclusive flag or seq number */ + int cmp (const feature_info_t& f) const { - return (ty != type) ? (ty < type ? -1 : 1) : 0; + return (f.type != type) ? (f.type < type ? -1 : 1) : + (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0; } };