1 #ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH 2 #define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH 3 4 #include "PairSet.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GPOS_impl { 9 10 11 template <typename Types> 12 struct PairPosFormat1_3 13 { 14 using PairSet = GPOS_impl::PairSet<Types>; 15 using PairValueRecord = GPOS_impl::PairValueRecord<Types>; 16 17 protected: 18 HBUINT16 format; /* Format identifier--format = 1 */ 19 typename Types::template OffsetTo<Coverage> 20 coverage; /* Offset to Coverage table--from 21 * beginning of subtable */ 22 ValueFormat valueFormat[2]; /* [0] Defines the types of data in 23 * ValueRecord1--for the first glyph 24 * in the pair--may be zero (0) */ 25 /* [1] Defines the types of data in 26 * ValueRecord2--for the second glyph 27 * in the pair--may be zero (0) */ 28 Array16Of<typename Types::template OffsetTo<PairSet>> 29 pairSet; /* Array of PairSet tables 30 * ordered by Coverage Index */ 31 public: 32 DEFINE_SIZE_ARRAY (8 + Types::size, pairSet); 33 sanitizeOT::Layout::GPOS_impl::PairPosFormat1_334 bool sanitize (hb_sanitize_context_t *c) const 35 { 36 TRACE_SANITIZE (this); 37 38 if (!c->check_struct (this)) return_trace (false); 39 hb_barrier (); 40 41 unsigned int len1 = valueFormat[0].get_len (); 42 unsigned int len2 = valueFormat[1].get_len (); 43 typename PairSet::sanitize_closure_t closure = 44 { 45 valueFormat, 46 len1, 47 PairSet::get_size (len1, len2) 48 }; 49 50 return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); 51 } 52 intersectsOT::Layout::GPOS_impl::PairPosFormat1_353 bool intersects (const hb_set_t *glyphs) const 54 { 55 auto &cov = this+coverage; 56 57 if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) 58 { 59 for (hb_codepoint_t g : glyphs->iter()) 60 { 61 unsigned i = cov.get_coverage (g); 62 if ((this+pairSet[i]).intersects (glyphs, valueFormat)) 63 return true; 64 } 65 return false; 66 } 67 68 return 69 + hb_zip (cov, pairSet) 70 | hb_filter (*glyphs, hb_first) 71 | hb_map (hb_second) 72 | hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_) 73 { return (this+_).intersects (glyphs, valueFormat); }) 74 | hb_any 75 ; 76 } 77 closure_lookupsOT::Layout::GPOS_impl::PairPosFormat1_378 void closure_lookups (hb_closure_lookups_context_t *c) const {} collect_variation_indicesOT::Layout::GPOS_impl::PairPosFormat1_379 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 80 { 81 if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return; 82 83 auto it = 84 + hb_zip (this+coverage, pairSet) 85 | hb_filter (c->glyph_set, hb_first) 86 | hb_map (hb_second) 87 ; 88 89 if (!it) return; 90 + it 91 | hb_map (hb_add (this)) 92 | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); }) 93 ; 94 } 95 collect_glyphsOT::Layout::GPOS_impl::PairPosFormat1_396 void collect_glyphs (hb_collect_glyphs_context_t *c) const 97 { 98 if (unlikely (!(this+coverage).collect_coverage (c->input))) return; 99 unsigned int count = pairSet.len; 100 for (unsigned int i = 0; i < count; i++) 101 (this+pairSet[i]).collect_glyphs (c, valueFormat); 102 } 103 get_coverageOT::Layout::GPOS_impl::PairPosFormat1_3104 const Coverage &get_coverage () const { return this+coverage; } 105 applyOT::Layout::GPOS_impl::PairPosFormat1_3106 bool apply (hb_ot_apply_context_t *c) const 107 { 108 TRACE_APPLY (this); 109 hb_buffer_t *buffer = c->buffer; 110 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 111 if (likely (index == NOT_COVERED)) return_trace (false); 112 113 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 114 skippy_iter.reset_fast (buffer->idx); 115 unsigned unsafe_to; 116 if (unlikely (!skippy_iter.next (&unsafe_to))) 117 { 118 buffer->unsafe_to_concat (buffer->idx, unsafe_to); 119 return_trace (false); 120 } 121 122 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); 123 } 124 subsetOT::Layout::GPOS_impl::PairPosFormat1_3125 bool subset (hb_subset_context_t *c) const 126 { 127 TRACE_SUBSET (this); 128 129 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 130 const hb_map_t &glyph_map = *c->plan->glyph_map; 131 132 auto *out = c->serializer->start_embed (*this); 133 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 134 out->format = format; 135 136 hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]); 137 138 if (c->plan->normalized_coords) 139 { 140 /* all device flags will be dropped when full instancing, no need to strip 141 * hints, also do not strip emtpy cause we don't compute the new default 142 * value during stripping */ 143 newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map); 144 } 145 /* do not strip hints for VF */ 146 else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) 147 { 148 hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); 149 bool has_fvar = (blob != hb_blob_get_empty ()); 150 hb_blob_destroy (blob); 151 152 bool strip = !has_fvar; 153 /* special case: strip hints when a VF has no GDEF varstore after 154 * subsetting*/ 155 if (has_fvar && !c->plan->has_gdef_varstore) 156 strip = true; 157 newFormats = compute_effective_value_formats (glyphset, strip, true); 158 } 159 160 out->valueFormat[0] = newFormats.first; 161 out->valueFormat[1] = newFormats.second; 162 163 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 164 165 + hb_zip (this+coverage, pairSet) 166 | hb_filter (glyphset, hb_first) 167 | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _) 168 { 169 auto snap = c->serializer->snapshot (); 170 auto *o = out->pairSet.serialize_append (c->serializer); 171 if (unlikely (!o)) return false; 172 bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat); 173 if (!ret) 174 { 175 out->pairSet.pop (); 176 c->serializer->revert (snap); 177 } 178 return ret; 179 }, 180 hb_second) 181 | hb_map (hb_first) 182 | hb_map (glyph_map) 183 | hb_sink (new_coverage) 184 ; 185 186 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 187 188 return_trace (bool (new_coverage)); 189 } 190 191 compute_effective_value_formatsOT::Layout::GPOS_impl::PairPosFormat1_3192 hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset, 193 bool strip_hints, bool strip_empty, 194 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const 195 { 196 unsigned record_size = PairSet::get_size (valueFormat); 197 198 unsigned format1 = 0; 199 unsigned format2 = 0; 200 for (const auto & _ : 201 + hb_zip (this+coverage, pairSet) 202 | hb_filter (glyphset, hb_first) 203 | hb_map (hb_second) 204 ) 205 { 206 const PairSet& set = (this + _); 207 const PairValueRecord *record = &set.firstPairValueRecord; 208 209 unsigned count = set.len; 210 for (unsigned i = 0; i < count; i++) 211 { 212 if (record->intersects (glyphset)) 213 { 214 format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map); 215 format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map); 216 } 217 record = &StructAtOffset<const PairValueRecord> (record, record_size); 218 } 219 220 if (format1 == valueFormat[0] && format2 == valueFormat[1]) 221 break; 222 } 223 224 return hb_pair (format1, format2); 225 } 226 }; 227 228 229 } 230 } 231 } 232 233 #endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH 234