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 | static unsigned get_size (unsigned len1, unsigned len2) |
28 | { |
29 | return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); |
30 | } |
31 | 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 | |
45 | 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 | |
60 | 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 | |
76 | 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 | |
85 | 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 | |
101 | 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 | |
160 | 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 | |