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; /* Array of correction heights at |
283 | * which the kern value changes. |
284 | * Sorted by the height value in |
285 | * design units (heightCount entries), |
286 | * Followed by: |
287 | * Array of kern values corresponding |
288 | * to heights. (heightCount+1 entries). |
289 | */ |
290 | |
291 | public: |
292 | DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); |
293 | }; |
294 | |
295 | struct MathKernInfoRecord |
296 | { |
297 | bool sanitize (hb_sanitize_context_t *c, const void *base) const |
298 | { |
299 | TRACE_SANITIZE (this); |
300 | |
301 | unsigned int count = ARRAY_LENGTH (mathKern); |
302 | for (unsigned int i = 0; i < count; i++) |
303 | if (unlikely (!mathKern[i].sanitize (c, base))) |
304 | return_trace (false); |
305 | |
306 | return_trace (true); |
307 | } |
308 | |
309 | hb_position_t get_kerning (hb_ot_math_kern_t kern, |
310 | hb_position_t correction_height, |
311 | hb_font_t *font, |
312 | const void *base) const |
313 | { |
314 | unsigned int idx = kern; |
315 | if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0; |
316 | return (base+mathKern[idx]).get_value (correction_height, font); |
317 | } |
318 | |
319 | protected: |
320 | /* Offset to MathKern table for each corner - |
321 | * from the beginning of MathKernInfo table. May be NULL. */ |
322 | OffsetTo<MathKern> mathKern[4]; |
323 | |
324 | public: |
325 | DEFINE_SIZE_STATIC (8); |
326 | }; |
327 | |
328 | struct MathKernInfo |
329 | { |
330 | bool sanitize (hb_sanitize_context_t *c) const |
331 | { |
332 | TRACE_SANITIZE (this); |
333 | return_trace (c->check_struct (this) && |
334 | mathKernCoverage.sanitize (c, this) && |
335 | mathKernInfoRecords.sanitize (c, this)); |
336 | } |
337 | |
338 | hb_position_t get_kerning (hb_codepoint_t glyph, |
339 | hb_ot_math_kern_t kern, |
340 | hb_position_t correction_height, |
341 | hb_font_t *font) const |
342 | { |
343 | unsigned int index = (this+mathKernCoverage).get_coverage (glyph); |
344 | return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); |
345 | } |
346 | |
347 | protected: |
348 | OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table - |
349 | * from the beginning of the |
350 | * MathKernInfo table. */ |
351 | ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of |
352 | * MathKernInfoRecords, |
353 | * per-glyph information for |
354 | * mathematical positioning |
355 | * of subscripts and |
356 | * superscripts. */ |
357 | |
358 | public: |
359 | DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); |
360 | }; |
361 | |
362 | struct MathGlyphInfo |
363 | { |
364 | bool sanitize (hb_sanitize_context_t *c) const |
365 | { |
366 | TRACE_SANITIZE (this); |
367 | return_trace (c->check_struct (this) && |
368 | mathItalicsCorrectionInfo.sanitize (c, this) && |
369 | mathTopAccentAttachment.sanitize (c, this) && |
370 | extendedShapeCoverage.sanitize (c, this) && |
371 | mathKernInfo.sanitize (c, this)); |
372 | } |
373 | |
374 | hb_position_t |
375 | get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const |
376 | { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); } |
377 | |
378 | hb_position_t |
379 | get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const |
380 | { return (this+mathTopAccentAttachment).get_value (glyph, font); } |
381 | |
382 | bool is_extended_shape (hb_codepoint_t glyph) const |
383 | { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; } |
384 | |
385 | hb_position_t get_kerning (hb_codepoint_t glyph, |
386 | hb_ot_math_kern_t kern, |
387 | hb_position_t correction_height, |
388 | hb_font_t *font) const |
389 | { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } |
390 | |
391 | protected: |
392 | /* Offset to MathItalicsCorrectionInfo table - |
393 | * from the beginning of MathGlyphInfo table. */ |
394 | OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo; |
395 | |
396 | /* Offset to MathTopAccentAttachment table - |
397 | * from the beginning of MathGlyphInfo table. */ |
398 | OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment; |
399 | |
400 | /* Offset to coverage table for Extended Shape glyphs - |
401 | * from the beginning of MathGlyphInfo table. When the left or right glyph of |
402 | * a box is an extended shape variant, the (ink) box (and not the default |
403 | * position defined by values in MathConstants table) should be used for |
404 | * vertical positioning purposes. May be NULL.. */ |
405 | OffsetTo<Coverage> extendedShapeCoverage; |
406 | |
407 | /* Offset to MathKernInfo table - |
408 | * from the beginning of MathGlyphInfo table. */ |
409 | OffsetTo<MathKernInfo> mathKernInfo; |
410 | |
411 | public: |
412 | DEFINE_SIZE_STATIC (8); |
413 | }; |
414 | |
415 | struct MathGlyphVariantRecord |
416 | { |
417 | friend struct MathGlyphConstruction; |
418 | |
419 | bool sanitize (hb_sanitize_context_t *c) const |
420 | { |
421 | TRACE_SANITIZE (this); |
422 | return_trace (c->check_struct (this)); |
423 | } |
424 | |
425 | protected: |
426 | GlyphID variantGlyph; /* Glyph ID for the variant. */ |
427 | HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the |
428 | * variant, in the direction of requested |
429 | * glyph extension. */ |
430 | |
431 | public: |
432 | DEFINE_SIZE_STATIC (4); |
433 | }; |
434 | |
435 | struct PartFlags : HBUINT16 |
436 | { |
437 | enum Flags { |
438 | Extender = 0x0001u, /* If set, the part can be skipped or repeated. */ |
439 | |
440 | Defined = 0x0001u, /* All defined flags. */ |
441 | }; |
442 | |
443 | public: |
444 | DEFINE_SIZE_STATIC (2); |
445 | }; |
446 | |
447 | struct MathGlyphPartRecord |
448 | { |
449 | bool sanitize (hb_sanitize_context_t *c) const |
450 | { |
451 | TRACE_SANITIZE (this); |
452 | return_trace (c->check_struct (this)); |
453 | } |
454 | |
455 | void (hb_ot_math_glyph_part_t &out, |
456 | int scale, |
457 | hb_font_t *font) const |
458 | { |
459 | out.glyph = glyph; |
460 | |
461 | out.start_connector_length = font->em_scale (startConnectorLength, scale); |
462 | out.end_connector_length = font->em_scale (endConnectorLength, scale); |
463 | out.full_advance = font->em_scale (fullAdvance, scale); |
464 | |
465 | static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == |
466 | (unsigned int) PartFlags::Extender, "" ); |
467 | |
468 | out.flags = (hb_ot_math_glyph_part_flags_t) |
469 | (unsigned int) |
470 | (partFlags & PartFlags::Defined); |
471 | } |
472 | |
473 | protected: |
474 | GlyphID glyph; /* Glyph ID for the part. */ |
475 | HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar |
476 | * connector material, in design units, is at |
477 | * the beginning of the glyph, in the |
478 | * direction of the extension. */ |
479 | HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar |
480 | * connector material, in design units, is at |
481 | * the end of the glyph, in the direction of |
482 | * the extension. */ |
483 | HBUINT16 fullAdvance; /* Full advance width/height for this part, |
484 | * in the direction of the extension. |
485 | * In design units. */ |
486 | PartFlags partFlags; /* Part qualifiers. */ |
487 | |
488 | public: |
489 | DEFINE_SIZE_STATIC (10); |
490 | }; |
491 | |
492 | struct MathGlyphAssembly |
493 | { |
494 | bool sanitize (hb_sanitize_context_t *c) const |
495 | { |
496 | TRACE_SANITIZE (this); |
497 | return_trace (c->check_struct (this) && |
498 | italicsCorrection.sanitize (c, this) && |
499 | partRecords.sanitize (c)); |
500 | } |
501 | |
502 | unsigned int get_parts (hb_direction_t direction, |
503 | hb_font_t *font, |
504 | unsigned int start_offset, |
505 | unsigned int *parts_count, /* IN/OUT */ |
506 | hb_ot_math_glyph_part_t *parts /* OUT */, |
507 | hb_position_t *italics_correction /* OUT */) const |
508 | { |
509 | if (parts_count) |
510 | { |
511 | int scale = font->dir_scale (direction); |
512 | hb_array_t<const MathGlyphPartRecord> arr = partRecords.sub_array (start_offset, parts_count); |
513 | unsigned int count = arr.length; |
514 | for (unsigned int i = 0; i < count; i++) |
515 | arr[i].extract (parts[i], scale, font); |
516 | } |
517 | |
518 | if (italics_correction) |
519 | *italics_correction = italicsCorrection.get_x_value (font, this); |
520 | |
521 | return partRecords.len; |
522 | } |
523 | |
524 | protected: |
525 | MathValueRecord italicsCorrection; /* Italics correction of this |
526 | * MathGlyphAssembly. Should not |
527 | * depend on the assembly size. */ |
528 | ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from |
529 | * left to right and bottom to |
530 | * top. */ |
531 | |
532 | public: |
533 | DEFINE_SIZE_ARRAY (6, partRecords); |
534 | }; |
535 | |
536 | struct MathGlyphConstruction |
537 | { |
538 | bool sanitize (hb_sanitize_context_t *c) const |
539 | { |
540 | TRACE_SANITIZE (this); |
541 | return_trace (c->check_struct (this) && |
542 | glyphAssembly.sanitize (c, this) && |
543 | mathGlyphVariantRecord.sanitize (c)); |
544 | } |
545 | |
546 | const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; } |
547 | |
548 | unsigned int get_variants (hb_direction_t direction, |
549 | hb_font_t *font, |
550 | unsigned int start_offset, |
551 | unsigned int *variants_count, /* IN/OUT */ |
552 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
553 | { |
554 | if (variants_count) |
555 | { |
556 | int scale = font->dir_scale (direction); |
557 | hb_array_t<const MathGlyphVariantRecord> arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); |
558 | unsigned int count = arr.length; |
559 | for (unsigned int i = 0; i < count; i++) |
560 | { |
561 | variants[i].glyph = arr[i].variantGlyph; |
562 | variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); |
563 | } |
564 | } |
565 | return mathGlyphVariantRecord.len; |
566 | } |
567 | |
568 | protected: |
569 | /* Offset to MathGlyphAssembly table for this shape - from the beginning of |
570 | MathGlyphConstruction table. May be NULL. */ |
571 | OffsetTo<MathGlyphAssembly> glyphAssembly; |
572 | |
573 | /* MathGlyphVariantRecords for alternative variants of the glyphs. */ |
574 | ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord; |
575 | |
576 | public: |
577 | DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord); |
578 | }; |
579 | |
580 | struct MathVariants |
581 | { |
582 | bool sanitize_offsets (hb_sanitize_context_t *c) const |
583 | { |
584 | TRACE_SANITIZE (this); |
585 | unsigned int count = vertGlyphCount + horizGlyphCount; |
586 | for (unsigned int i = 0; i < count; i++) |
587 | if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false); |
588 | return_trace (true); |
589 | } |
590 | |
591 | bool sanitize (hb_sanitize_context_t *c) const |
592 | { |
593 | TRACE_SANITIZE (this); |
594 | return_trace (c->check_struct (this) && |
595 | vertGlyphCoverage.sanitize (c, this) && |
596 | horizGlyphCoverage.sanitize (c, this) && |
597 | c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) && |
598 | sanitize_offsets (c)); |
599 | } |
600 | |
601 | hb_position_t get_min_connector_overlap (hb_direction_t direction, |
602 | hb_font_t *font) const |
603 | { return font->em_scale_dir (minConnectorOverlap, direction); } |
604 | |
605 | unsigned int get_glyph_variants (hb_codepoint_t glyph, |
606 | hb_direction_t direction, |
607 | hb_font_t *font, |
608 | unsigned int start_offset, |
609 | unsigned int *variants_count, /* IN/OUT */ |
610 | hb_ot_math_glyph_variant_t *variants /* OUT */) const |
611 | { return get_glyph_construction (glyph, direction, font) |
612 | .get_variants (direction, font, start_offset, variants_count, variants); } |
613 | |
614 | unsigned int get_glyph_parts (hb_codepoint_t glyph, |
615 | hb_direction_t direction, |
616 | hb_font_t *font, |
617 | unsigned int start_offset, |
618 | unsigned int *parts_count, /* IN/OUT */ |
619 | hb_ot_math_glyph_part_t *parts /* OUT */, |
620 | hb_position_t *italics_correction /* OUT */) const |
621 | { return get_glyph_construction (glyph, direction, font) |
622 | .get_assembly () |
623 | .get_parts (direction, font, |
624 | start_offset, parts_count, parts, |
625 | italics_correction); } |
626 | |
627 | private: |
628 | const MathGlyphConstruction & |
629 | get_glyph_construction (hb_codepoint_t glyph, |
630 | hb_direction_t direction, |
631 | hb_font_t *font HB_UNUSED) const |
632 | { |
633 | bool vertical = HB_DIRECTION_IS_VERTICAL (direction); |
634 | unsigned int count = vertical ? vertGlyphCount : horizGlyphCount; |
635 | const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage |
636 | : horizGlyphCoverage; |
637 | |
638 | unsigned int index = (this+coverage).get_coverage (glyph); |
639 | if (unlikely (index >= count)) return Null (MathGlyphConstruction); |
640 | |
641 | if (!vertical) |
642 | index += vertGlyphCount; |
643 | |
644 | return this+glyphConstruction[index]; |
645 | } |
646 | |
647 | protected: |
648 | HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting |
649 | * glyphs during glyph construction, |
650 | * in design units. */ |
651 | OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table - |
652 | * from the beginning of MathVariants |
653 | * table. */ |
654 | OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table - |
655 | * from the beginning of MathVariants |
656 | * table. */ |
657 | HBUINT16 vertGlyphCount; /* Number of glyphs for which |
658 | * information is provided for |
659 | * vertically growing variants. */ |
660 | HBUINT16 horizGlyphCount; /* Number of glyphs for which |
661 | * information is provided for |
662 | * horizontally growing variants. */ |
663 | |
664 | /* Array of offsets to MathGlyphConstruction tables - from the beginning of |
665 | the MathVariants table, for shapes growing in vertical/horizontal |
666 | direction. */ |
667 | UnsizedArrayOf<OffsetTo<MathGlyphConstruction> > |
668 | glyphConstruction; |
669 | |
670 | public: |
671 | DEFINE_SIZE_ARRAY (10, glyphConstruction); |
672 | }; |
673 | |
674 | |
675 | /* |
676 | * MATH -- Mathematical typesetting |
677 | * https://docs.microsoft.com/en-us/typography/opentype/spec/math |
678 | */ |
679 | |
680 | struct MATH |
681 | { |
682 | static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH; |
683 | |
684 | bool has_data () const { return version.to_int (); } |
685 | |
686 | bool sanitize (hb_sanitize_context_t *c) const |
687 | { |
688 | TRACE_SANITIZE (this); |
689 | return_trace (version.sanitize (c) && |
690 | likely (version.major == 1) && |
691 | mathConstants.sanitize (c, this) && |
692 | mathGlyphInfo.sanitize (c, this) && |
693 | mathVariants.sanitize (c, this)); |
694 | } |
695 | |
696 | hb_position_t get_constant (hb_ot_math_constant_t constant, |
697 | hb_font_t *font) const |
698 | { return (this+mathConstants).get_value (constant, font); } |
699 | |
700 | const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } |
701 | |
702 | const MathVariants &get_variants () const { return this+mathVariants; } |
703 | |
704 | protected: |
705 | FixedVersion<>version; /* Version of the MATH table |
706 | * initially set to 0x00010000u */ |
707 | OffsetTo<MathConstants> mathConstants;/* MathConstants table */ |
708 | OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */ |
709 | OffsetTo<MathVariants> mathVariants; /* MathVariants table */ |
710 | |
711 | public: |
712 | DEFINE_SIZE_STATIC (10); |
713 | }; |
714 | |
715 | } /* namespace OT */ |
716 | |
717 | |
718 | #endif /* HB_OT_MATH_TABLE_HH */ |
719 | |