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 : ValueBase 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 hb_barrier () && 50 c->check_range (&firstPairValueRecord, 51 len, 52 closure->stride))) return_trace (false); 53 hb_barrier (); 54 55 unsigned int count = len; 56 const PairValueRecord *record = &firstPairValueRecord; 57 return_trace (c->lazy_some_gpos || 58 (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && 59 closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride))); 60 } 61 intersectsOT::Layout::GPOS_impl::PairSet62 bool intersects (const hb_set_t *glyphs, 63 const ValueFormat *valueFormats) const 64 { 65 unsigned record_size = get_size (valueFormats); 66 67 const PairValueRecord *record = &firstPairValueRecord; 68 unsigned int count = len; 69 for (unsigned int i = 0; i < count; i++) 70 { 71 if (glyphs->has (record->secondGlyph)) 72 return true; 73 record = &StructAtOffset<const PairValueRecord> (record, record_size); 74 } 75 return false; 76 } 77 collect_glyphsOT::Layout::GPOS_impl::PairSet78 void collect_glyphs (hb_collect_glyphs_context_t *c, 79 const ValueFormat *valueFormats) const 80 { 81 unsigned record_size = get_size (valueFormats); 82 83 const PairValueRecord *record = &firstPairValueRecord; 84 c->input->add_array (&record->secondGlyph, len, record_size); 85 } 86 collect_variation_indicesOT::Layout::GPOS_impl::PairSet87 void collect_variation_indices (hb_collect_variation_indices_context_t *c, 88 const ValueFormat *valueFormats) const 89 { 90 unsigned record_size = get_size (valueFormats); 91 92 const PairValueRecord *record = &firstPairValueRecord; 93 unsigned count = len; 94 for (unsigned i = 0; i < count; i++) 95 { 96 if (c->glyph_set->has (record->secondGlyph)) 97 { record->collect_variation_indices (c, valueFormats, this); } 98 99 record = &StructAtOffset<const PairValueRecord> (record, record_size); 100 } 101 } 102 applyOT::Layout::GPOS_impl::PairSet103 bool apply (hb_ot_apply_context_t *c, 104 const ValueFormat *valueFormats, 105 unsigned int pos) const 106 { 107 TRACE_APPLY (this); 108 hb_buffer_t *buffer = c->buffer; 109 unsigned int len1 = valueFormats[0].get_len (); 110 unsigned int len2 = valueFormats[1].get_len (); 111 unsigned record_size = get_size (len1, len2); 112 113 const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, 114 &firstPairValueRecord, 115 len, 116 record_size); 117 if (record) 118 { 119 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 120 { 121 c->buffer->message (c->font, 122 "try kerning glyphs at %u,%u", 123 c->buffer->idx, pos); 124 } 125 126 bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); 127 bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); 128 129 if (applied_first || applied_second) 130 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 131 { 132 c->buffer->message (c->font, 133 "kerned glyphs at %u,%u", 134 c->buffer->idx, pos); 135 } 136 137 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 138 { 139 c->buffer->message (c->font, 140 "tried kerning glyphs at %u,%u", 141 c->buffer->idx, pos); 142 } 143 144 if (applied_first || applied_second) 145 buffer->unsafe_to_break (buffer->idx, pos + 1); 146 147 if (len2) 148 { 149 pos++; 150 // https://github.com/harfbuzz/harfbuzz/issues/3824 151 // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 152 buffer->unsafe_to_break (buffer->idx, pos + 1); 153 } 154 155 buffer->idx = pos; 156 return_trace (true); 157 } 158 buffer->unsafe_to_concat (buffer->idx, pos + 1); 159 return_trace (false); 160 } 161 subsetOT::Layout::GPOS_impl::PairSet162 bool subset (hb_subset_context_t *c, 163 const ValueFormat valueFormats[2], 164 const ValueFormat newFormats[2]) const 165 { 166 TRACE_SUBSET (this); 167 auto snap = c->serializer->snapshot (); 168 169 auto *out = c->serializer->start_embed (*this); 170 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 171 out->len = 0; 172 173 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 174 const hb_map_t &glyph_map = *c->plan->glyph_map; 175 176 unsigned len1 = valueFormats[0].get_len (); 177 unsigned len2 = valueFormats[1].get_len (); 178 unsigned record_size = get_size (len1, len2); 179 180 typename PairValueRecord::context_t context = 181 { 182 this, 183 valueFormats, 184 newFormats, 185 len1, 186 &glyph_map, 187 &c->plan->layout_variation_idx_delta_map 188 }; 189 190 const PairValueRecord *record = &firstPairValueRecord; 191 unsigned count = len, num = 0; 192 for (unsigned i = 0; i < count; i++) 193 { 194 if (glyphset.has (record->secondGlyph) 195 && record->subset (c, &context)) num++; 196 record = &StructAtOffset<const PairValueRecord> (record, record_size); 197 } 198 199 out->len = num; 200 if (!num) c->serializer->revert (snap); 201 return_trace (num); 202 } 203 }; 204 205 206 } 207 } 208 } 209 210 #endif // OT_LAYOUT_GPOS_PAIRSET_HH 211