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