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
34namespace OT {
35
36
37struct 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
60struct 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
166struct 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
197struct 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
230struct 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
295struct 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
328struct 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
362struct 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
415struct 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
435struct 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
447struct 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 extract (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
492struct 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
536struct 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
580struct 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
680struct 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