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