1 #ifndef OT_LAYOUT_GPOS_PAIRSET_HH 2 #define OT_LAYOUT_GPOS_PAIRSET_HH 3 4 #include "PairValueRecord.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GPOS_impl { 9 10 11 template <typename Types> 12 struct PairSet 13 { 14 template <typename Types2> 15 friend struct PairPosFormat1_3; 16 17 using PairValueRecord = GPOS_impl::PairValueRecord<Types>; 18 19 protected: 20 HBUINT16 len; /* Number of PairValueRecords */ 21 PairValueRecord firstPairValueRecord; 22 /* Array of PairValueRecords--ordered 23 * by GlyphID of the second glyph */ 24 public: 25 DEFINE_SIZE_MIN (2); 26 get_sizeOT::Layout::GPOS_impl::PairSet27 static unsigned get_size (unsigned len1, unsigned len2) 28 { 29 return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); 30 } get_sizeOT::Layout::GPOS_impl::PairSet31 static unsigned get_size (const ValueFormat valueFormats[2]) 32 { 33 unsigned len1 = valueFormats[0].get_len (); 34 unsigned len2 = valueFormats[1].get_len (); 35 return get_size (len1, len2); 36 } 37 38 struct sanitize_closure_t 39 { 40 const ValueFormat *valueFormats; 41 unsigned int len1; /* valueFormats[0].get_len() */ 42 unsigned int stride; /* bytes */ 43 }; 44 sanitizeOT::Layout::GPOS_impl::PairSet45 bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const 46 { 47 TRACE_SANITIZE (this); 48 if (!(c->check_struct (this) 49 && c->check_range (&firstPairValueRecord, 50 len, 51 closure->stride))) return_trace (false); 52 53 unsigned int count = len; 54 const PairValueRecord *record = &firstPairValueRecord; 55 return_trace (c->lazy_some_gpos || 56 (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && 57 closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride))); 58 } 59 intersectsOT::Layout::GPOS_impl::PairSet60 bool intersects (const hb_set_t *glyphs, 61 const ValueFormat *valueFormats) const 62 { 63 unsigned record_size = get_size (valueFormats); 64 65 const PairValueRecord *record = &firstPairValueRecord; 66 unsigned int count = len; 67 for (unsigned int i = 0; i < count; i++) 68 { 69 if (glyphs->has (record->secondGlyph)) 70 return true; 71 record = &StructAtOffset<const PairValueRecord> (record, record_size); 72 } 73 return false; 74 } 75 collect_glyphsOT::Layout::GPOS_impl::PairSet76 void collect_glyphs (hb_collect_glyphs_context_t *c, 77 const ValueFormat *valueFormats) const 78 { 79 unsigned record_size = get_size (valueFormats); 80 81 const PairValueRecord *record = &firstPairValueRecord; 82 c->input->add_array (&record->secondGlyph, len, record_size); 83 } 84 collect_variation_indicesOT::Layout::GPOS_impl::PairSet85 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 86 const ValueFormat *valueFormats) const 87 { 88 unsigned record_size = get_size (valueFormats); 89 90 const PairValueRecord *record = &firstPairValueRecord; 91 unsigned count = len; 92 for (unsigned i = 0; i < count; i++) 93 { 94 if (c->glyph_set->has (record->secondGlyph)) 95 { record->collect_variation_indices (c, valueFormats, this); } 96 97 record = &StructAtOffset<const PairValueRecord> (record, record_size); 98 } 99 } 100 applyOT::Layout::GPOS_impl::PairSet101 bool apply (hb_ot_apply_context_t *c, 102 const ValueFormat *valueFormats, 103 unsigned int pos) const 104 { 105 TRACE_APPLY (this); 106 hb_buffer_t *buffer = c->buffer; 107 unsigned int len1 = valueFormats[0].get_len (); 108 unsigned int len2 = valueFormats[1].get_len (); 109 unsigned record_size = get_size (len1, len2); 110 111 const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, 112 &firstPairValueRecord, 113 len, 114 record_size); 115 if (record) 116 { 117 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 118 { 119 c->buffer->message (c->font, 120 "try kerning glyphs at %u,%u", 121 c->buffer->idx, pos); 122 } 123 124 bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); 125 bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); 126 127 if (applied_first || applied_second) 128 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 129 { 130 c->buffer->message (c->font, 131 "kerned glyphs at %u,%u", 132 c->buffer->idx, pos); 133 } 134 135 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 136 { 137 c->buffer->message (c->font, 138 "tried kerning glyphs at %u,%u", 139 c->buffer->idx, pos); 140 } 141 142 if (applied_first || applied_second) 143 buffer->unsafe_to_break (buffer->idx, pos + 1); 144 145 if (len2) 146 { 147 pos++; 148 // https://github.com/harfbuzz/harfbuzz/issues/3824 149 // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 150 buffer->unsafe_to_break (buffer->idx, pos + 1); 151 } 152 153 buffer->idx = pos; 154 return_trace (true); 155 } 156 buffer->unsafe_to_concat (buffer->idx, pos + 1); 157 return_trace (false); 158 } 159 subsetOT::Layout::GPOS_impl::PairSet160 bool subset (hb_subset_context_t *c, 161 const ValueFormat valueFormats[2], 162 const ValueFormat newFormats[2]) const 163 { 164 TRACE_SUBSET (this); 165 auto snap = c->serializer->snapshot (); 166 167 auto *out = c->serializer->start_embed (*this); 168 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 169 out->len = 0; 170 171 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 172 const hb_map_t &glyph_map = *c->plan->glyph_map; 173 174 unsigned len1 = valueFormats[0].get_len (); 175 unsigned len2 = valueFormats[1].get_len (); 176 unsigned record_size = get_size (len1, len2); 177 178 typename PairValueRecord::context_t context = 179 { 180 this, 181 valueFormats, 182 newFormats, 183 len1, 184 &glyph_map, 185 &c->plan->layout_variation_idx_delta_map 186 }; 187 188 const PairValueRecord *record = &firstPairValueRecord; 189 unsigned count = len, num = 0; 190 for (unsigned i = 0; i < count; i++) 191 { 192 if (glyphset.has (record->secondGlyph) 193 && record->subset (c, &context)) num++; 194 record = &StructAtOffset<const PairValueRecord> (record, record_size); 195 } 196 197 out->len = num; 198 if (!num) c->serializer->revert (snap); 199 return_trace (num); 200 } 201 }; 202 203 204 } 205 } 206 } 207 208 #endif // OT_LAYOUT_GPOS_PAIRSET_HH 209