1 #ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH 2 #define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH 3 4 #include "MarkMarkPosFormat1.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GPOS_impl { 9 10 typedef AnchorMatrix Mark2Array; /* mark2-major-- 11 * in order of Mark2Coverage Index--, 12 * mark1-minor-- 13 * ordered by class--zero-based. */ 14 15 template <typename Types> 16 struct MarkMarkPosFormat1_2 17 { 18 protected: 19 HBUINT16 format; /* Format identifier--format = 1 */ 20 typename Types::template OffsetTo<Coverage> 21 mark1Coverage; /* Offset to Combining Mark1 Coverage 22 * table--from beginning of MarkMarkPos 23 * subtable */ 24 typename Types::template OffsetTo<Coverage> 25 mark2Coverage; /* Offset to Combining Mark2 Coverage 26 * table--from beginning of MarkMarkPos 27 * subtable */ 28 HBUINT16 classCount; /* Number of defined mark classes */ 29 typename Types::template OffsetTo<MarkArray> 30 mark1Array; /* Offset to Mark1Array table--from 31 * beginning of MarkMarkPos subtable */ 32 typename Types::template OffsetTo<Mark2Array> 33 mark2Array; /* Offset to Mark2Array table--from 34 * beginning of MarkMarkPos subtable */ 35 public: 36 DEFINE_SIZE_STATIC (4 + 4 * Types::size); 37 sanitizeOT::Layout::GPOS_impl::MarkMarkPosFormat1_238 bool sanitize (hb_sanitize_context_t *c) const 39 { 40 TRACE_SANITIZE (this); 41 return_trace (c->check_struct (this) && 42 mark1Coverage.sanitize (c, this) && 43 mark2Coverage.sanitize (c, this) && 44 mark1Array.sanitize (c, this) && 45 hb_barrier () && 46 mark2Array.sanitize (c, this, (unsigned int) classCount)); 47 } 48 intersectsOT::Layout::GPOS_impl::MarkMarkPosFormat1_249 bool intersects (const hb_set_t *glyphs) const 50 { 51 return (this+mark1Coverage).intersects (glyphs) && 52 (this+mark2Coverage).intersects (glyphs); 53 } 54 closure_lookupsOT::Layout::GPOS_impl::MarkMarkPosFormat1_255 void closure_lookups (hb_closure_lookups_context_t *c) const {} 56 collect_variation_indicesOT::Layout::GPOS_impl::MarkMarkPosFormat1_257 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 58 { 59 + hb_zip (this+mark1Coverage, this+mark1Array) 60 | hb_filter (c->glyph_set, hb_first) 61 | hb_map (hb_second) 62 | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) 63 ; 64 65 hb_map_t klass_mapping; 66 Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); 67 68 unsigned mark2_count = (this+mark2Array).rows; 69 auto mark2_iter = 70 + hb_zip (this+mark2Coverage, hb_range (mark2_count)) 71 | hb_filter (c->glyph_set, hb_first) 72 | hb_map (hb_second) 73 ; 74 75 hb_sorted_vector_t<unsigned> mark2_indexes; 76 for (const unsigned row : mark2_iter) 77 { 78 + hb_range ((unsigned) classCount) 79 | hb_filter (klass_mapping) 80 | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) 81 | hb_sink (mark2_indexes) 82 ; 83 } 84 (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); 85 } 86 collect_glyphsOT::Layout::GPOS_impl::MarkMarkPosFormat1_287 void collect_glyphs (hb_collect_glyphs_context_t *c) const 88 { 89 if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; 90 if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; 91 } 92 get_coverageOT::Layout::GPOS_impl::MarkMarkPosFormat1_293 const Coverage &get_coverage () const { return this+mark1Coverage; } 94 applyOT::Layout::GPOS_impl::MarkMarkPosFormat1_295 bool apply (hb_ot_apply_context_t *c) const 96 { 97 TRACE_APPLY (this); 98 hb_buffer_t *buffer = c->buffer; 99 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); 100 if (likely (mark1_index == NOT_COVERED)) return_trace (false); 101 102 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ 103 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 104 skippy_iter.reset_fast (buffer->idx); 105 skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); 106 unsigned unsafe_from; 107 if (unlikely (!skippy_iter.prev (&unsafe_from))) 108 { 109 buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); 110 return_trace (false); 111 } 112 113 if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))) 114 { 115 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 116 return_trace (false); 117 } 118 119 unsigned int j = skippy_iter.idx; 120 121 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); 122 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); 123 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); 124 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); 125 126 if (likely (id1 == id2)) 127 { 128 if (id1 == 0) /* Marks belonging to the same base. */ 129 goto good; 130 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ 131 goto good; 132 } 133 else 134 { 135 /* If ligature ids don't match, it may be the case that one of the marks 136 * itself is a ligature. In which case match. */ 137 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) 138 goto good; 139 } 140 141 /* Didn't match. */ 142 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 143 return_trace (false); 144 145 good: 146 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); 147 if (mark2_index == NOT_COVERED) 148 { 149 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 150 return_trace (false); 151 } 152 153 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); 154 } 155 subsetOT::Layout::GPOS_impl::MarkMarkPosFormat1_2156 bool subset (hb_subset_context_t *c) const 157 { 158 TRACE_SUBSET (this); 159 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 160 const hb_map_t &glyph_map = *c->plan->glyph_map; 161 162 auto *out = c->serializer->start_embed (*this); 163 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 164 out->format = format; 165 166 hb_map_t klass_mapping; 167 Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping); 168 169 if (!klass_mapping.get_population ()) return_trace (false); 170 out->classCount = klass_mapping.get_population (); 171 172 auto mark1_iter = 173 + hb_zip (this+mark1Coverage, this+mark1Array) 174 | hb_filter (glyphset, hb_first) 175 ; 176 177 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 178 + mark1_iter 179 | hb_map (hb_first) 180 | hb_map (glyph_map) 181 | hb_sink (new_coverage) 182 ; 183 184 if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) 185 return_trace (false); 186 187 if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this, 188 (this+mark1Coverage).iter (), 189 &klass_mapping))) 190 return_trace (false); 191 192 unsigned mark2count = (this+mark2Array).rows; 193 auto mark2_iter = 194 + hb_zip (this+mark2Coverage, hb_range (mark2count)) 195 | hb_filter (glyphset, hb_first) 196 ; 197 198 new_coverage.reset (); 199 + mark2_iter 200 | hb_map (hb_first) 201 | hb_map (glyph_map) 202 | hb_sink (new_coverage) 203 ; 204 205 if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) 206 return_trace (false); 207 208 hb_sorted_vector_t<unsigned> mark2_indexes; 209 for (const unsigned row : + mark2_iter 210 | hb_map (hb_second)) 211 { 212 + hb_range ((unsigned) classCount) 213 | hb_filter (klass_mapping) 214 | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) 215 | hb_sink (mark2_indexes) 216 ; 217 } 218 219 return_trace (out->mark2Array.serialize_subset (c, mark2Array, this, 220 mark2_iter.len (), 221 mark2_indexes.iter ())); 222 223 } 224 }; 225 226 227 } 228 } 229 } 230 231 #endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */ 232