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 mark2Array.sanitize (c, this, (unsigned int) classCount)); 46 } 47 intersectsOT::Layout::GPOS_impl::MarkMarkPosFormat1_248 bool intersects (const hb_set_t *glyphs) const 49 { 50 return (this+mark1Coverage).intersects (glyphs) && 51 (this+mark2Coverage).intersects (glyphs); 52 } 53 closure_lookupsOT::Layout::GPOS_impl::MarkMarkPosFormat1_254 void closure_lookups (hb_closure_lookups_context_t *c) const {} 55 collect_variation_indicesOT::Layout::GPOS_impl::MarkMarkPosFormat1_256 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 57 { 58 + hb_zip (this+mark1Coverage, this+mark1Array) 59 | hb_filter (c->glyph_set, hb_first) 60 | hb_map (hb_second) 61 | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) 62 ; 63 64 hb_map_t klass_mapping; 65 Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); 66 67 unsigned mark2_count = (this+mark2Array).rows; 68 auto mark2_iter = 69 + hb_zip (this+mark2Coverage, hb_range (mark2_count)) 70 | hb_filter (c->glyph_set, hb_first) 71 | hb_map (hb_second) 72 ; 73 74 hb_sorted_vector_t<unsigned> mark2_indexes; 75 for (const unsigned row : mark2_iter) 76 { 77 + hb_range ((unsigned) classCount) 78 | hb_filter (klass_mapping) 79 | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) 80 | hb_sink (mark2_indexes) 81 ; 82 } 83 (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); 84 } 85 collect_glyphsOT::Layout::GPOS_impl::MarkMarkPosFormat1_286 void collect_glyphs (hb_collect_glyphs_context_t *c) const 87 { 88 if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; 89 if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; 90 } 91 get_coverageOT::Layout::GPOS_impl::MarkMarkPosFormat1_292 const Coverage &get_coverage () const { return this+mark1Coverage; } 93 applyOT::Layout::GPOS_impl::MarkMarkPosFormat1_294 bool apply (hb_ot_apply_context_t *c) const 95 { 96 TRACE_APPLY (this); 97 hb_buffer_t *buffer = c->buffer; 98 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); 99 if (likely (mark1_index == NOT_COVERED)) return_trace (false); 100 101 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ 102 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; 103 skippy_iter.reset (buffer->idx, 1); 104 skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); 105 unsigned unsafe_from; 106 if (!skippy_iter.prev (&unsafe_from)) 107 { 108 buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); 109 return_trace (false); 110 } 111 112 if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) 113 { 114 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 115 return_trace (false); 116 } 117 118 unsigned int j = skippy_iter.idx; 119 120 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); 121 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); 122 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); 123 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); 124 125 if (likely (id1 == id2)) 126 { 127 if (id1 == 0) /* Marks belonging to the same base. */ 128 goto good; 129 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ 130 goto good; 131 } 132 else 133 { 134 /* If ligature ids don't match, it may be the case that one of the marks 135 * itself is a ligature. In which case match. */ 136 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) 137 goto good; 138 } 139 140 /* Didn't match. */ 141 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 142 return_trace (false); 143 144 good: 145 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); 146 if (mark2_index == NOT_COVERED) 147 { 148 buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); 149 return_trace (false); 150 } 151 152 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); 153 } 154 subsetOT::Layout::GPOS_impl::MarkMarkPosFormat1_2155 bool subset (hb_subset_context_t *c) const 156 { 157 TRACE_SUBSET (this); 158 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 159 const hb_map_t &glyph_map = *c->plan->glyph_map; 160 161 auto *out = c->serializer->start_embed (*this); 162 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 163 out->format = format; 164 165 hb_map_t klass_mapping; 166 Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping); 167 168 if (!klass_mapping.get_population ()) return_trace (false); 169 out->classCount = klass_mapping.get_population (); 170 171 auto mark1_iter = 172 + hb_zip (this+mark1Coverage, this+mark1Array) 173 | hb_filter (glyphset, hb_first) 174 ; 175 176 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 177 + mark1_iter 178 | hb_map (hb_first) 179 | hb_map (glyph_map) 180 | hb_sink (new_coverage) 181 ; 182 183 if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) 184 return_trace (false); 185 186 out->mark1Array.serialize_subset (c, mark1Array, this, 187 (this+mark1Coverage).iter (), 188 &klass_mapping); 189 190 unsigned mark2count = (this+mark2Array).rows; 191 auto mark2_iter = 192 + hb_zip (this+mark2Coverage, hb_range (mark2count)) 193 | hb_filter (glyphset, hb_first) 194 ; 195 196 new_coverage.reset (); 197 + mark2_iter 198 | hb_map (hb_first) 199 | hb_map (glyph_map) 200 | hb_sink (new_coverage) 201 ; 202 203 if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) 204 return_trace (false); 205 206 hb_sorted_vector_t<unsigned> mark2_indexes; 207 for (const unsigned row : + mark2_iter 208 | hb_map (hb_second)) 209 { 210 + hb_range ((unsigned) classCount) 211 | hb_filter (klass_mapping) 212 | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) 213 | hb_sink (mark2_indexes) 214 ; 215 } 216 217 out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ()); 218 219 return_trace (true); 220 } 221 }; 222 223 224 } 225 } 226 } 227 228 #endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */ 229