PairPosFormat1.hh (8304B)
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 34 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 53 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)) 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 78 void closure_lookups (hb_closure_lookups_context_t *c) const {} 79 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 96 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 104 const Coverage &get_coverage () const { return this+coverage; } 105 106 struct external_cache_t 107 { 108 hb_ot_layout_mapping_cache_t coverage; 109 }; 110 void *external_cache_create () const 111 { 112 external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); 113 if (likely (cache)) 114 { 115 cache->coverage.clear (); 116 } 117 return cache; 118 } 119 120 bool apply (hb_ot_apply_context_t *c, void *external_cache) const 121 { 122 TRACE_APPLY (this); 123 124 hb_buffer_t *buffer = c->buffer; 125 126 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE 127 external_cache_t *cache = (external_cache_t *) external_cache; 128 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); 129 #else 130 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 131 #endif 132 if (index == NOT_COVERED) return_trace (false); 133 134 auto &skippy_iter = c->iter_input; 135 skippy_iter.reset_fast (buffer->idx); 136 unsigned unsafe_to; 137 if (unlikely (!skippy_iter.next (&unsafe_to))) 138 { 139 buffer->unsafe_to_concat (buffer->idx, unsafe_to); 140 return_trace (false); 141 } 142 143 return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); 144 } 145 146 bool subset (hb_subset_context_t *c) const 147 { 148 TRACE_SUBSET (this); 149 150 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 151 const hb_map_t &glyph_map = *c->plan->glyph_map; 152 153 auto *out = c->serializer->start_embed (*this); 154 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 155 out->format = format; 156 157 hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]); 158 159 if (c->plan->normalized_coords) 160 { 161 /* all device flags will be dropped when full instancing, no need to strip 162 * hints, also do not strip emtpy cause we don't compute the new default 163 * value during stripping */ 164 newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map); 165 } 166 /* do not strip hints for VF */ 167 else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) 168 { 169 hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r')); 170 bool has_fvar = (blob != hb_blob_get_empty ()); 171 hb_blob_destroy (blob); 172 173 bool strip = !has_fvar; 174 /* special case: strip hints when a VF has no GDEF varstore after 175 * subsetting*/ 176 if (has_fvar && !c->plan->has_gdef_varstore) 177 strip = true; 178 newFormats = compute_effective_value_formats (glyphset, strip, true); 179 } 180 181 out->valueFormat[0] = newFormats.first; 182 out->valueFormat[1] = newFormats.second; 183 184 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 185 186 + hb_zip (this+coverage, pairSet) 187 | hb_filter (glyphset, hb_first) 188 | hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _) 189 { 190 auto snap = c->serializer->snapshot (); 191 auto *o = out->pairSet.serialize_append (c->serializer); 192 if (unlikely (!o)) return false; 193 bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat); 194 if (!ret) 195 { 196 out->pairSet.pop (); 197 c->serializer->revert (snap); 198 } 199 return ret; 200 }, 201 hb_second) 202 | hb_map (hb_first) 203 | hb_map (glyph_map) 204 | hb_sink (new_coverage) 205 ; 206 207 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 208 209 return_trace (bool (new_coverage)); 210 } 211 212 213 hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset, 214 bool strip_hints, bool strip_empty, 215 const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const 216 { 217 unsigned record_size = PairSet::get_size (valueFormat); 218 219 unsigned format1 = 0; 220 unsigned format2 = 0; 221 for (const auto & _ : 222 + hb_zip (this+coverage, pairSet) 223 | hb_filter (glyphset, hb_first) 224 | hb_map (hb_second) 225 ) 226 { 227 const PairSet& set = (this + _); 228 const PairValueRecord *record = &set.firstPairValueRecord; 229 230 unsigned count = set.len; 231 for (unsigned i = 0; i < count; i++) 232 { 233 if (record->intersects (glyphset)) 234 { 235 format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map); 236 format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map); 237 } 238 record = &StructAtOffset<const PairValueRecord> (record, record_size); 239 } 240 241 if (format1 == valueFormat[0] && format2 == valueFormat[1]) 242 break; 243 } 244 245 return hb_pair (format1, format2); 246 } 247 }; 248 249 250 } 251 } 252 } 253 254 #endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH