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 | inline 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 | inline 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 | inline 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 nullptr. |
54 | * Suggested format for device table is 1. */ |
55 | |
56 | public: |
57 | DEFINE_SIZE_STATIC (4); |
58 | }; |
59 | |
60 | struct MathConstants |
61 | { |
62 | inline 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 | inline 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 | inline 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 | inline 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 | inline 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 | inline 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 | inline 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 | inline 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 (!mathValueRecords[i].sanitize (c, this)) return_trace (false); |
238 | return_trace (true); |
239 | } |
240 | |
241 | inline bool sanitize (hb_sanitize_context_t *c) const |
242 | { |
243 | TRACE_SANITIZE (this); |
244 | return_trace (c->check_struct (this) && |
245 | c->check_array (mathValueRecords, |
246 | mathValueRecords[0].static_size, |
247 | 2 * heightCount + 1) && |
248 | sanitize_math_value_records (c)); |
249 | } |
250 | |
251 | inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const |
252 | { |
253 | const MathValueRecord* correctionHeight = mathValueRecords; |
254 | const MathValueRecord* kernValue = mathValueRecords + heightCount; |
255 | int sign = font->y_scale < 0 ? -1 : +1; |
256 | |
257 | /* The description of the MathKern table is a ambiguous, but interpreting |
258 | * "between the two heights found at those indexes" for 0 < i < len as |
259 | * |
260 | * correctionHeight[i-1] < correction_height <= correctionHeight[i] |
261 | * |
262 | * makes the result consistent with the limit cases and we can just use the |
263 | * binary search algorithm of std::upper_bound: |
264 | */ |
265 | unsigned int i = 0; |
266 | unsigned int count = heightCount; |
267 | while (count > 0) |
268 | { |
269 | unsigned int half = count / 2; |
270 | hb_position_t height = correctionHeight[i + half].get_y_value(font, this); |
271 | if (sign * height < sign * correction_height) |
272 | { |
273 | i += half + 1; |
274 | count -= half + 1; |
275 | } else |
276 | count = half; |
277 | } |
278 | return kernValue[i].get_x_value(font, this); |
279 | } |
280 | |
281 | protected: |
282 | HBUINT16 heightCount; |
283 | MathValueRecord mathValueRecords[VAR]; /* 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, mathValueRecords); |
294 | }; |
295 | |
296 | struct MathKernInfoRecord |
297 | { |
298 | inline 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 | inline 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 nullptr. */ |
323 | OffsetTo<MathKern> mathKern[4]; |
324 | |
325 | public: |
326 | DEFINE_SIZE_STATIC (8); |
327 | }; |
328 | |
329 | struct MathKernInfo |
330 | { |
331 | inline 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 | inline 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> mathKernCoverage; /* Offset to Coverage table - |
350 | * from the beginning of the |
351 | * MathKernInfo table. */ |
352 | ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of |
353 | * MathKernInfoRecords, |
354 | * per-glyph information for |
355 | * mathematical positioning |
356 | * of subscripts and |
357 | * superscripts. */ |
358 | |
359 | public: |
360 | DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); |
361 | }; |
362 | |
363 | struct MathGlyphInfo |
364 | { |
365 | inline bool sanitize (hb_sanitize_context_t *c) const |
366 | { |
367 | TRACE_SANITIZE (this); |
368 | return_trace (c->check_struct (this) && |
369 | mathItalicsCorrectionInfo.sanitize (c, this) && |
370 | mathTopAccentAttachment.sanitize (c, this) && |
371 | extendedShapeCoverage.sanitize (c, this) && |
372 | mathKernInfo.sanitize(c, this)); |
373 | } |
374 | |
375 | inline hb_position_t |
376 | get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const |
377 | { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } |
378 | |
379 | inline hb_position_t |
380 | get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const |
381 | { return (this+mathTopAccentAttachment).get_value (glyph, font); } |
382 | |
383 | inline bool is_extended_shape (hb_codepoint_t glyph) const |
384 | { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } |
385 | |
386 | inline hb_position_t get_kerning (hb_codepoint_t glyph, |
387 | hb_ot_math_kern_t kern, |
388 | hb_position_t correction_height, |
389 | hb_font_t *font) const |
390 | { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } |
391 | |
392 | protected: |
393 | /* Offset to MathItalicsCorrectionInfo table - |
394 | * from the beginning of MathGlyphInfo table. */ |
395 | OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; |
396 | |
397 | /* Offset to MathTopAccentAttachment table - |
398 | * from the beginning of MathGlyphInfo table. */ |
399 | OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment; |
400 | |
401 | /* Offset to coverage table for Extended Shape glyphs - |
402 | * from the beginning of MathGlyphInfo table. When the left or right glyph of |
403 | * a box is an extended shape variant, the (ink) box (and not the default |
404 | * position defined by values in MathConstants table) should be used for |
405 | * vertical positioning purposes. May be nullptr.. */ |
406 | OffsetTo<Coverage> extendedShapeCoverage; |
407 | |
408 | /* Offset to MathKernInfo table - |
409 | * from the beginning of MathGlyphInfo table. */ |
410 | OffsetTo<MathKernInfo> mathKernInfo; |
411 | |
412 | public: |
413 | DEFINE_SIZE_STATIC (8); |
414 | }; |
415 | |
416 | struct MathGlyphVariantRecord |
417 | { |
418 | friend struct MathGlyphConstruction; |
419 | |
420 | inline bool sanitize (hb_sanitize_context_t *c) const |
421 | { |
422 | TRACE_SANITIZE (this); |
423 | return_trace (c->check_struct (this)); |
424 | } |
425 | |
426 | protected: |
427 | GlyphID variantGlyph; /* Glyph ID for the variant. */ |
428 | HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the |
429 | * variant, in the direction of requested |
430 | * glyph extension. */ |
431 | |
432 | public: |
433 | DEFINE_SIZE_STATIC (4); |
434 | }; |
435 | |
436 | struct PartFlags : HBUINT16 |
437 | { |
438 | enum Flags { |
439 | Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ |
440 | |
441 | Defined = 0x0001u, /* All defined flags. */ |
442 | }; |
443 | |
444 | public: |
445 | DEFINE_SIZE_STATIC (2); |
446 | }; |
447 | |
448 | struct MathGlyphPartRecord |
449 | { |
450 | inline bool sanitize (hb_sanitize_context_t *c) const |
451 | { |
452 | TRACE_SANITIZE (this); |
453 | return_trace (c->check_struct (this)); |
454 | } |
455 | |
456 | inline void (hb_ot_math_glyph_part_t &out, |
457 | int scale, |
458 | hb_font_t *font) const |
459 | { |
460 | out.glyph = glyph; |
461 | |
462 | out.start_connector_length = font->em_scale (startConnectorLength, scale); |
463 | out.end_connector_length = font->em_scale (endConnectorLength, scale); |
464 | out.full_advance = font->em_scale (fullAdvance, scale); |
465 | |
466 | static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == |
467 | (unsigned int) PartFlags::Extender, "" ); |
468 | |
469 | out.flags = (hb_ot_math_glyph_part_flags_t) |
470 | (unsigned int) |
471 | (partFlags & PartFlags::Defined); |
472 | } |
473 | |
474 | protected: |
475 | GlyphID glyph; /* Glyph ID for the part. */ |
476 | HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar |
477 | * connector material, in design units, is at |
478 | * the beginning of the glyph, in the |
479 | * direction of the extension. */ |
480 | HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar |
481 | * connector material, in design units, is at |
482 | * the end of the glyph, in the direction of |
483 | * the extension. */ |
484 | HBUINT16 fullAdvance; /* Full advance width/height for this part, |
485 | * in the direction of the extension. |
486 | * In design units. */ |
487 | PartFlags partFlags; /* Part qualifiers. */ |
488 | |
489 | public: |
490 | DEFINE_SIZE_STATIC (10); |
491 | }; |
492 | |
493 | struct MathGlyphAssembly |
494 | { |
495 | inline bool sanitize (hb_sanitize_context_t *c) const |
496 | { |
497 | TRACE_SANITIZE (this); |
498 | return_trace (c->check_struct (this) && |
499 | italicsCorrection.sanitize(c, this) && |
500 | partRecords.sanitize(c)); |
501 | } |
502 | |
503 | inline unsigned int get_parts (hb_direction_t direction, |
504 | hb_font_t *font, |
505 | unsigned int start_offset, |
506 | unsigned int *parts_count, /* IN/OUT */ |
507 | hb_ot_math_glyph_part_t *parts /* OUT */, |
508 | hb_position_t *italics_correction /* OUT */) const |
509 | { |
510 | if (parts_count) |
511 | { |
512 | int scale = font->dir_scale (direction); |
513 | const MathGlyphPartRecord *arr = |
514 | partRecords.sub_array (start_offset, parts_count); |
515 | unsigned int count = *parts_count; |
516 | for (unsigned int i = 0; i < count; i++) |
517 | arr[i].extract (parts[i], scale, font); |
518 | } |
519 | |
520 | if (italics_correction) |
521 | *italics_correction = italicsCorrection.get_x_value (font, this); |
522 | |
523 | return partRecords.len; |
524 | } |
525 | |
526 | protected: |
527 | MathValueRecord italicsCorrection; /* Italics correction of this |
528 | * MathGlyphAssembly. Should not |
529 | * depend on the assembly size. */ |
530 | ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from |
531 | * left to right and bottom to |
532 | * top. */ |
533 | |
534 | public: |
535 | DEFINE_SIZE_ARRAY (6, partRecords); |
536 | }; |
537 | |
538 | struct MathGlyphConstruction |
539 | { |
540 | inline bool sanitize (hb_sanitize_context_t *c) const |
541 | { |
542 | TRACE_SANITIZE (this); |
543 | return_trace (c->check_struct (this) && |
544 | glyphAssembly.sanitize(c, this) && |
545 | mathGlyphVariantRecord.sanitize(c)); |
546 | } |
547 | |
548 | inline const MathGlyphAssembly &get_assembly (void) const |
549 | { return this+glyphAssembly; } |
550 | |
551 | inline unsigned int get_variants (hb_direction_t direction, |
552 | hb_font_t *font, |
553 | unsigned int start_offset, |
554 | unsigned int *variants_count, /* IN/OUT */ |
555 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
556 | { |
557 | if (variants_count) |
558 | { |
559 | int scale = font->dir_scale (direction); |
560 | const MathGlyphVariantRecord *arr = |
561 | mathGlyphVariantRecord.sub_array (start_offset, variants_count); |
562 | unsigned int count = *variants_count; |
563 | for (unsigned int i = 0; i < count; i++) |
564 | { |
565 | variants[i].glyph = arr[i].variantGlyph; |
566 | variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); |
567 | } |
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 nullptr. */ |
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 | inline 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[i].sanitize (c, this)) return_trace (false); |
592 | return_trace (true); |
593 | } |
594 | |
595 | inline 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, |
602 | glyphConstruction[0].static_size, |
603 | vertGlyphCount + horizGlyphCount) && |
604 | sanitize_offsets (c)); |
605 | } |
606 | |
607 | inline hb_position_t get_min_connector_overlap (hb_direction_t direction, |
608 | hb_font_t *font) const |
609 | { return font->em_scale_dir (minConnectorOverlap, direction); } |
610 | |
611 | inline unsigned int get_glyph_variants (hb_codepoint_t glyph, |
612 | hb_direction_t direction, |
613 | hb_font_t *font, |
614 | unsigned int start_offset, |
615 | unsigned int *variants_count, /* IN/OUT */ |
616 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
617 | { return get_glyph_construction (glyph, direction, font) |
618 | .get_variants (direction, font, start_offset, variants_count, variants); } |
619 | |
620 | inline unsigned int get_glyph_parts (hb_codepoint_t glyph, |
621 | hb_direction_t direction, |
622 | hb_font_t *font, |
623 | unsigned int start_offset, |
624 | unsigned int *parts_count, /* IN/OUT */ |
625 | hb_ot_math_glyph_part_t *parts /* OUT */, |
626 | hb_position_t *italics_correction /* OUT */) const |
627 | { return get_glyph_construction (glyph, direction, font) |
628 | .get_assembly () |
629 | .get_parts (direction, font, |
630 | start_offset, parts_count, parts, |
631 | italics_correction); } |
632 | |
633 | private: |
634 | inline const MathGlyphConstruction & |
635 | get_glyph_construction (hb_codepoint_t glyph, |
636 | hb_direction_t direction, |
637 | hb_font_t *font) const |
638 | { |
639 | bool vertical = HB_DIRECTION_IS_VERTICAL (direction); |
640 | unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; |
641 | const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage |
642 | : horizGlyphCoverage; |
643 | |
644 | unsigned int index = (this+coverage).get_coverage (glyph); |
645 | if (unlikely (index >= count)) return Null(MathGlyphConstruction); |
646 | |
647 | if (!vertical) |
648 | index += vertGlyphCount; |
649 | |
650 | return this+glyphConstruction[index]; |
651 | } |
652 | |
653 | protected: |
654 | HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting |
655 | * glyphs during glyph construction, |
656 | * in design units. */ |
657 | OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table - |
658 | * from the beginning of MathVariants |
659 | * table. */ |
660 | OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table - |
661 | * from the beginning of MathVariants |
662 | * table. */ |
663 | HBUINT16 vertGlyphCount; /* Number of glyphs for which |
664 | * information is provided for |
665 | * vertically growing variants. */ |
666 | HBUINT16 horizGlyphCount; /* Number of glyphs for which |
667 | * information is provided for |
668 | * horizontally growing variants. */ |
669 | |
670 | /* Array of offsets to MathGlyphConstruction tables - from the beginning of |
671 | the MathVariants table, for shapes growing in vertical/horizontal |
672 | direction. */ |
673 | OffsetTo<MathGlyphConstruction> glyphConstruction[VAR]; |
674 | |
675 | public: |
676 | DEFINE_SIZE_ARRAY (10, glyphConstruction); |
677 | }; |
678 | |
679 | |
680 | /* |
681 | * MATH -- Mathematical typesetting |
682 | * https://docs.microsoft.com/en-us/typography/opentype/spec/math |
683 | */ |
684 | |
685 | struct MATH |
686 | { |
687 | static const hb_tag_t tableTag = HB_OT_TAG_MATH; |
688 | |
689 | inline bool has_data (void) const { return version.to_int () != 0; } |
690 | |
691 | inline bool sanitize (hb_sanitize_context_t *c) const |
692 | { |
693 | TRACE_SANITIZE (this); |
694 | return_trace (version.sanitize (c) && |
695 | likely (version.major == 1) && |
696 | mathConstants.sanitize (c, this) && |
697 | mathGlyphInfo.sanitize (c, this) && |
698 | mathVariants.sanitize (c, this)); |
699 | } |
700 | |
701 | inline hb_position_t get_constant (hb_ot_math_constant_t constant, |
702 | hb_font_t *font) const |
703 | { return (this+mathConstants).get_value (constant, font); } |
704 | |
705 | inline const MathGlyphInfo &get_math_glyph_info (void) const |
706 | { return this+mathGlyphInfo; } |
707 | |
708 | inline const MathVariants &get_math_variants (void) const |
709 | { return this+mathVariants; } |
710 | |
711 | protected: |
712 | FixedVersion<>version; /* Version of the MATH table |
713 | * initially set to 0x00010000u */ |
714 | OffsetTo<MathConstants> mathConstants;/* MathConstants table */ |
715 | OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */ |
716 | OffsetTo<MathVariants> mathVariants; /* MathVariants table */ |
717 | |
718 | public: |
719 | DEFINE_SIZE_STATIC (10); |
720 | }; |
721 | |
722 | } /* namespace OT */ |
723 | |
724 | |
725 | #endif /* HB_OT_MATH_TABLE_HH */ |
726 | |