diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 68ad17a23..403e1733f 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -150,6 +150,28 @@ struct hb_subset_layout_context_t : unsigned lookup_index_count; }; +struct hb_collect_variation_indices_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "CLOSURE_LAYOUT_VARIATION_IDXES"; } + template + return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + hb_set_t *layout_variation_indices; + const hb_set_t *glyph_set; + const hb_map_t *gpos_lookups; + unsigned int debug_depth; + + hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, + const hb_set_t *glyph_set_, + const hb_map_t *gpos_lookups_) : + layout_variation_indices (layout_variation_indices_), + glyph_set (glyph_set_), + gpos_lookups (gpos_lookups_), + debug_depth (0) {} +}; + template struct subset_offset_array_t { @@ -2916,6 +2938,12 @@ struct VariationDevice return_trace (c->embed (this)); } + void record_variation_index (hb_set_t *layout_variation_indices) const + { + unsigned var_idx = (outerIndex << 16) + innerIndex; + layout_variation_indices->add (var_idx); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -3020,6 +3048,25 @@ struct Device } } + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { + switch (u.b.format) { +#ifndef HB_NO_HINTING + case 1: + case 2: + case 3: + return; +#endif +#ifndef HB_NO_VAR + case 0x8000: + u.variation.record_variation_index (layout_variation_indices); + return; +#endif + default: + return; + } + } + protected: union { DeviceHeader b; diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh index 7873f94fa..1247a16d3 100644 --- a/src/hb-ot-layout-gdef-table.hh +++ b/src/hb-ot-layout-gdef-table.hh @@ -175,6 +175,9 @@ struct CaretValueFormat3 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this)); } + + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { (this+deviceTable).collect_variation_indices (layout_variation_indices); } bool sanitize (hb_sanitize_context_t *c) const { @@ -221,6 +224,19 @@ struct CaretValue } } + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { + switch (u.format) { + case 1: + case 2: + return; + case 3: + u.format3.collect_variation_indices (layout_variation_indices); + return; + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -277,6 +293,12 @@ struct LigGlyph return_trace (bool (out->carets)); } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const OffsetTo& offset : carets.iter ()) + (this+offset).collect_variation_indices (c->layout_variation_indices); + } bool sanitize (hb_sanitize_context_t *c) const { @@ -336,6 +358,16 @@ struct LigCaretList return_trace (bool (new_coverage)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, ligGlyph) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) + ; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -544,6 +576,34 @@ struct GDEF (version.to_int () >= 0x00010003u ? varStore.static_size : 0); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+ligCaretList).collect_variation_indices (c); } + + void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map /* OUT */) const + { + if (version.to_int () < 0x00010003u || !varStore) return; + if (layout_variation_indices->is_empty ()) return; + + unsigned new_major = 0, new_minor = 0; + unsigned last_major = (layout_variation_indices->get_min ()) >> 16; + for (unsigned idx : layout_variation_indices->iter ()) + { + uint16_t major = idx >> 16; + if (major >= (this+varStore).get_sub_table_count ()) break; + if (major != last_major) + { + new_minor = 0; + ++new_major; + } + + unsigned new_idx = (new_major << 16) + new_minor; + layout_variation_idx_map->set (idx, new_idx); + ++new_minor; + last_major = major; + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index d55d6ece8..ffe0dc874 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -176,6 +176,43 @@ struct ValueFormat : HBUINT16 if (format & yAdvDevice) copy_device (c, base, values++); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base, + const hb_array_t& values) const + { + unsigned format = *this; + unsigned i = 0; + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + if (format & xPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::xAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + } + private: bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const { @@ -194,6 +231,16 @@ struct ValueFormat : HBUINT16 return true; } + static inline OffsetTo& get_device (Value* value) + { + return *static_cast *> (value); + } + static inline const OffsetTo& get_device (const Value* value, bool *worked=nullptr) + { + if (worked) *worked |= bool (*value); + return *static_cast *> (value); + } + bool copy_device (hb_serialize_context_t *c, const void *base, const Value *src_value) const { Value *dst_value = c->copy (*src_value); @@ -215,16 +262,6 @@ struct ValueFormat : HBUINT16 } } - static inline OffsetTo& get_device (Value* value) - { - return *static_cast *> (value); - } - static inline const OffsetTo& get_device (const Value* value, bool *worked=nullptr) - { - if (worked) *worked |= bool (*value); - return *static_cast *> (value); - } - static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) { if (worked) *worked |= bool (*value); @@ -394,6 +431,12 @@ struct AnchorFormat3 return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); + (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); + } + protected: HBUINT16 format; /* Format identifier--format = 3 */ FWORD xCoordinate; /* Horizontal value--in design units */ @@ -447,6 +490,18 @@ struct Anchor } } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } + protected: union { HBUINT16 format; /* Format identifier */ @@ -470,6 +525,15 @@ struct AnchorMatrix return this+matrixZ[row * cols + col]; } + template + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + Iterator index_iter) const + { + for (unsigned i : index_iter) + (this+matrixZ[i]).collect_variation_indices (c); + } + template bool serialize (hb_serialize_context_t *c, @@ -536,6 +600,12 @@ struct MarkRecord return_trace (out); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+markAnchor).collect_variation_indices (c); + } + protected: HBUINT16 klass; /* Class defined for this mark */ OffsetTo @@ -611,6 +681,18 @@ struct SinglePosFormat1 { return (this+coverage).intersects (glyphs); } void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_iter (this+coverage) + | hb_filter (c->glyph_set) + ; + + if (!it) return; + valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } @@ -701,6 +783,25 @@ struct SinglePosFormat2 { return (this+coverage).intersects (glyphs); } void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) + | hb_filter (c->glyph_set, hb_first) + ; + + if (!it) return; + + unsigned sub_length = valueFormat.get_len (); + const hb_array_t values_array = values.as_array (valueCount * sub_length); + + for (unsigned i : + it + | hb_map (hb_second)) + valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length)); + + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } @@ -895,6 +996,21 @@ struct PairValueRecord return_trace (true); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats, + const void *base) const + { + unsigned record1_len = valueFormats[0].get_len (); + unsigned record2_len = valueFormats[1].get_len (); + const hb_array_t values_array = values.as_array (record1_len + record2_len); + + if (valueFormats[0].has_device ()) + valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); + + if (valueFormats[1].has_device ()) + valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); + } + protected: HBGlyphID secondGlyph; /* GlyphID of second glyph in the * pair--first glyph is listed in the @@ -938,6 +1054,24 @@ struct PairSet c->input->add_array (&record->secondGlyph, len, record_size); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len; + for (unsigned i = 0; i < count; i++) + { + if (c->glyph_set->has (record->secondGlyph)) + { record->collect_variation_indices (c, valueFormats, this); } + + record = &StructAtOffset (record, record_size); + } + } + bool apply (hb_ot_apply_context_t *c, const ValueFormat *valueFormats, unsigned int pos) const @@ -1051,6 +1185,22 @@ struct PairPosFormat1 } void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return; + + auto it = + + hb_zip (this+coverage, pairSet) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + if (!it) return; + + it + | hb_map (hb_add (this)) + | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); }) + ; + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { @@ -1163,6 +1313,37 @@ struct PairPosFormat2 } void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; + + hb_set_t class1_set, class2_set; + for (const unsigned cp : c->glyph_set->iter ()) + { + unsigned klass1 = (this+classDef1).get (cp); + unsigned klass2 = (this+classDef2).get (cp); + class1_set.add (klass1); + class2_set.add (klass2); + } + + if (class1_set.is_empty () || class2_set.is_empty ()) return; + + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + const hb_array_t values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2)); + for (const unsigned class1_idx : class1_set.iter ()) + { + for (const unsigned class2_idx : class2_set.iter ()) + { + unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + if (valueFormat1.has_device ()) + valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1)); + + if (valueFormat2.has_device ()) + valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2)); + } + } + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { @@ -1336,6 +1517,13 @@ struct EntryExitRecord return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+entryAnchor).collect_variation_indices (c); + (src_base+exitAnchor).collect_variation_indices (c); + } + EntryExitRecord* copy (hb_serialize_context_t *c, const void *base) const { TRACE_SERIALIZE (this); @@ -1370,6 +1558,15 @@ struct CursivePosFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, entryExitRecord) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); }) + ; + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } @@ -1592,6 +1789,36 @@ struct MarkBasePosFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t base_indexes; + for (const unsigned row : base_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + (this+baseArray).collect_variation_indices (c, base_indexes.iter ()); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; @@ -1777,6 +2004,42 @@ struct MarkLigPosFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned ligcount = (this+ligatureArray).len; + auto lig_iter = + + hb_zip (this+ligatureCoverage, hb_range (ligcount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + const LigatureArray& lig_array = this+ligatureArray; + for (const unsigned i : lig_iter) + { + hb_sorted_vector_t lig_indexes; + unsigned row_count = lig_array[i].rows; + for (unsigned row : + hb_range (row_count)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (lig_indexes) + ; + } + + lig_array[i].collect_variation_indices (c, lig_indexes.iter ()); + } + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; @@ -1899,6 +2162,36 @@ struct MarkMarkPosFormat1 void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+mark1Coverage, this+mark1Array) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); + + unsigned mark2_count = (this+mark2Array).rows; + auto mark2_iter = + + hb_zip (this+mark2Coverage, hb_range (mark2_count)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t mark2_indexes; + for (const unsigned row : mark2_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (mark2_indexes) + ; + } + (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; @@ -1986,7 +2279,7 @@ struct MarkMarkPosFormat1 out->mark1Array.serialize (c->serializer, out) .serialize (c->serializer, &klass_mapping, &(this+mark1Array), + mark1_iter | hb_map (hb_second)); -////// + unsigned mark2count = (this+mark2Array).rows; auto mark2_iter = + hb_zip (this+mark2Coverage, hb_range (mark2count)) @@ -2243,6 +2536,16 @@ struct GPOS : GSUBGPOS HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, hb_face_t *face) const; + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) + { + if (!c->gpos_lookups->has (i)) continue; + const PosLookup &l = get_lookup (i); + l.dispatch (c); + } + } + typedef GSUBGPOS::accelerator_t accelerator_t; }; diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh index 8e839b965..6aa2f161a 100644 --- a/src/hb-ot-layout-gsubgpos.hh +++ b/src/hb-ot-layout-gsubgpos.hh @@ -1674,6 +1674,8 @@ struct ContextFormat1 ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverage).collect_coverage (c->input); @@ -1814,6 +1816,8 @@ struct ContextFormat2 ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverage).collect_coverage (c->input); @@ -1964,6 +1968,8 @@ struct ContextFormat3 recurse_lookups (c, lookupCount, lookupRecord); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverageZ[0]).collect_coverage (c->input); @@ -2562,6 +2568,8 @@ struct ChainContextFormat1 ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverage).collect_coverage (c->input); @@ -2706,6 +2714,8 @@ struct ChainContextFormat2 ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { (this+coverage).collect_coverage (c->input); @@ -2904,6 +2914,8 @@ struct ChainContextFormat3 recurse_lookups (c, lookup.len, lookup.arrayZ); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { const OffsetArrayOf &input = StructAfter> (backtrack); @@ -3082,6 +3094,9 @@ struct ExtensionFormat1 return_trace (get_subtable ().dispatch (c, get_type (), hb_forward (ds)...)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { dispatch (c); } + /* This is called from may_dispatch() above with hb_sanitize_context_t. */ bool sanitize (hb_sanitize_context_t *c) const { diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 9f4d7cb0b..7bbd5d6fa 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -318,6 +318,37 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs); } +#ifndef HB_NO_VAR +/** + * hb_ot_layout_collect_variation_indices: + * @face: The #hb_face_t to work on + * @layout_variation_indices: (inout): The #hb_set_t set of var indexes in all Device + * tables + * + * Fetch and remap a list of variation indices in all Device tables referenced + * in the specified face's GDEF table and GPOS tables that are going to be + * retained in the final subset + * + * Since: REPLACEME + **/ +void +hb_ot_layout_collect_variation_indices (hb_face_t *face, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices /* OUT */, + hb_map_t *layout_variation_idx_map /* OUT */) +{ + if (!face->table.GDEF->table->has_data ()) return; + OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups); + face->table.GDEF->table->collect_variation_indices (&c); + + if (hb_ot_layout_has_positioning (face)) + face->table.GPOS->table->collect_variation_indices (&c); + + face->table.GDEF->table->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map); +} +#endif + #ifndef HB_NO_LAYOUT_UNUSED /** diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h index 0bd66166a..514d74446 100644 --- a/src/hb-ot-layout.h +++ b/src/hb-ot-layout.h @@ -121,6 +121,12 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, hb_ot_layout_glyph_class_t klass, hb_set_t *glyphs /* OUT */); +HB_EXTERN void +hb_ot_layout_collect_variation_indices (hb_face_t *face, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices /* INOUT */, + hb_map_t *layout_variation_idx_map /* INOUT */); /* Not that useful. Provides list of attach points for a glyph that a * client may want to cache */ diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index 54656f5dd..2d5871430 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -35,6 +35,7 @@ #include "hb-ot-var-fvar-table.hh" #include "hb-ot-stat-table.hh" + #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, @@ -128,6 +129,18 @@ _gpos_closure_lookups_features (hb_face_t *face, } #endif +#ifndef HB_NO_VAR +static inline void + _collect_layout_variation_indices (hb_face_t *face, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map) +{ + hb_ot_layout_collect_variation_indices (face, glyphset, gpos_lookups, layout_variation_indices, layout_variation_idx_map); +} +#endif + static inline void _cmap_closure (hb_face_t *face, const hb_set_t *unicodes, @@ -156,7 +169,8 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, const hb_set_t *unicodes, const hb_set_t *input_glyphs_to_retain, bool close_over_gsub, - bool close_over_gpos) + bool close_over_gpos, + bool close_over_gdef) { OT::cmap::accelerator_t cmap; OT::glyf::accelerator_t glyf; @@ -216,6 +230,11 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); +#ifndef HB_NO_VAR + if (close_over_gdef) + _collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map); +#endif + #ifndef HB_NO_SUBSET_CFF cff.fini (); #endif @@ -308,12 +327,15 @@ hb_subset_plan_create (hb_face_t *face, plan->gpos_lookups = hb_map_create (); plan->gsub_features = hb_map_create (); plan->gpos_features = hb_map_create (); + plan->layout_variation_indices = hb_set_create (); + plan->layout_variation_idx_map = hb_map_create (); _populate_gids_to_retain (plan, input->unicodes, input->glyphs, !input->drop_tables->has (HB_OT_TAG_GSUB), - !input->drop_tables->has (HB_OT_TAG_GPOS)); + !input->drop_tables->has (HB_OT_TAG_GPOS), + !input->drop_tables->has (HB_OT_TAG_GDEF)); _create_old_gid_to_new_gid_map (face, input->retain_gids, @@ -351,6 +373,8 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->gpos_lookups); hb_map_destroy (plan->gsub_features); hb_map_destroy (plan->gpos_features); + hb_set_destroy (plan->layout_variation_indices); + hb_map_destroy (plan->layout_variation_idx_map); free (plan); diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index cd3d07b00..7a85b5137 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -82,6 +82,11 @@ struct hb_subset_plan_t hb_map_t *gsub_features; hb_map_t *gpos_features; + //The set of layout item variation store delta set indices to be retained + hb_set_t *layout_variation_indices; + //Old -> New layout item variation store delta set index mapping + hb_map_t *layout_variation_idx_map; + public: /*