/src/harfbuzz/src/hb-ot-math-table.hh
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2016 Igalia S.L. |
3 | | * |
4 | | * This is part of HarfBuzz, a text shaping library. |
5 | | * |
6 | | * Permission is hereby granted, without written agreement and without |
7 | | * license or royalty fees, to use, copy, modify, and distribute this |
8 | | * software and its documentation for any purpose, provided that the |
9 | | * above copyright notice and the following two paragraphs appear in |
10 | | * all copies of this software. |
11 | | * |
12 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | | * DAMAGE. |
17 | | * |
18 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | | * |
24 | | * Igalia Author(s): Frédéric Wang |
25 | | */ |
26 | | |
27 | | #ifndef HB_OT_MATH_TABLE_HH |
28 | | #define HB_OT_MATH_TABLE_HH |
29 | | |
30 | | #include "hb-open-type.hh" |
31 | | #include "hb-ot-layout-common.hh" |
32 | | #include "hb-ot-math.h" |
33 | | |
34 | | namespace OT { |
35 | | |
36 | | |
37 | | struct MathValueRecord |
38 | | { |
39 | | hb_position_t get_x_value (hb_font_t *font, const void *base) const |
40 | 234k | { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); } |
41 | | hb_position_t get_y_value (hb_font_t *font, const void *base) const |
42 | 1.57M | { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } |
43 | | |
44 | | MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const |
45 | 0 | { |
46 | 0 | TRACE_SERIALIZE (this); |
47 | 0 | auto *out = c->embed (this); |
48 | 0 | if (unlikely (!out)) return_trace (nullptr); |
49 | 0 | out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head); |
50 | 0 |
|
51 | 0 | return_trace (out); |
52 | 0 | } |
53 | | |
54 | | bool sanitize (hb_sanitize_context_t *c, const void *base) const |
55 | 3.58M | { |
56 | 3.58M | TRACE_SANITIZE (this); |
57 | 3.58M | return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); |
58 | 3.58M | } |
59 | | |
60 | | protected: |
61 | | HBINT16 value; /* The X or Y value in design units */ |
62 | | Offset16To<Device> deviceTable; /* Offset to the device table - from the |
63 | | * beginning of parent table. May be NULL. |
64 | | * Suggested format for device table is 1. */ |
65 | | |
66 | | public: |
67 | | DEFINE_SIZE_STATIC (4); |
68 | | }; |
69 | | |
70 | | struct MathConstants |
71 | | { |
72 | | friend struct MATH; |
73 | | |
74 | | MathConstants* copy (hb_serialize_context_t *c) const |
75 | 0 | { |
76 | 0 | TRACE_SERIALIZE (this); |
77 | 0 | auto *out = c->start_embed (this); |
78 | 0 |
|
79 | 0 | HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2); |
80 | 0 | if (unlikely (!p)) return_trace (nullptr); |
81 | 0 | hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2); |
82 | 0 |
|
83 | 0 | HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2); |
84 | 0 | if (unlikely (!m)) return_trace (nullptr); |
85 | 0 | hb_memcpy (m, minHeight, HBUINT16::static_size * 2); |
86 | 0 |
|
87 | 0 | unsigned count = ARRAY_LENGTH (mathValueRecords); |
88 | 0 | for (unsigned i = 0; i < count; i++) |
89 | 0 | if (!c->copy (mathValueRecords[i], this)) |
90 | 0 | return_trace (nullptr); |
91 | 0 |
|
92 | 0 | if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr); |
93 | 0 | return_trace (out); |
94 | 0 | } |
95 | | |
96 | | bool sanitize_math_value_records (hb_sanitize_context_t *c) const |
97 | 219 | { |
98 | 219 | TRACE_SANITIZE (this); |
99 | | |
100 | 219 | unsigned int count = ARRAY_LENGTH (mathValueRecords); |
101 | 9.79k | for (unsigned int i = 0; i < count; i++) |
102 | 9.62k | if (!mathValueRecords[i].sanitize (c, this)) |
103 | 45 | return_trace (false); |
104 | | |
105 | 219 | return_trace (true); |
106 | 219 | } |
107 | | |
108 | | bool sanitize (hb_sanitize_context_t *c) const |
109 | 228 | { |
110 | 228 | TRACE_SANITIZE (this); |
111 | 228 | return_trace (c->check_struct (this) && sanitize_math_value_records (c)); |
112 | 228 | } |
113 | | |
114 | | hb_position_t get_value (hb_ot_math_constant_t constant, |
115 | | hb_font_t *font) const |
116 | 1.87M | { |
117 | 1.87M | switch (constant) { |
118 | | |
119 | 33.5k | case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: |
120 | 67.0k | case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: |
121 | 67.0k | return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; |
122 | | |
123 | 33.5k | case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: |
124 | 67.0k | case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: |
125 | 67.0k | return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); |
126 | | |
127 | 33.5k | case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: |
128 | 67.0k | case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: |
129 | 100k | case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: |
130 | 134k | case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: |
131 | 134k | return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); |
132 | | |
133 | 33.5k | case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: |
134 | 67.0k | case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: |
135 | 100k | case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: |
136 | 134k | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: |
137 | 167k | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: |
138 | 201k | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: |
139 | 234k | case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: |
140 | 268k | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: |
141 | 301k | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: |
142 | 335k | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: |
143 | 368k | case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: |
144 | 402k | case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: |
145 | 435k | case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: |
146 | 469k | case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: |
147 | 502k | case HB_OT_MATH_CONSTANT_MATH_LEADING: |
148 | 536k | case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: |
149 | 570k | case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: |
150 | 603k | case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: |
151 | 637k | case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: |
152 | 670k | case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: |
153 | 704k | case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: |
154 | 737k | case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: |
155 | 771k | case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: |
156 | 804k | case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: |
157 | 838k | case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: |
158 | 871k | case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: |
159 | 905k | case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: |
160 | 938k | case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: |
161 | 972k | case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: |
162 | 1.00M | case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: |
163 | 1.03M | case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: |
164 | 1.07M | case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: |
165 | 1.10M | case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: |
166 | 1.14M | case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: |
167 | 1.17M | case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: |
168 | 1.20M | case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: |
169 | 1.24M | case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: |
170 | 1.27M | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: |
171 | 1.30M | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: |
172 | 1.34M | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: |
173 | 1.37M | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: |
174 | 1.40M | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: |
175 | 1.44M | case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: |
176 | 1.47M | case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: |
177 | 1.50M | case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: |
178 | 1.54M | case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: |
179 | 1.57M | case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: |
180 | 1.57M | return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); |
181 | | |
182 | 33.5k | case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: |
183 | 33.5k | return radicalDegreeBottomRaisePercent; |
184 | | |
185 | 0 | default: |
186 | 0 | return 0; |
187 | 1.87M | } |
188 | 1.87M | } |
189 | | |
190 | | protected: |
191 | | HBINT16 percentScaleDown[2]; |
192 | | HBUINT16 minHeight[2]; |
193 | | MathValueRecord mathValueRecords[51]; |
194 | | HBINT16 radicalDegreeBottomRaisePercent; |
195 | | |
196 | | public: |
197 | | DEFINE_SIZE_STATIC (214); |
198 | | }; |
199 | | |
200 | | struct MathItalicsCorrectionInfo |
201 | | { |
202 | | bool subset (hb_subset_context_t *c) const |
203 | 0 | { |
204 | 0 | TRACE_SUBSET (this); |
205 | 0 | const hb_set_t &glyphset = c->plan->_glyphset_mathed; |
206 | 0 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
207 | 0 |
|
208 | 0 | auto *out = c->serializer->start_embed (*this); |
209 | 0 | if (unlikely (!c->serializer->extend_min (out))) return_trace (false); |
210 | 0 |
|
211 | 0 | hb_sorted_vector_t<hb_codepoint_t> new_coverage; |
212 | 0 | + hb_zip (this+coverage, italicsCorrection) |
213 | 0 | | hb_filter (glyphset, hb_first) |
214 | 0 | | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second) |
215 | 0 | | hb_map (hb_first) |
216 | 0 | | hb_map (glyph_map) |
217 | 0 | | hb_sink (new_coverage) |
218 | 0 | ; |
219 | 0 |
|
220 | 0 | out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); |
221 | 0 | return_trace (true); |
222 | 0 | } |
223 | | |
224 | | bool sanitize (hb_sanitize_context_t *c) const |
225 | 140 | { |
226 | 140 | TRACE_SANITIZE (this); |
227 | 140 | return_trace (c->check_struct (this) && |
228 | 140 | coverage.sanitize (c, this) && |
229 | 140 | italicsCorrection.sanitize (c, this)); |
230 | 140 | } |
231 | | |
232 | | hb_position_t get_value (hb_codepoint_t glyph, |
233 | | hb_font_t *font) const |
234 | 33.5k | { |
235 | 33.5k | unsigned int index = (this+coverage).get_coverage (glyph); |
236 | 33.5k | return italicsCorrection[index].get_x_value (font, this); |
237 | 33.5k | } |
238 | | |
239 | | protected: |
240 | | Offset16To<Coverage> coverage; /* Offset to Coverage table - |
241 | | * from the beginning of |
242 | | * MathItalicsCorrectionInfo |
243 | | * table. */ |
244 | | Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords |
245 | | * defining italics correction |
246 | | * values for each |
247 | | * covered glyph. */ |
248 | | |
249 | | public: |
250 | | DEFINE_SIZE_ARRAY (4, italicsCorrection); |
251 | | }; |
252 | | |
253 | | struct MathTopAccentAttachment |
254 | | { |
255 | | bool subset (hb_subset_context_t *c) const |
256 | 0 | { |
257 | 0 | TRACE_SUBSET (this); |
258 | 0 | const hb_set_t &glyphset = c->plan->_glyphset_mathed; |
259 | 0 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
260 | 0 |
|
261 | 0 | auto *out = c->serializer->start_embed (*this); |
262 | 0 | if (unlikely (!c->serializer->extend_min (out))) return_trace (false); |
263 | 0 |
|
264 | 0 | hb_sorted_vector_t<hb_codepoint_t> new_coverage; |
265 | 0 | + hb_zip (this+topAccentCoverage, topAccentAttachment) |
266 | 0 | | hb_filter (glyphset, hb_first) |
267 | 0 | | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second) |
268 | 0 | | hb_map (hb_first) |
269 | 0 | | hb_map (glyph_map) |
270 | 0 | | hb_sink (new_coverage) |
271 | 0 | ; |
272 | 0 |
|
273 | 0 | out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); |
274 | 0 | return_trace (true); |
275 | 0 | } |
276 | | |
277 | | bool sanitize (hb_sanitize_context_t *c) const |
278 | 135 | { |
279 | 135 | TRACE_SANITIZE (this); |
280 | 135 | return_trace (c->check_struct (this) && |
281 | 135 | topAccentCoverage.sanitize (c, this) && |
282 | 135 | topAccentAttachment.sanitize (c, this)); |
283 | 135 | } |
284 | | |
285 | | hb_position_t get_value (hb_codepoint_t glyph, |
286 | | hb_font_t *font) const |
287 | 33.5k | { |
288 | 33.5k | unsigned int index = (this+topAccentCoverage).get_coverage (glyph); |
289 | 33.5k | if (index == NOT_COVERED) |
290 | 33.5k | return font->get_glyph_h_advance (glyph) / 2; |
291 | 4 | return topAccentAttachment[index].get_x_value (font, this); |
292 | 33.5k | } |
293 | | |
294 | | protected: |
295 | | Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table - |
296 | | * from the beginning of |
297 | | * MathTopAccentAttachment |
298 | | * table. */ |
299 | | Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords |
300 | | * defining top accent |
301 | | * attachment points for each |
302 | | * covered glyph. */ |
303 | | |
304 | | public: |
305 | | DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); |
306 | | }; |
307 | | |
308 | | struct MathKern |
309 | | { |
310 | | MathKern* copy (hb_serialize_context_t *c) const |
311 | 0 | { |
312 | 0 | TRACE_SERIALIZE (this); |
313 | 0 | auto *out = c->start_embed (this); |
314 | 0 |
|
315 | 0 | if (unlikely (!c->embed (heightCount))) return_trace (nullptr); |
316 | 0 |
|
317 | 0 | unsigned count = 2 * heightCount + 1; |
318 | 0 | for (unsigned i = 0; i < count; i++) |
319 | 0 | if (!c->copy (mathValueRecordsZ.arrayZ[i], this)) |
320 | 0 | return_trace (nullptr); |
321 | 0 |
|
322 | 0 | return_trace (out); |
323 | 0 | } |
324 | | |
325 | | bool sanitize_math_value_records (hb_sanitize_context_t *c) const |
326 | 4.08k | { |
327 | 4.08k | TRACE_SANITIZE (this); |
328 | 4.08k | unsigned int count = 2 * heightCount + 1; |
329 | 3.11M | for (unsigned int i = 0; i < count; i++) |
330 | 3.11M | if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); |
331 | 4.08k | return_trace (true); |
332 | 4.08k | } |
333 | | |
334 | | bool sanitize (hb_sanitize_context_t *c) const |
335 | 4.09k | { |
336 | 4.09k | TRACE_SANITIZE (this); |
337 | 4.09k | return_trace (c->check_struct (this) && |
338 | 4.09k | hb_barrier () && |
339 | 4.09k | c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && |
340 | 4.09k | sanitize_math_value_records (c)); |
341 | 4.09k | } |
342 | | |
343 | | hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const |
344 | 33.5k | { |
345 | 33.5k | const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; |
346 | 33.5k | const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; |
347 | 33.5k | int sign = font->y_scale < 0 ? -1 : +1; |
348 | | |
349 | | /* According to OpenType spec (v1.9), except for the boundary cases, the index |
350 | | * chosen for kern value should be i such that |
351 | | * correctionHeight[i-1] <= correction_height < correctionHeight[i] |
352 | | * We can use the binary search algorithm of std::upper_bound(). Or, we can |
353 | | * use the internal hb_bsearch_impl. |
354 | | */ |
355 | 33.5k | unsigned int pos; |
356 | 33.5k | auto cmp = +[](const void* key, const void* p, |
357 | 33.5k | int sign, hb_font_t* font, const MathKern* mathKern) -> int { |
358 | 65 | return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern); |
359 | 65 | }; |
360 | 33.5k | unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight, |
361 | 33.5k | heightCount, MathValueRecord::static_size, |
362 | 33.5k | cmp, sign, font, this) ? pos + 1 : pos; |
363 | 33.5k | return kernValue[i].get_x_value (font, this); |
364 | 33.5k | } |
365 | | |
366 | | unsigned int get_entries (unsigned int start_offset, |
367 | | unsigned int *entries_count, /* IN/OUT */ |
368 | | hb_ot_math_kern_entry_t *kern_entries, /* OUT */ |
369 | | hb_font_t *font) const |
370 | 26 | { |
371 | 26 | const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; |
372 | 26 | const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; |
373 | 26 | const unsigned int entriesCount = heightCount + 1; |
374 | | |
375 | 26 | if (entries_count) |
376 | 13 | { |
377 | 13 | unsigned int start = hb_min (start_offset, entriesCount); |
378 | 13 | unsigned int end = hb_min (start + *entries_count, entriesCount); |
379 | 13 | *entries_count = end - start; |
380 | | |
381 | 78 | for (unsigned int i = 0; i < *entries_count; i++) { |
382 | 65 | unsigned int j = start + i; |
383 | | |
384 | 65 | hb_position_t max_height; |
385 | 65 | if (j == heightCount) { |
386 | 0 | max_height = INT32_MAX; |
387 | 65 | } else { |
388 | 65 | max_height = correctionHeight[j].get_y_value (font, this); |
389 | 65 | } |
390 | | |
391 | 65 | kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; |
392 | 65 | } |
393 | 13 | } |
394 | 26 | return entriesCount; |
395 | 26 | } |
396 | | |
397 | | protected: |
398 | | HBUINT16 heightCount; |
399 | | UnsizedArrayOf<MathValueRecord> |
400 | | mathValueRecordsZ; |
401 | | /* Array of correction heights at |
402 | | * which the kern value changes. |
403 | | * Sorted by the height value in |
404 | | * design units (heightCount entries), |
405 | | * Followed by: |
406 | | * Array of kern values corresponding |
407 | | * to heights. (heightCount+1 entries). |
408 | | */ |
409 | | |
410 | | public: |
411 | | DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); |
412 | | }; |
413 | | |
414 | | struct MathKernInfoRecord |
415 | | { |
416 | | MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const |
417 | 0 | { |
418 | 0 | TRACE_SERIALIZE (this); |
419 | 0 | auto *out = c->embed (this); |
420 | 0 | if (unlikely (!out)) return_trace (nullptr); |
421 | 0 |
|
422 | 0 | unsigned count = ARRAY_LENGTH (mathKern); |
423 | 0 | for (unsigned i = 0; i < count; i++) |
424 | 0 | out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head); |
425 | 0 |
|
426 | 0 | return_trace (out); |
427 | 0 | } |
428 | | |
429 | | bool sanitize (hb_sanitize_context_t *c, const void *base) const |
430 | 3.04k | { |
431 | 3.04k | TRACE_SANITIZE (this); |
432 | | |
433 | 3.04k | unsigned int count = ARRAY_LENGTH (mathKern); |
434 | 15.1k | for (unsigned int i = 0; i < count; i++) |
435 | 12.1k | if (unlikely (!mathKern[i].sanitize (c, base))) |
436 | 32 | return_trace (false); |
437 | | |
438 | 3.04k | return_trace (true); |
439 | 3.04k | } |
440 | | |
441 | | hb_position_t get_kerning (hb_ot_math_kern_t kern, |
442 | | hb_position_t correction_height, |
443 | | hb_font_t *font, |
444 | | const void *base) const |
445 | 33.5k | { |
446 | 33.5k | unsigned int idx = kern; |
447 | 33.5k | if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; |
448 | 33.5k | return (base+mathKern[idx]).get_value (correction_height, font); |
449 | 33.5k | } |
450 | | |
451 | | unsigned int get_kernings (hb_ot_math_kern_t kern, |
452 | | unsigned int start_offset, |
453 | | unsigned int *entries_count, /* IN/OUT */ |
454 | | hb_ot_math_kern_entry_t *kern_entries, /* OUT */ |
455 | | hb_font_t *font, |
456 | | const void *base) const |
457 | 67.0k | { |
458 | 67.0k | unsigned int idx = kern; |
459 | 67.0k | if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { |
460 | 67.0k | if (entries_count) *entries_count = 0; |
461 | 67.0k | return 0; |
462 | 67.0k | } |
463 | 26 | return (base+mathKern[idx]).get_entries (start_offset, |
464 | 26 | entries_count, |
465 | 26 | kern_entries, |
466 | 26 | font); |
467 | 67.0k | } |
468 | | |
469 | | protected: |
470 | | /* Offset to MathKern table for each corner - |
471 | | * from the beginning of MathKernInfo table. May be NULL. */ |
472 | | Offset16To<MathKern> mathKern[4]; |
473 | | |
474 | | public: |
475 | | DEFINE_SIZE_STATIC (8); |
476 | | }; |
477 | | |
478 | | struct MathKernInfo |
479 | | { |
480 | | bool subset (hb_subset_context_t *c) const |
481 | 0 | { |
482 | 0 | TRACE_SUBSET (this); |
483 | 0 | const hb_set_t &glyphset = c->plan->_glyphset_mathed; |
484 | 0 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
485 | 0 |
|
486 | 0 | auto *out = c->serializer->start_embed (*this); |
487 | 0 | if (unlikely (!c->serializer->extend_min (out))) return_trace (false); |
488 | 0 |
|
489 | 0 | hb_sorted_vector_t<hb_codepoint_t> new_coverage; |
490 | 0 | + hb_zip (this+mathKernCoverage, mathKernInfoRecords) |
491 | 0 | | hb_filter (glyphset, hb_first) |
492 | 0 | | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second) |
493 | 0 | | hb_map (hb_first) |
494 | 0 | | hb_map (glyph_map) |
495 | 0 | | hb_sink (new_coverage) |
496 | 0 | ; |
497 | 0 |
|
498 | 0 | out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ()); |
499 | 0 | return_trace (true); |
500 | 0 | } |
501 | | |
502 | | bool sanitize (hb_sanitize_context_t *c) const |
503 | 108 | { |
504 | 108 | TRACE_SANITIZE (this); |
505 | 108 | return_trace (c->check_struct (this) && |
506 | 108 | mathKernCoverage.sanitize (c, this) && |
507 | 108 | mathKernInfoRecords.sanitize (c, this)); |
508 | 108 | } |
509 | | |
510 | | hb_position_t get_kerning (hb_codepoint_t glyph, |
511 | | hb_ot_math_kern_t kern, |
512 | | hb_position_t correction_height, |
513 | | hb_font_t *font) const |
514 | 33.5k | { |
515 | 33.5k | unsigned int index = (this+mathKernCoverage).get_coverage (glyph); |
516 | 33.5k | return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); |
517 | 33.5k | } |
518 | | |
519 | | unsigned int get_kernings (hb_codepoint_t glyph, |
520 | | hb_ot_math_kern_t kern, |
521 | | unsigned int start_offset, |
522 | | unsigned int *entries_count, /* IN/OUT */ |
523 | | hb_ot_math_kern_entry_t *kern_entries, /* OUT */ |
524 | | hb_font_t *font) const |
525 | 67.0k | { |
526 | 67.0k | unsigned int index = (this+mathKernCoverage).get_coverage (glyph); |
527 | 67.0k | return mathKernInfoRecords[index].get_kernings (kern, |
528 | 67.0k | start_offset, |
529 | 67.0k | entries_count, |
530 | 67.0k | kern_entries, |
531 | 67.0k | font, |
532 | 67.0k | this); |
533 | 67.0k | } |
534 | | |
535 | | protected: |
536 | | Offset16To<Coverage> |
537 | | mathKernCoverage; |
538 | | /* Offset to Coverage table - |
539 | | * from the beginning of the |
540 | | * MathKernInfo table. */ |
541 | | Array16Of<MathKernInfoRecord> |
542 | | mathKernInfoRecords; |
543 | | /* Array of MathKernInfoRecords, |
544 | | * per-glyph information for |
545 | | * mathematical positioning |
546 | | * of subscripts and |
547 | | * superscripts. */ |
548 | | |
549 | | public: |
550 | | DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); |
551 | | }; |
552 | | |
553 | | struct MathGlyphInfo |
554 | | { |
555 | | bool subset (hb_subset_context_t *c) const |
556 | 0 | { |
557 | 0 | TRACE_SUBSET (this); |
558 | 0 | auto *out = c->serializer->embed (*this); |
559 | 0 | if (unlikely (!out)) return_trace (false); |
560 | 0 |
|
561 | 0 | out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this); |
562 | 0 | out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this); |
563 | 0 |
|
564 | 0 | const hb_set_t &glyphset = c->plan->_glyphset_mathed; |
565 | 0 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
566 | 0 |
|
567 | 0 | auto it = |
568 | 0 | + hb_iter (this+extendedShapeCoverage) |
569 | 0 | | hb_take (c->plan->source->get_num_glyphs ()) |
570 | 0 | | hb_filter (glyphset) |
571 | 0 | | hb_map_retains_sorting (glyph_map) |
572 | 0 | ; |
573 | 0 |
|
574 | 0 | if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it); |
575 | 0 | else out->extendedShapeCoverage = 0; |
576 | 0 |
|
577 | 0 | out->mathKernInfo.serialize_subset (c, mathKernInfo, this); |
578 | 0 | return_trace (true); |
579 | 0 | } |
580 | | |
581 | | bool sanitize (hb_sanitize_context_t *c) const |
582 | 244 | { |
583 | 244 | TRACE_SANITIZE (this); |
584 | 244 | return_trace (c->check_struct (this) && |
585 | 244 | mathItalicsCorrectionInfo.sanitize (c, this) && |
586 | 244 | mathTopAccentAttachment.sanitize (c, this) && |
587 | 244 | extendedShapeCoverage.sanitize (c, this) && |
588 | 244 | mathKernInfo.sanitize (c, this)); |
589 | 244 | } |
590 | | |
591 | | hb_position_t |
592 | | get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const |
593 | 33.5k | { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } |
594 | | |
595 | | hb_position_t |
596 | | get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const |
597 | 33.5k | { return (this+mathTopAccentAttachment).get_value (glyph, font); } |
598 | | |
599 | | bool is_extended_shape (hb_codepoint_t glyph) const |
600 | 33.5k | { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } |
601 | | |
602 | | hb_position_t get_kerning (hb_codepoint_t glyph, |
603 | | hb_ot_math_kern_t kern, |
604 | | hb_position_t correction_height, |
605 | | hb_font_t *font) const |
606 | 33.5k | { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } |
607 | | |
608 | | hb_position_t get_kernings (hb_codepoint_t glyph, |
609 | | hb_ot_math_kern_t kern, |
610 | | unsigned int start_offset, |
611 | | unsigned int *entries_count, /* IN/OUT */ |
612 | | hb_ot_math_kern_entry_t *kern_entries, /* OUT */ |
613 | | hb_font_t *font) const |
614 | 67.0k | { return (this+mathKernInfo).get_kernings (glyph, |
615 | 67.0k | kern, |
616 | 67.0k | start_offset, |
617 | 67.0k | entries_count, |
618 | 67.0k | kern_entries, |
619 | 67.0k | font); } |
620 | | |
621 | | protected: |
622 | | /* Offset to MathItalicsCorrectionInfo table - |
623 | | * from the beginning of MathGlyphInfo table. */ |
624 | | Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; |
625 | | |
626 | | /* Offset to MathTopAccentAttachment table - |
627 | | * from the beginning of MathGlyphInfo table. */ |
628 | | Offset16To<MathTopAccentAttachment> mathTopAccentAttachment; |
629 | | |
630 | | /* Offset to coverage table for Extended Shape glyphs - |
631 | | * from the beginning of MathGlyphInfo table. When the left or right glyph of |
632 | | * a box is an extended shape variant, the (ink) box (and not the default |
633 | | * position defined by values in MathConstants table) should be used for |
634 | | * vertical positioning purposes. May be NULL.. */ |
635 | | Offset16To<Coverage> extendedShapeCoverage; |
636 | | |
637 | | /* Offset to MathKernInfo table - |
638 | | * from the beginning of MathGlyphInfo table. */ |
639 | | Offset16To<MathKernInfo> mathKernInfo; |
640 | | |
641 | | public: |
642 | | DEFINE_SIZE_STATIC (8); |
643 | | }; |
644 | | |
645 | | struct MathGlyphVariantRecord |
646 | | { |
647 | | friend struct MathGlyphConstruction; |
648 | | |
649 | | bool subset (hb_subset_context_t *c) const |
650 | 0 | { |
651 | 0 | TRACE_SUBSET (this); |
652 | 0 | auto *out = c->serializer->embed (this); |
653 | 0 | if (unlikely (!out)) return_trace (false); |
654 | 0 |
|
655 | 0 | const hb_map_t& glyph_map = *c->plan->glyph_map; |
656 | 0 | return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); |
657 | 0 | } |
658 | | |
659 | | bool sanitize (hb_sanitize_context_t *c) const |
660 | 0 | { |
661 | 0 | TRACE_SANITIZE (this); |
662 | 0 | return_trace (c->check_struct (this)); |
663 | 0 | } |
664 | | |
665 | | void closure_glyphs (hb_set_t *variant_glyphs) const |
666 | 0 | { variant_glyphs->add (variantGlyph); } |
667 | | |
668 | | protected: |
669 | | HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */ |
670 | | HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the |
671 | | * variant, in the direction of requested |
672 | | * glyph extension. */ |
673 | | |
674 | | public: |
675 | | DEFINE_SIZE_STATIC (4); |
676 | | }; |
677 | | |
678 | | struct PartFlags : HBUINT16 |
679 | | { |
680 | | enum Flags { |
681 | | Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ |
682 | | |
683 | | Defined = 0x0001u, /* All defined flags. */ |
684 | | }; |
685 | | |
686 | | public: |
687 | | DEFINE_SIZE_STATIC (2); |
688 | | }; |
689 | | |
690 | | struct MathGlyphPartRecord |
691 | | { |
692 | | bool subset (hb_subset_context_t *c) const |
693 | 0 | { |
694 | 0 | TRACE_SUBSET (this); |
695 | 0 | auto *out = c->serializer->embed (this); |
696 | 0 | if (unlikely (!out)) return_trace (false); |
697 | 0 |
|
698 | 0 | const hb_map_t& glyph_map = *c->plan->glyph_map; |
699 | 0 | return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW)); |
700 | 0 | } |
701 | | |
702 | | bool sanitize (hb_sanitize_context_t *c) const |
703 | 0 | { |
704 | 0 | TRACE_SANITIZE (this); |
705 | 0 | return_trace (c->check_struct (this)); |
706 | 0 | } |
707 | | |
708 | | void extract (hb_ot_math_glyph_part_t &out, |
709 | | int64_t mult, |
710 | | hb_font_t *font) const |
711 | 6 | { |
712 | 6 | out.glyph = glyph; |
713 | | |
714 | 6 | out.start_connector_length = font->em_mult (startConnectorLength, mult); |
715 | 6 | out.end_connector_length = font->em_mult (endConnectorLength, mult); |
716 | 6 | out.full_advance = font->em_mult (fullAdvance, mult); |
717 | | |
718 | 6 | static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == |
719 | 6 | (unsigned int) PartFlags::Extender, ""); |
720 | | |
721 | 6 | out.flags = (hb_ot_math_glyph_part_flags_t) |
722 | 6 | (unsigned int) |
723 | 6 | (partFlags & PartFlags::Defined); |
724 | 6 | } |
725 | | |
726 | | void closure_glyphs (hb_set_t *variant_glyphs) const |
727 | 0 | { variant_glyphs->add (glyph); } |
728 | | |
729 | | protected: |
730 | | HBGlyphID16 glyph; /* Glyph ID for the part. */ |
731 | | HBUINT16 startConnectorLength; |
732 | | /* Advance width/ height of the straight bar |
733 | | * connector material, in design units, is at |
734 | | * the beginning of the glyph, in the |
735 | | * direction of the extension. */ |
736 | | HBUINT16 endConnectorLength; |
737 | | /* Advance width/ height of the straight bar |
738 | | * connector material, in design units, is at |
739 | | * the end of the glyph, in the direction of |
740 | | * the extension. */ |
741 | | HBUINT16 fullAdvance; /* Full advance width/height for this part, |
742 | | * in the direction of the extension. |
743 | | * In design units. */ |
744 | | PartFlags partFlags; /* Part qualifiers. */ |
745 | | |
746 | | public: |
747 | | DEFINE_SIZE_STATIC (10); |
748 | | }; |
749 | | |
750 | | struct MathGlyphAssembly |
751 | | { |
752 | | bool subset (hb_subset_context_t *c) const |
753 | 0 | { |
754 | 0 | TRACE_SUBSET (this); |
755 | 0 |
|
756 | 0 | if (!c->serializer->copy (italicsCorrection, this)) return_trace (false); |
757 | 0 | if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false); |
758 | 0 |
|
759 | 0 | for (const auto& record : partRecords.iter ()) |
760 | 0 | if (!record.subset (c)) return_trace (false); |
761 | 0 | return_trace (true); |
762 | 0 | } |
763 | | |
764 | | bool sanitize (hb_sanitize_context_t *c) const |
765 | 1.82k | { |
766 | 1.82k | TRACE_SANITIZE (this); |
767 | 1.82k | return_trace (c->check_struct (this) && |
768 | 1.82k | italicsCorrection.sanitize (c, this) && |
769 | 1.82k | partRecords.sanitize (c)); |
770 | 1.82k | } |
771 | | |
772 | | unsigned int get_parts (hb_direction_t direction, |
773 | | hb_font_t *font, |
774 | | unsigned int start_offset, |
775 | | unsigned int *parts_count, /* IN/OUT */ |
776 | | hb_ot_math_glyph_part_t *parts /* OUT */, |
777 | | hb_position_t *italics_correction /* OUT */) const |
778 | 100k | { |
779 | 100k | if (parts_count) |
780 | 33.5k | { |
781 | 33.5k | int64_t mult = font->dir_mult (direction); |
782 | 33.5k | for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count), |
783 | 33.5k | hb_array (parts, *parts_count))) |
784 | 6 | _.first.extract (_.second, mult, font); |
785 | 33.5k | } |
786 | | |
787 | 100k | if (italics_correction) |
788 | 33.5k | *italics_correction = italicsCorrection.get_x_value (font, this); |
789 | | |
790 | 100k | return partRecords.len; |
791 | 100k | } |
792 | | |
793 | | void closure_glyphs (hb_set_t *variant_glyphs) const |
794 | 0 | { |
795 | 0 | for (const auto& _ : partRecords.iter ()) |
796 | 0 | _.closure_glyphs (variant_glyphs); |
797 | 0 | } |
798 | | |
799 | | protected: |
800 | | MathValueRecord |
801 | | italicsCorrection; |
802 | | /* Italics correction of this |
803 | | * MathGlyphAssembly. Should not |
804 | | * depend on the assembly size. */ |
805 | | Array16Of<MathGlyphPartRecord> |
806 | | partRecords; /* Array of part records, from |
807 | | * left to right and bottom to |
808 | | * top. */ |
809 | | |
810 | | public: |
811 | | DEFINE_SIZE_ARRAY (6, partRecords); |
812 | | }; |
813 | | |
814 | | struct MathGlyphConstruction |
815 | | { |
816 | | bool subset (hb_subset_context_t *c) const |
817 | 0 | { |
818 | 0 | TRACE_SUBSET (this); |
819 | 0 | auto *out = c->serializer->start_embed (*this); |
820 | 0 | if (unlikely (!c->serializer->extend_min (out))) return_trace (false); |
821 | 0 |
|
822 | 0 | out->glyphAssembly.serialize_subset (c, glyphAssembly, this); |
823 | 0 |
|
824 | 0 | if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) |
825 | 0 | return_trace (false); |
826 | 0 | for (const auto& record : mathGlyphVariantRecord.iter ()) |
827 | 0 | if (!record.subset (c)) return_trace (false); |
828 | 0 |
|
829 | 0 | return_trace (true); |
830 | 0 | } |
831 | | |
832 | | bool sanitize (hb_sanitize_context_t *c) const |
833 | 3.87k | { |
834 | 3.87k | TRACE_SANITIZE (this); |
835 | 3.87k | return_trace (c->check_struct (this) && |
836 | 3.87k | glyphAssembly.sanitize (c, this) && |
837 | 3.87k | mathGlyphVariantRecord.sanitize (c)); |
838 | 3.87k | } |
839 | | |
840 | 100k | const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } |
841 | | |
842 | | unsigned int get_variants (hb_direction_t direction, |
843 | | hb_font_t *font, |
844 | | unsigned int start_offset, |
845 | | unsigned int *variants_count, /* IN/OUT */ |
846 | | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
847 | 100k | { |
848 | 100k | if (variants_count) |
849 | 33.5k | { |
850 | 33.5k | int64_t mult = font->dir_mult (direction); |
851 | 33.5k | for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count), |
852 | 33.5k | hb_array (variants, *variants_count))) |
853 | 7 | _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; |
854 | 33.5k | } |
855 | 100k | return mathGlyphVariantRecord.len; |
856 | 100k | } |
857 | | |
858 | | void closure_glyphs (hb_set_t *variant_glyphs) const |
859 | 0 | { |
860 | 0 | (this+glyphAssembly).closure_glyphs (variant_glyphs); |
861 | 0 |
|
862 | 0 | for (const auto& _ : mathGlyphVariantRecord.iter ()) |
863 | 0 | _.closure_glyphs (variant_glyphs); |
864 | 0 | } |
865 | | |
866 | | protected: |
867 | | /* Offset to MathGlyphAssembly table for this shape - from the beginning of |
868 | | MathGlyphConstruction table. May be NULL. */ |
869 | | Offset16To<MathGlyphAssembly> glyphAssembly; |
870 | | |
871 | | /* MathGlyphVariantRecords for alternative variants of the glyphs. */ |
872 | | Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord; |
873 | | |
874 | | public: |
875 | | DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); |
876 | | }; |
877 | | |
878 | | struct MathVariants |
879 | | { |
880 | | void closure_glyphs (const hb_set_t *glyph_set, |
881 | | hb_set_t *variant_glyphs) const |
882 | 0 | { |
883 | 0 | const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount); |
884 | 0 |
|
885 | 0 | if (vertGlyphCoverage) |
886 | 0 | { |
887 | 0 | const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount); |
888 | 0 | + hb_zip (this+vertGlyphCoverage, vert_offsets) |
889 | 0 | | hb_filter (glyph_set, hb_first) |
890 | 0 | | hb_map (hb_second) |
891 | 0 | | hb_map (hb_add (this)) |
892 | 0 | | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) |
893 | 0 | ; |
894 | 0 | } |
895 | 0 |
|
896 | 0 | if (horizGlyphCoverage) |
897 | 0 | { |
898 | 0 | const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount); |
899 | 0 | + hb_zip (this+horizGlyphCoverage, hori_offsets) |
900 | 0 | | hb_filter (glyph_set, hb_first) |
901 | 0 | | hb_map (hb_second) |
902 | 0 | | hb_map (hb_add (this)) |
903 | 0 | | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); }) |
904 | 0 | ; |
905 | 0 | } |
906 | 0 | } |
907 | | |
908 | | void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage, |
909 | | const Offset16To<Coverage>& coverage, |
910 | | unsigned i, |
911 | | unsigned end_index, |
912 | | hb_set_t& indices, |
913 | | const hb_set_t& glyphset, |
914 | | const hb_map_t& glyph_map) const |
915 | 0 | { |
916 | 0 | if (!coverage) return; |
917 | 0 |
|
918 | 0 | for (const auto _ : (this+coverage).iter ()) |
919 | 0 | { |
920 | 0 | if (i >= end_index) return; |
921 | 0 | if (glyphset.has (_)) |
922 | 0 | { |
923 | 0 | unsigned new_gid = glyph_map.get (_); |
924 | 0 | new_coverage.push (new_gid); |
925 | 0 | indices.add (i); |
926 | 0 | } |
927 | 0 | i++; |
928 | 0 | } |
929 | 0 | } |
930 | | |
931 | | bool subset (hb_subset_context_t *c) const |
932 | 0 | { |
933 | 0 | TRACE_SUBSET (this); |
934 | 0 | const hb_set_t &glyphset = c->plan->_glyphset_mathed; |
935 | 0 | const hb_map_t &glyph_map = *c->plan->glyph_map; |
936 | 0 |
|
937 | 0 | auto *out = c->serializer->start_embed (*this); |
938 | 0 | if (unlikely (!c->serializer->extend_min (out))) return_trace (false); |
939 | 0 | if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW)) |
940 | 0 | return_trace (false); |
941 | 0 |
|
942 | 0 | hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage; |
943 | 0 | hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage; |
944 | 0 | hb_set_t indices; |
945 | 0 | collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map); |
946 | 0 | collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map); |
947 | 0 |
|
948 | 0 | if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) |
949 | 0 | return_trace (false); |
950 | 0 | if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) |
951 | 0 | return_trace (false); |
952 | 0 |
|
953 | 0 | for (unsigned i : indices.iter ()) |
954 | 0 | { |
955 | 0 | auto *o = c->serializer->embed (glyphConstruction[i]); |
956 | 0 | if (!o) return_trace (false); |
957 | 0 | o->serialize_subset (c, glyphConstruction[i], this); |
958 | 0 | } |
959 | 0 |
|
960 | 0 | if (new_vert_coverage) |
961 | 0 | out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); |
962 | 0 |
|
963 | 0 | if (new_hori_coverage) |
964 | 0 | out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); |
965 | 0 | return_trace (true); |
966 | 0 | } |
967 | | |
968 | | bool sanitize_offsets (hb_sanitize_context_t *c) const |
969 | 143 | { |
970 | 143 | TRACE_SANITIZE (this); |
971 | 143 | unsigned int count = vertGlyphCount + horizGlyphCount; |
972 | 9.84k | for (unsigned int i = 0; i < count; i++) |
973 | 9.74k | if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); |
974 | 143 | return_trace (true); |
975 | 143 | } |
976 | | |
977 | | bool sanitize (hb_sanitize_context_t *c) const |
978 | 162 | { |
979 | 162 | TRACE_SANITIZE (this); |
980 | 162 | return_trace (c->check_struct (this) && |
981 | 162 | vertGlyphCoverage.sanitize (c, this) && |
982 | 162 | horizGlyphCoverage.sanitize (c, this) && |
983 | 162 | hb_barrier () && |
984 | 162 | c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && |
985 | 162 | sanitize_offsets (c)); |
986 | 162 | } |
987 | | |
988 | | hb_position_t get_min_connector_overlap (hb_direction_t direction, |
989 | | hb_font_t *font) const |
990 | 33.5k | { return font->em_scale_dir (minConnectorOverlap, direction); } |
991 | | |
992 | | unsigned int get_glyph_variants (hb_codepoint_t glyph, |
993 | | hb_direction_t direction, |
994 | | hb_font_t *font, |
995 | | unsigned int start_offset, |
996 | | unsigned int *variants_count, /* IN/OUT */ |
997 | | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
998 | 100k | { return get_glyph_construction (glyph, direction, font) |
999 | 100k | .get_variants (direction, font, start_offset, variants_count, variants); } |
1000 | | |
1001 | | unsigned int get_glyph_parts (hb_codepoint_t glyph, |
1002 | | hb_direction_t direction, |
1003 | | hb_font_t *font, |
1004 | | unsigned int start_offset, |
1005 | | unsigned int *parts_count, /* IN/OUT */ |
1006 | | hb_ot_math_glyph_part_t *parts /* OUT */, |
1007 | | hb_position_t *italics_correction /* OUT */) const |
1008 | 100k | { return get_glyph_construction (glyph, direction, font) |
1009 | 100k | .get_assembly () |
1010 | 100k | .get_parts (direction, font, |
1011 | 100k | start_offset, parts_count, parts, |
1012 | 100k | italics_correction); } |
1013 | | |
1014 | | private: |
1015 | | const MathGlyphConstruction & |
1016 | | get_glyph_construction (hb_codepoint_t glyph, |
1017 | | hb_direction_t direction, |
1018 | | hb_font_t *font HB_UNUSED) const |
1019 | 201k | { |
1020 | 201k | bool vertical = HB_DIRECTION_IS_VERTICAL (direction); |
1021 | 201k | unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; |
1022 | 201k | const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage |
1023 | 201k | : horizGlyphCoverage; |
1024 | | |
1025 | 201k | unsigned int index = (this+coverage).get_coverage (glyph); |
1026 | 201k | if (unlikely (index >= count)) return Null (MathGlyphConstruction); |
1027 | | |
1028 | 26 | if (!vertical) |
1029 | 20 | index += vertGlyphCount; |
1030 | | |
1031 | 26 | return this+glyphConstruction[index]; |
1032 | 201k | } |
1033 | | |
1034 | | protected: |
1035 | | HBUINT16 minConnectorOverlap; |
1036 | | /* Minimum overlap of connecting |
1037 | | * glyphs during glyph construction, |
1038 | | * in design units. */ |
1039 | | Offset16To<Coverage> vertGlyphCoverage; |
1040 | | /* Offset to Coverage table - |
1041 | | * from the beginning of MathVariants |
1042 | | * table. */ |
1043 | | Offset16To<Coverage> horizGlyphCoverage; |
1044 | | /* Offset to Coverage table - |
1045 | | * from the beginning of MathVariants |
1046 | | * table. */ |
1047 | | HBUINT16 vertGlyphCount; /* Number of glyphs for which |
1048 | | * information is provided for |
1049 | | * vertically growing variants. */ |
1050 | | HBUINT16 horizGlyphCount;/* Number of glyphs for which |
1051 | | * information is provided for |
1052 | | * horizontally growing variants. */ |
1053 | | |
1054 | | /* Array of offsets to MathGlyphConstruction tables - from the beginning of |
1055 | | the MathVariants table, for shapes growing in vertical/horizontal |
1056 | | direction. */ |
1057 | | UnsizedArrayOf<Offset16To<MathGlyphConstruction>> |
1058 | | glyphConstruction; |
1059 | | |
1060 | | public: |
1061 | | DEFINE_SIZE_ARRAY (10, glyphConstruction); |
1062 | | }; |
1063 | | |
1064 | | |
1065 | | /* |
1066 | | * MATH -- Mathematical typesetting |
1067 | | * https://docs.microsoft.com/en-us/typography/opentype/spec/math |
1068 | | */ |
1069 | | |
1070 | | struct MATH |
1071 | | { |
1072 | | static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; |
1073 | | |
1074 | 33.5k | bool has_data () const { return version.to_int (); } |
1075 | | |
1076 | | void closure_glyphs (hb_set_t *glyph_set) const |
1077 | 0 | { |
1078 | 0 | if (mathVariants) |
1079 | 0 | { |
1080 | 0 | hb_set_t variant_glyphs; |
1081 | 0 | (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs); |
1082 | 0 | hb_set_union (glyph_set, &variant_glyphs); |
1083 | 0 | } |
1084 | 0 | } |
1085 | | |
1086 | | bool subset (hb_subset_context_t *c) const |
1087 | 0 | { |
1088 | 0 | TRACE_SUBSET (this); |
1089 | 0 | auto *out = c->serializer->embed (*this); |
1090 | 0 | if (unlikely (!out)) return_trace (false); |
1091 | 0 |
|
1092 | 0 | out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head); |
1093 | 0 | out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this); |
1094 | 0 | out->mathVariants.serialize_subset (c, mathVariants, this); |
1095 | 0 | return_trace (true); |
1096 | 0 | } |
1097 | | |
1098 | | bool sanitize (hb_sanitize_context_t *c) const |
1099 | 367 | { |
1100 | 367 | TRACE_SANITIZE (this); |
1101 | 367 | return_trace (version.sanitize (c) && |
1102 | 367 | likely (version.major == 1) && |
1103 | 367 | hb_barrier () && |
1104 | 367 | mathConstants.sanitize (c, this) && |
1105 | 367 | mathGlyphInfo.sanitize (c, this) && |
1106 | 367 | mathVariants.sanitize (c, this)); |
1107 | 367 | } |
1108 | | |
1109 | | // https://github.com/harfbuzz/harfbuzz/issues/4653 |
1110 | | HB_INTERNAL bool is_bad_cambria (hb_font_t *font) const |
1111 | 67.0k | { |
1112 | 67.0k | #ifndef HB_NO_MATH |
1113 | 67.0k | switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length, |
1114 | 67.0k | (this+mathConstants).minHeight[1], // displayOperatorMinHeight |
1115 | | (this+mathConstants).minHeight[0]) // delimitedSubFormulaMinHeight |
1116 | 67.0k | { |
1117 | | /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5 cambria.ttc |
1118 | | * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9 cambria.ttc |
1119 | | * sha1sum:b1e5a3feaca2ea3dfcf79ccb377de749ecf60343 cambria.ttc */ |
1120 | 2 | case HB_CODEPOINT_ENCODE3 (25722, 2500, 3000): |
1121 | 2 | return true; |
1122 | 67.0k | } |
1123 | 67.0k | #endif |
1124 | 67.0k | return false; |
1125 | 67.0k | } |
1126 | | |
1127 | | hb_position_t get_constant (hb_ot_math_constant_t constant, |
1128 | | hb_font_t *font) const |
1129 | 1.87M | { return (this+mathConstants).get_value (constant, font); } |
1130 | | |
1131 | 201k | const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } |
1132 | | |
1133 | 234k | const MathVariants &get_variants () const { return this+mathVariants; } |
1134 | | |
1135 | | protected: |
1136 | | FixedVersion<>version; /* Version of the MATH table |
1137 | | * initially set to 0x00010000u */ |
1138 | | Offset16To<MathConstants> |
1139 | | mathConstants; /* MathConstants table */ |
1140 | | Offset16To<MathGlyphInfo> |
1141 | | mathGlyphInfo; /* MathGlyphInfo table */ |
1142 | | Offset16To<MathVariants> |
1143 | | mathVariants; /* MathVariants table */ |
1144 | | |
1145 | | public: |
1146 | | DEFINE_SIZE_STATIC (10); |
1147 | | }; |
1148 | | |
1149 | | } /* namespace OT */ |
1150 | | |
1151 | | |
1152 | | #endif /* HB_OT_MATH_TABLE_HH */ |