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 | { 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 | { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); } |
43 | |
44 | bool sanitize (hb_sanitize_context_t *c, const void *base) const |
45 | { |
46 | TRACE_SANITIZE (this); |
47 | return_trace (c->check_struct (this) && deviceTable.sanitize (c, base)); |
48 | } |
49 | |
50 | protected: |
51 | HBINT16 value; /* The X or Y value in design units */ |
52 | OffsetTo<Device> deviceTable; /* Offset to the device table - from the |
53 | * beginning of parent table. May be NULL. |
54 | * Suggested format for device table is 1. */ |
55 | |
56 | public: |
57 | DEFINE_SIZE_STATIC (4); |
58 | }; |
59 | |
60 | struct MathConstants |
61 | { |
62 | bool sanitize_math_value_records (hb_sanitize_context_t *c) const |
63 | { |
64 | TRACE_SANITIZE (this); |
65 | |
66 | unsigned int count = ARRAY_LENGTH (mathValueRecords); |
67 | for (unsigned int i = 0; i < count; i++) |
68 | if (!mathValueRecords[i].sanitize (c, this)) |
69 | return_trace (false); |
70 | |
71 | return_trace (true); |
72 | } |
73 | |
74 | bool sanitize (hb_sanitize_context_t *c) const |
75 | { |
76 | TRACE_SANITIZE (this); |
77 | return_trace (c->check_struct (this) && sanitize_math_value_records (c)); |
78 | } |
79 | |
80 | hb_position_t get_value (hb_ot_math_constant_t constant, |
81 | hb_font_t *font) const |
82 | { |
83 | switch (constant) { |
84 | |
85 | case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN: |
86 | case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN: |
87 | return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN]; |
88 | |
89 | case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT: |
90 | case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT: |
91 | return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]); |
92 | |
93 | case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE: |
94 | case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE: |
95 | case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP: |
96 | case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT: |
97 | return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this); |
98 | |
99 | case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT: |
100 | case HB_OT_MATH_CONSTANT_AXIS_HEIGHT: |
101 | case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT: |
102 | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN: |
103 | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN: |
104 | case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN: |
105 | case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN: |
106 | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP: |
107 | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN: |
108 | case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP: |
109 | case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN: |
110 | case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS: |
111 | case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN: |
112 | case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN: |
113 | case HB_OT_MATH_CONSTANT_MATH_LEADING: |
114 | case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER: |
115 | case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS: |
116 | case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP: |
117 | case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP: |
118 | case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER: |
119 | case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS: |
120 | case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP: |
121 | case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP: |
122 | case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN: |
123 | case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN: |
124 | case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN: |
125 | case HB_OT_MATH_CONSTANT_STACK_GAP_MIN: |
126 | case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP: |
127 | case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP: |
128 | case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN: |
129 | case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN: |
130 | case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN: |
131 | case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP: |
132 | case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN: |
133 | case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN: |
134 | case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX: |
135 | case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN: |
136 | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX: |
137 | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT: |
138 | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN: |
139 | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP: |
140 | case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED: |
141 | case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER: |
142 | case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS: |
143 | case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP: |
144 | case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN: |
145 | case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN: |
146 | return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this); |
147 | |
148 | case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT: |
149 | return radicalDegreeBottomRaisePercent; |
150 | |
151 | default: |
152 | return 0; |
153 | } |
154 | } |
155 | |
156 | protected: |
157 | HBINT16 percentScaleDown[2]; |
158 | HBUINT16 minHeight[2]; |
159 | MathValueRecord mathValueRecords[51]; |
160 | HBINT16 radicalDegreeBottomRaisePercent; |
161 | |
162 | public: |
163 | DEFINE_SIZE_STATIC (214); |
164 | }; |
165 | |
166 | struct MathItalicsCorrectionInfo |
167 | { |
168 | bool sanitize (hb_sanitize_context_t *c) const |
169 | { |
170 | TRACE_SANITIZE (this); |
171 | return_trace (c->check_struct (this) && |
172 | coverage.sanitize (c, this) && |
173 | italicsCorrection.sanitize (c, this)); |
174 | } |
175 | |
176 | hb_position_t get_value (hb_codepoint_t glyph, |
177 | hb_font_t *font) const |
178 | { |
179 | unsigned int index = (this+coverage).get_coverage (glyph); |
180 | return italicsCorrection[index].get_x_value (font, this); |
181 | } |
182 | |
183 | protected: |
184 | OffsetTo<Coverage> coverage; /* Offset to Coverage table - |
185 | * from the beginning of |
186 | * MathItalicsCorrectionInfo |
187 | * table. */ |
188 | ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords |
189 | * defining italics correction |
190 | * values for each |
191 | * covered glyph. */ |
192 | |
193 | public: |
194 | DEFINE_SIZE_ARRAY (4, italicsCorrection); |
195 | }; |
196 | |
197 | struct MathTopAccentAttachment |
198 | { |
199 | bool sanitize (hb_sanitize_context_t *c) const |
200 | { |
201 | TRACE_SANITIZE (this); |
202 | return_trace (c->check_struct (this) && |
203 | topAccentCoverage.sanitize (c, this) && |
204 | topAccentAttachment.sanitize (c, this)); |
205 | } |
206 | |
207 | hb_position_t get_value (hb_codepoint_t glyph, |
208 | hb_font_t *font) const |
209 | { |
210 | unsigned int index = (this+topAccentCoverage).get_coverage (glyph); |
211 | if (index == NOT_COVERED) |
212 | return font->get_glyph_h_advance (glyph) / 2; |
213 | return topAccentAttachment[index].get_x_value (font, this); |
214 | } |
215 | |
216 | protected: |
217 | OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table - |
218 | * from the beginning of |
219 | * MathTopAccentAttachment |
220 | * table. */ |
221 | ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords |
222 | * defining top accent |
223 | * attachment points for each |
224 | * covered glyph. */ |
225 | |
226 | public: |
227 | DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment); |
228 | }; |
229 | |
230 | struct MathKern |
231 | { |
232 | bool sanitize_math_value_records (hb_sanitize_context_t *c) const |
233 | { |
234 | TRACE_SANITIZE (this); |
235 | unsigned int count = 2 * heightCount + 1; |
236 | for (unsigned int i = 0; i < count; i++) |
237 | if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false); |
238 | return_trace (true); |
239 | } |
240 | |
241 | bool sanitize (hb_sanitize_context_t *c) const |
242 | { |
243 | TRACE_SANITIZE (this); |
244 | return_trace (c->check_struct (this) && |
245 | c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) && |
246 | sanitize_math_value_records (c)); |
247 | } |
248 | |
249 | hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const |
250 | { |
251 | const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; |
252 | const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; |
253 | int sign = font->y_scale < 0 ? -1 : +1; |
254 | |
255 | /* The description of the MathKern table is a ambiguous, but interpreting |
256 | * "between the two heights found at those indexes" for 0 < i < len as |
257 | * |
258 | * correctionHeight[i-1] < correction_height <= correctionHeight[i] |
259 | * |
260 | * makes the result consistent with the limit cases and we can just use the |
261 | * binary search algorithm of std::upper_bound: |
262 | */ |
263 | unsigned int i = 0; |
264 | unsigned int count = heightCount; |
265 | while (count > 0) |
266 | { |
267 | unsigned int half = count / 2; |
268 | hb_position_t height = correctionHeight[i + half].get_y_value (font, this); |
269 | if (sign * height < sign * correction_height) |
270 | { |
271 | i += half + 1; |
272 | count -= half + 1; |
273 | } else |
274 | count = half; |
275 | } |
276 | return kernValue[i].get_x_value (font, this); |
277 | } |
278 | |
279 | protected: |
280 | HBUINT16 heightCount; |
281 | UnsizedArrayOf<MathValueRecord> |
282 | mathValueRecordsZ; |
283 | /* Array of correction heights at |
284 | * which the kern value changes. |
285 | * Sorted by the height value in |
286 | * design units (heightCount entries), |
287 | * Followed by: |
288 | * Array of kern values corresponding |
289 | * to heights. (heightCount+1 entries). |
290 | */ |
291 | |
292 | public: |
293 | DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); |
294 | }; |
295 | |
296 | struct MathKernInfoRecord |
297 | { |
298 | bool sanitize (hb_sanitize_context_t *c, const void *base) const |
299 | { |
300 | TRACE_SANITIZE (this); |
301 | |
302 | unsigned int count = ARRAY_LENGTH (mathKern); |
303 | for (unsigned int i = 0; i < count; i++) |
304 | if (unlikely (!mathKern[i].sanitize (c, base))) |
305 | return_trace (false); |
306 | |
307 | return_trace (true); |
308 | } |
309 | |
310 | hb_position_t get_kerning (hb_ot_math_kern_t kern, |
311 | hb_position_t correction_height, |
312 | hb_font_t *font, |
313 | const void *base) const |
314 | { |
315 | unsigned int idx = kern; |
316 | if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; |
317 | return (base+mathKern[idx]).get_value (correction_height, font); |
318 | } |
319 | |
320 | protected: |
321 | /* Offset to MathKern table for each corner - |
322 | * from the beginning of MathKernInfo table. May be NULL. */ |
323 | OffsetTo<MathKern> mathKern[4]; |
324 | |
325 | public: |
326 | DEFINE_SIZE_STATIC (8); |
327 | }; |
328 | |
329 | struct MathKernInfo |
330 | { |
331 | bool sanitize (hb_sanitize_context_t *c) const |
332 | { |
333 | TRACE_SANITIZE (this); |
334 | return_trace (c->check_struct (this) && |
335 | mathKernCoverage.sanitize (c, this) && |
336 | mathKernInfoRecords.sanitize (c, this)); |
337 | } |
338 | |
339 | hb_position_t get_kerning (hb_codepoint_t glyph, |
340 | hb_ot_math_kern_t kern, |
341 | hb_position_t correction_height, |
342 | hb_font_t *font) const |
343 | { |
344 | unsigned int index = (this+mathKernCoverage).get_coverage (glyph); |
345 | return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); |
346 | } |
347 | |
348 | protected: |
349 | OffsetTo<Coverage> |
350 | mathKernCoverage; |
351 | /* Offset to Coverage table - |
352 | * from the beginning of the |
353 | * MathKernInfo table. */ |
354 | ArrayOf<MathKernInfoRecord> |
355 | mathKernInfoRecords; |
356 | /* Array of MathKernInfoRecords, |
357 | * per-glyph information for |
358 | * mathematical positioning |
359 | * of subscripts and |
360 | * superscripts. */ |
361 | |
362 | public: |
363 | DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); |
364 | }; |
365 | |
366 | struct MathGlyphInfo |
367 | { |
368 | bool sanitize (hb_sanitize_context_t *c) const |
369 | { |
370 | TRACE_SANITIZE (this); |
371 | return_trace (c->check_struct (this) && |
372 | mathItalicsCorrectionInfo.sanitize (c, this) && |
373 | mathTopAccentAttachment.sanitize (c, this) && |
374 | extendedShapeCoverage.sanitize (c, this) && |
375 | mathKernInfo.sanitize (c, this)); |
376 | } |
377 | |
378 | hb_position_t |
379 | get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const |
380 | { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } |
381 | |
382 | hb_position_t |
383 | get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const |
384 | { return (this+mathTopAccentAttachment).get_value (glyph, font); } |
385 | |
386 | bool is_extended_shape (hb_codepoint_t glyph) const |
387 | { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } |
388 | |
389 | hb_position_t get_kerning (hb_codepoint_t glyph, |
390 | hb_ot_math_kern_t kern, |
391 | hb_position_t correction_height, |
392 | hb_font_t *font) const |
393 | { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } |
394 | |
395 | protected: |
396 | /* Offset to MathItalicsCorrectionInfo table - |
397 | * from the beginning of MathGlyphInfo table. */ |
398 | OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; |
399 | |
400 | /* Offset to MathTopAccentAttachment table - |
401 | * from the beginning of MathGlyphInfo table. */ |
402 | OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment; |
403 | |
404 | /* Offset to coverage table for Extended Shape glyphs - |
405 | * from the beginning of MathGlyphInfo table. When the left or right glyph of |
406 | * a box is an extended shape variant, the (ink) box (and not the default |
407 | * position defined by values in MathConstants table) should be used for |
408 | * vertical positioning purposes. May be NULL.. */ |
409 | OffsetTo<Coverage> extendedShapeCoverage; |
410 | |
411 | /* Offset to MathKernInfo table - |
412 | * from the beginning of MathGlyphInfo table. */ |
413 | OffsetTo<MathKernInfo> mathKernInfo; |
414 | |
415 | public: |
416 | DEFINE_SIZE_STATIC (8); |
417 | }; |
418 | |
419 | struct MathGlyphVariantRecord |
420 | { |
421 | friend struct MathGlyphConstruction; |
422 | |
423 | bool sanitize (hb_sanitize_context_t *c) const |
424 | { |
425 | TRACE_SANITIZE (this); |
426 | return_trace (c->check_struct (this)); |
427 | } |
428 | |
429 | protected: |
430 | HBGlyphID variantGlyph; /* Glyph ID for the variant. */ |
431 | HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the |
432 | * variant, in the direction of requested |
433 | * glyph extension. */ |
434 | |
435 | public: |
436 | DEFINE_SIZE_STATIC (4); |
437 | }; |
438 | |
439 | struct PartFlags : HBUINT16 |
440 | { |
441 | enum Flags { |
442 | Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ |
443 | |
444 | Defined = 0x0001u, /* All defined flags. */ |
445 | }; |
446 | |
447 | public: |
448 | DEFINE_SIZE_STATIC (2); |
449 | }; |
450 | |
451 | struct MathGlyphPartRecord |
452 | { |
453 | bool sanitize (hb_sanitize_context_t *c) const |
454 | { |
455 | TRACE_SANITIZE (this); |
456 | return_trace (c->check_struct (this)); |
457 | } |
458 | |
459 | void (hb_ot_math_glyph_part_t &out, |
460 | int64_t mult, |
461 | hb_font_t *font) const |
462 | { |
463 | out.glyph = glyph; |
464 | |
465 | out.start_connector_length = font->em_mult (startConnectorLength, mult); |
466 | out.end_connector_length = font->em_mult (endConnectorLength, mult); |
467 | out.full_advance = font->em_mult (fullAdvance, mult); |
468 | |
469 | static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == |
470 | (unsigned int) PartFlags::Extender, "" ); |
471 | |
472 | out.flags = (hb_ot_math_glyph_part_flags_t) |
473 | (unsigned int) |
474 | (partFlags & PartFlags::Defined); |
475 | } |
476 | |
477 | protected: |
478 | HBGlyphID glyph; /* Glyph ID for the part. */ |
479 | HBUINT16 startConnectorLength; |
480 | /* Advance width/ height of the straight bar |
481 | * connector material, in design units, is at |
482 | * the beginning of the glyph, in the |
483 | * direction of the extension. */ |
484 | HBUINT16 endConnectorLength; |
485 | /* Advance width/ height of the straight bar |
486 | * connector material, in design units, is at |
487 | * the end of the glyph, in the direction of |
488 | * the extension. */ |
489 | HBUINT16 fullAdvance; /* Full advance width/height for this part, |
490 | * in the direction of the extension. |
491 | * In design units. */ |
492 | PartFlags partFlags; /* Part qualifiers. */ |
493 | |
494 | public: |
495 | DEFINE_SIZE_STATIC (10); |
496 | }; |
497 | |
498 | struct MathGlyphAssembly |
499 | { |
500 | bool sanitize (hb_sanitize_context_t *c) const |
501 | { |
502 | TRACE_SANITIZE (this); |
503 | return_trace (c->check_struct (this) && |
504 | italicsCorrection.sanitize (c, this) && |
505 | partRecords.sanitize (c)); |
506 | } |
507 | |
508 | unsigned int get_parts (hb_direction_t direction, |
509 | hb_font_t *font, |
510 | unsigned int start_offset, |
511 | unsigned int *parts_count, /* IN/OUT */ |
512 | hb_ot_math_glyph_part_t *parts /* OUT */, |
513 | hb_position_t *italics_correction /* OUT */) const |
514 | { |
515 | if (parts_count) |
516 | { |
517 | int64_t mult = font->dir_mult (direction); |
518 | for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count), |
519 | hb_array (parts, *parts_count))) |
520 | _.first.extract (_.second, mult, font); |
521 | } |
522 | |
523 | if (italics_correction) |
524 | *italics_correction = italicsCorrection.get_x_value (font, this); |
525 | |
526 | return partRecords.len; |
527 | } |
528 | |
529 | protected: |
530 | MathValueRecord |
531 | italicsCorrection; |
532 | /* Italics correction of this |
533 | * MathGlyphAssembly. Should not |
534 | * depend on the assembly size. */ |
535 | ArrayOf<MathGlyphPartRecord> |
536 | partRecords; /* Array of part records, from |
537 | * left to right and bottom to |
538 | * top. */ |
539 | |
540 | public: |
541 | DEFINE_SIZE_ARRAY (6, partRecords); |
542 | }; |
543 | |
544 | struct MathGlyphConstruction |
545 | { |
546 | bool sanitize (hb_sanitize_context_t *c) const |
547 | { |
548 | TRACE_SANITIZE (this); |
549 | return_trace (c->check_struct (this) && |
550 | glyphAssembly.sanitize (c, this) && |
551 | mathGlyphVariantRecord.sanitize (c)); |
552 | } |
553 | |
554 | const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } |
555 | |
556 | unsigned int get_variants (hb_direction_t direction, |
557 | hb_font_t *font, |
558 | unsigned int start_offset, |
559 | unsigned int *variants_count, /* IN/OUT */ |
560 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
561 | { |
562 | if (variants_count) |
563 | { |
564 | int64_t mult = font->dir_mult (direction); |
565 | for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count), |
566 | hb_array (variants, *variants_count))) |
567 | _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; |
568 | } |
569 | return mathGlyphVariantRecord.len; |
570 | } |
571 | |
572 | protected: |
573 | /* Offset to MathGlyphAssembly table for this shape - from the beginning of |
574 | MathGlyphConstruction table. May be NULL. */ |
575 | OffsetTo<MathGlyphAssembly> glyphAssembly; |
576 | |
577 | /* MathGlyphVariantRecords for alternative variants of the glyphs. */ |
578 | ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord; |
579 | |
580 | public: |
581 | DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); |
582 | }; |
583 | |
584 | struct MathVariants |
585 | { |
586 | bool sanitize_offsets (hb_sanitize_context_t *c) const |
587 | { |
588 | TRACE_SANITIZE (this); |
589 | unsigned int count = vertGlyphCount + horizGlyphCount; |
590 | for (unsigned int i = 0; i < count; i++) |
591 | if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); |
592 | return_trace (true); |
593 | } |
594 | |
595 | bool sanitize (hb_sanitize_context_t *c) const |
596 | { |
597 | TRACE_SANITIZE (this); |
598 | return_trace (c->check_struct (this) && |
599 | vertGlyphCoverage.sanitize (c, this) && |
600 | horizGlyphCoverage.sanitize (c, this) && |
601 | c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && |
602 | sanitize_offsets (c)); |
603 | } |
604 | |
605 | hb_position_t get_min_connector_overlap (hb_direction_t direction, |
606 | hb_font_t *font) const |
607 | { return font->em_scale_dir (minConnectorOverlap, direction); } |
608 | |
609 | unsigned int get_glyph_variants (hb_codepoint_t glyph, |
610 | hb_direction_t direction, |
611 | hb_font_t *font, |
612 | unsigned int start_offset, |
613 | unsigned int *variants_count, /* IN/OUT */ |
614 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
615 | { return get_glyph_construction (glyph, direction, font) |
616 | .get_variants (direction, font, start_offset, variants_count, variants); } |
617 | |
618 | unsigned int get_glyph_parts (hb_codepoint_t glyph, |
619 | hb_direction_t direction, |
620 | hb_font_t *font, |
621 | unsigned int start_offset, |
622 | unsigned int *parts_count, /* IN/OUT */ |
623 | hb_ot_math_glyph_part_t *parts /* OUT */, |
624 | hb_position_t *italics_correction /* OUT */) const |
625 | { return get_glyph_construction (glyph, direction, font) |
626 | .get_assembly () |
627 | .get_parts (direction, font, |
628 | start_offset, parts_count, parts, |
629 | italics_correction); } |
630 | |
631 | private: |
632 | const MathGlyphConstruction & |
633 | get_glyph_construction (hb_codepoint_t glyph, |
634 | hb_direction_t direction, |
635 | hb_font_t *font HB_UNUSED) const |
636 | { |
637 | bool vertical = HB_DIRECTION_IS_VERTICAL (direction); |
638 | unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; |
639 | const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage |
640 | : horizGlyphCoverage; |
641 | |
642 | unsigned int index = (this+coverage).get_coverage (glyph); |
643 | if (unlikely (index >= count)) return Null (MathGlyphConstruction); |
644 | |
645 | if (!vertical) |
646 | index += vertGlyphCount; |
647 | |
648 | return this+glyphConstruction[index]; |
649 | } |
650 | |
651 | protected: |
652 | HBUINT16 minConnectorOverlap; |
653 | /* Minimum overlap of connecting |
654 | * glyphs during glyph construction, |
655 | * in design units. */ |
656 | OffsetTo<Coverage> vertGlyphCoverage; |
657 | /* Offset to Coverage table - |
658 | * from the beginning of MathVariants |
659 | * table. */ |
660 | OffsetTo<Coverage> horizGlyphCoverage; |
661 | /* Offset to Coverage table - |
662 | * from the beginning of MathVariants |
663 | * table. */ |
664 | HBUINT16 vertGlyphCount; /* Number of glyphs for which |
665 | * information is provided for |
666 | * vertically growing variants. */ |
667 | HBUINT16 horizGlyphCount;/* Number of glyphs for which |
668 | * information is provided for |
669 | * horizontally growing variants. */ |
670 | |
671 | /* Array of offsets to MathGlyphConstruction tables - from the beginning of |
672 | the MathVariants table, for shapes growing in vertical/horizontal |
673 | direction. */ |
674 | UnsizedArrayOf<OffsetTo<MathGlyphConstruction>> |
675 | glyphConstruction; |
676 | |
677 | public: |
678 | DEFINE_SIZE_ARRAY (10, glyphConstruction); |
679 | }; |
680 | |
681 | |
682 | /* |
683 | * MATH -- Mathematical typesetting |
684 | * https://docs.microsoft.com/en-us/typography/opentype/spec/math |
685 | */ |
686 | |
687 | struct MATH |
688 | { |
689 | static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; |
690 | |
691 | bool has_data () const { return version.to_int (); } |
692 | |
693 | bool sanitize (hb_sanitize_context_t *c) const |
694 | { |
695 | TRACE_SANITIZE (this); |
696 | return_trace (version.sanitize (c) && |
697 | likely (version.major == 1) && |
698 | mathConstants.sanitize (c, this) && |
699 | mathGlyphInfo.sanitize (c, this) && |
700 | mathVariants.sanitize (c, this)); |
701 | } |
702 | |
703 | hb_position_t get_constant (hb_ot_math_constant_t constant, |
704 | hb_font_t *font) const |
705 | { return (this+mathConstants).get_value (constant, font); } |
706 | |
707 | const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } |
708 | |
709 | const MathVariants &get_variants () const { return this+mathVariants; } |
710 | |
711 | protected: |
712 | FixedVersion<>version; /* Version of the MATH table |
713 | * initially set to 0x00010000u */ |
714 | OffsetTo<MathConstants> |
715 | mathConstants; /* MathConstants table */ |
716 | OffsetTo<MathGlyphInfo> |
717 | mathGlyphInfo; /* MathGlyphInfo table */ |
718 | OffsetTo<MathVariants> |
719 | mathVariants; /* MathVariants table */ |
720 | |
721 | public: |
722 | DEFINE_SIZE_STATIC (10); |
723 | }; |
724 | |
725 | } /* namespace OT */ |
726 | |
727 | |
728 | #endif /* HB_OT_MATH_TABLE_HH */ |
729 | |