Bug 1862332 [wpt PR 42877] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / gfx / harfbuzz / src / hb-ot-math-table.hh
blob32e497aef602d1fcb11c74fbbd20dad2c69f8641
1 /*
2 * Copyright © 2016 Igalia S.L.
4 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
24 * Igalia Author(s): Frédéric Wang
27 #ifndef HB_OT_MATH_TABLE_HH
28 #define HB_OT_MATH_TABLE_HH
30 #include "hb-open-type.hh"
31 #include "hb-ot-layout-common.hh"
32 #include "hb-ot-math.h"
34 namespace OT {
37 struct MathValueRecord
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); }
44 MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const
46 TRACE_SERIALIZE (this);
47 auto *out = c->embed (this);
48 if (unlikely (!out)) return_trace (nullptr);
49 out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
51 return_trace (out);
54 bool sanitize (hb_sanitize_context_t *c, const void *base) const
56 TRACE_SANITIZE (this);
57 return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
60 protected:
61 HBINT16 value; /* The X or Y value in design units */
62 Offset16To<Device> deviceTable; /* Offset to the device table - from the
63 * beginning of parent table. May be NULL.
64 * Suggested format for device table is 1. */
66 public:
67 DEFINE_SIZE_STATIC (4);
70 struct MathConstants
72 MathConstants* copy (hb_serialize_context_t *c) const
74 TRACE_SERIALIZE (this);
75 auto *out = c->start_embed (this);
77 HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
78 if (unlikely (!p)) return_trace (nullptr);
79 hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
81 HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
82 if (unlikely (!m)) return_trace (nullptr);
83 hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
85 unsigned count = ARRAY_LENGTH (mathValueRecords);
86 for (unsigned i = 0; i < count; i++)
87 if (!c->copy (mathValueRecords[i], this))
88 return_trace (nullptr);
90 if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
91 return_trace (out);
94 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
96 TRACE_SANITIZE (this);
98 unsigned int count = ARRAY_LENGTH (mathValueRecords);
99 for (unsigned int i = 0; i < count; i++)
100 if (!mathValueRecords[i].sanitize (c, this))
101 return_trace (false);
103 return_trace (true);
106 bool sanitize (hb_sanitize_context_t *c) const
108 TRACE_SANITIZE (this);
109 return_trace (c->check_struct (this) && sanitize_math_value_records (c));
112 hb_position_t get_value (hb_ot_math_constant_t constant,
113 hb_font_t *font) const
115 switch (constant) {
117 case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
118 case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
119 return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
121 case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
122 case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
123 return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
125 case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
126 case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
127 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
128 case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
129 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
131 case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
132 case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
133 case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
134 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
135 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
136 case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
137 case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
138 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
139 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
140 case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
141 case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
142 case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
143 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
144 case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
145 case HB_OT_MATH_CONSTANT_MATH_LEADING:
146 case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
147 case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
148 case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
149 case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
150 case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
151 case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
152 case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
153 case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
154 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
155 case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
156 case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
157 case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
158 case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
159 case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
160 case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
161 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
162 case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
163 case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
164 case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
165 case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
166 case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
167 case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
168 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
169 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
170 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
171 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
172 case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
173 case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
174 case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
175 case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
176 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
177 case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
178 return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
180 case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
181 return radicalDegreeBottomRaisePercent;
183 default:
184 return 0;
188 protected:
189 HBINT16 percentScaleDown[2];
190 HBUINT16 minHeight[2];
191 MathValueRecord mathValueRecords[51];
192 HBINT16 radicalDegreeBottomRaisePercent;
194 public:
195 DEFINE_SIZE_STATIC (214);
198 struct MathItalicsCorrectionInfo
200 bool subset (hb_subset_context_t *c) const
202 TRACE_SUBSET (this);
203 const hb_set_t &glyphset = c->plan->_glyphset_mathed;
204 const hb_map_t &glyph_map = *c->plan->glyph_map;
206 auto *out = c->serializer->start_embed (*this);
207 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
209 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
210 + hb_zip (this+coverage, italicsCorrection)
211 | hb_filter (glyphset, hb_first)
212 | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
213 | hb_map (hb_first)
214 | hb_map (glyph_map)
215 | hb_sink (new_coverage)
218 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
219 return_trace (true);
222 bool sanitize (hb_sanitize_context_t *c) const
224 TRACE_SANITIZE (this);
225 return_trace (c->check_struct (this) &&
226 coverage.sanitize (c, this) &&
227 italicsCorrection.sanitize (c, this));
230 hb_position_t get_value (hb_codepoint_t glyph,
231 hb_font_t *font) const
233 unsigned int index = (this+coverage).get_coverage (glyph);
234 return italicsCorrection[index].get_x_value (font, this);
237 protected:
238 Offset16To<Coverage> coverage; /* Offset to Coverage table -
239 * from the beginning of
240 * MathItalicsCorrectionInfo
241 * table. */
242 Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
243 * defining italics correction
244 * values for each
245 * covered glyph. */
247 public:
248 DEFINE_SIZE_ARRAY (4, italicsCorrection);
251 struct MathTopAccentAttachment
253 bool subset (hb_subset_context_t *c) const
255 TRACE_SUBSET (this);
256 const hb_set_t &glyphset = c->plan->_glyphset_mathed;
257 const hb_map_t &glyph_map = *c->plan->glyph_map;
259 auto *out = c->serializer->start_embed (*this);
260 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
262 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
263 + hb_zip (this+topAccentCoverage, topAccentAttachment)
264 | hb_filter (glyphset, hb_first)
265 | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
266 | hb_map (hb_first)
267 | hb_map (glyph_map)
268 | hb_sink (new_coverage)
271 out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
272 return_trace (true);
275 bool sanitize (hb_sanitize_context_t *c) const
277 TRACE_SANITIZE (this);
278 return_trace (c->check_struct (this) &&
279 topAccentCoverage.sanitize (c, this) &&
280 topAccentAttachment.sanitize (c, this));
283 hb_position_t get_value (hb_codepoint_t glyph,
284 hb_font_t *font) const
286 unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
287 if (index == NOT_COVERED)
288 return font->get_glyph_h_advance (glyph) / 2;
289 return topAccentAttachment[index].get_x_value (font, this);
292 protected:
293 Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table -
294 * from the beginning of
295 * MathTopAccentAttachment
296 * table. */
297 Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
298 * defining top accent
299 * attachment points for each
300 * covered glyph. */
302 public:
303 DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
306 struct MathKern
308 MathKern* copy (hb_serialize_context_t *c) const
310 TRACE_SERIALIZE (this);
311 auto *out = c->start_embed (this);
313 if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
315 unsigned count = 2 * heightCount + 1;
316 for (unsigned i = 0; i < count; i++)
317 if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
318 return_trace (nullptr);
320 return_trace (out);
323 bool sanitize_math_value_records (hb_sanitize_context_t *c) const
325 TRACE_SANITIZE (this);
326 unsigned int count = 2 * heightCount + 1;
327 for (unsigned int i = 0; i < count; i++)
328 if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
329 return_trace (true);
332 bool sanitize (hb_sanitize_context_t *c) const
334 TRACE_SANITIZE (this);
335 return_trace (c->check_struct (this) &&
336 hb_barrier () &&
337 c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
338 sanitize_math_value_records (c));
341 hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
343 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
344 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
345 int sign = font->y_scale < 0 ? -1 : +1;
347 /* The description of the MathKern table is a ambiguous, but interpreting
348 * "between the two heights found at those indexes" for 0 < i < len as
350 * correctionHeight[i-1] < correction_height <= correctionHeight[i]
352 * makes the result consistent with the limit cases and we can just use the
353 * binary search algorithm of std::upper_bound:
355 unsigned int i = 0;
356 unsigned int count = heightCount;
357 while (count > 0)
359 unsigned int half = count / 2;
360 hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
361 if (sign * height < sign * correction_height)
363 i += half + 1;
364 count -= half + 1;
365 } else
366 count = half;
368 return kernValue[i].get_x_value (font, this);
371 unsigned int get_entries (unsigned int start_offset,
372 unsigned int *entries_count, /* IN/OUT */
373 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
374 hb_font_t *font) const
376 const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
377 const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
378 const unsigned int entriesCount = heightCount + 1;
380 if (entries_count)
382 unsigned int start = hb_min (start_offset, entriesCount);
383 unsigned int end = hb_min (start + *entries_count, entriesCount);
384 *entries_count = end - start;
386 for (unsigned int i = 0; i < *entries_count; i++) {
387 unsigned int j = start + i;
389 hb_position_t max_height;
390 if (j == heightCount) {
391 max_height = INT32_MAX;
392 } else {
393 max_height = correctionHeight[j].get_y_value (font, this);
396 kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
399 return entriesCount;
402 protected:
403 HBUINT16 heightCount;
404 UnsizedArrayOf<MathValueRecord>
405 mathValueRecordsZ;
406 /* Array of correction heights at
407 * which the kern value changes.
408 * Sorted by the height value in
409 * design units (heightCount entries),
410 * Followed by:
411 * Array of kern values corresponding
412 * to heights. (heightCount+1 entries).
415 public:
416 DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
419 struct MathKernInfoRecord
421 MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
423 TRACE_SERIALIZE (this);
424 auto *out = c->embed (this);
425 if (unlikely (!out)) return_trace (nullptr);
427 unsigned count = ARRAY_LENGTH (mathKern);
428 for (unsigned i = 0; i < count; i++)
429 out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
431 return_trace (out);
434 bool sanitize (hb_sanitize_context_t *c, const void *base) const
436 TRACE_SANITIZE (this);
438 unsigned int count = ARRAY_LENGTH (mathKern);
439 for (unsigned int i = 0; i < count; i++)
440 if (unlikely (!mathKern[i].sanitize (c, base)))
441 return_trace (false);
443 return_trace (true);
446 hb_position_t get_kerning (hb_ot_math_kern_t kern,
447 hb_position_t correction_height,
448 hb_font_t *font,
449 const void *base) const
451 unsigned int idx = kern;
452 if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
453 return (base+mathKern[idx]).get_value (correction_height, font);
456 unsigned int get_kernings (hb_ot_math_kern_t kern,
457 unsigned int start_offset,
458 unsigned int *entries_count, /* IN/OUT */
459 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
460 hb_font_t *font,
461 const void *base) const
463 unsigned int idx = kern;
464 if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
465 if (entries_count) *entries_count = 0;
466 return 0;
468 return (base+mathKern[idx]).get_entries (start_offset,
469 entries_count,
470 kern_entries,
471 font);
474 protected:
475 /* Offset to MathKern table for each corner -
476 * from the beginning of MathKernInfo table. May be NULL. */
477 Offset16To<MathKern> mathKern[4];
479 public:
480 DEFINE_SIZE_STATIC (8);
483 struct MathKernInfo
485 bool subset (hb_subset_context_t *c) const
487 TRACE_SUBSET (this);
488 const hb_set_t &glyphset = c->plan->_glyphset_mathed;
489 const hb_map_t &glyph_map = *c->plan->glyph_map;
491 auto *out = c->serializer->start_embed (*this);
492 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
494 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
495 + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
496 | hb_filter (glyphset, hb_first)
497 | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
498 | hb_map (hb_first)
499 | hb_map (glyph_map)
500 | hb_sink (new_coverage)
503 out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
504 return_trace (true);
507 bool sanitize (hb_sanitize_context_t *c) const
509 TRACE_SANITIZE (this);
510 return_trace (c->check_struct (this) &&
511 mathKernCoverage.sanitize (c, this) &&
512 mathKernInfoRecords.sanitize (c, this));
515 hb_position_t get_kerning (hb_codepoint_t glyph,
516 hb_ot_math_kern_t kern,
517 hb_position_t correction_height,
518 hb_font_t *font) const
520 unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
521 return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
524 unsigned int get_kernings (hb_codepoint_t glyph,
525 hb_ot_math_kern_t kern,
526 unsigned int start_offset,
527 unsigned int *entries_count, /* IN/OUT */
528 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
529 hb_font_t *font) const
531 unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
532 return mathKernInfoRecords[index].get_kernings (kern,
533 start_offset,
534 entries_count,
535 kern_entries,
536 font,
537 this);
540 protected:
541 Offset16To<Coverage>
542 mathKernCoverage;
543 /* Offset to Coverage table -
544 * from the beginning of the
545 * MathKernInfo table. */
546 Array16Of<MathKernInfoRecord>
547 mathKernInfoRecords;
548 /* Array of MathKernInfoRecords,
549 * per-glyph information for
550 * mathematical positioning
551 * of subscripts and
552 * superscripts. */
554 public:
555 DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
558 struct MathGlyphInfo
560 bool subset (hb_subset_context_t *c) const
562 TRACE_SUBSET (this);
563 auto *out = c->serializer->embed (*this);
564 if (unlikely (!out)) return_trace (false);
566 out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
567 out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
569 const hb_set_t &glyphset = c->plan->_glyphset_mathed;
570 const hb_map_t &glyph_map = *c->plan->glyph_map;
572 auto it =
573 + hb_iter (this+extendedShapeCoverage)
574 | hb_take (c->plan->source->get_num_glyphs ())
575 | hb_filter (glyphset)
576 | hb_map_retains_sorting (glyph_map)
579 if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
580 else out->extendedShapeCoverage = 0;
582 out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
583 return_trace (true);
586 bool sanitize (hb_sanitize_context_t *c) const
588 TRACE_SANITIZE (this);
589 return_trace (c->check_struct (this) &&
590 mathItalicsCorrectionInfo.sanitize (c, this) &&
591 mathTopAccentAttachment.sanitize (c, this) &&
592 extendedShapeCoverage.sanitize (c, this) &&
593 mathKernInfo.sanitize (c, this));
596 hb_position_t
597 get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
598 { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
600 hb_position_t
601 get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
602 { return (this+mathTopAccentAttachment).get_value (glyph, font); }
604 bool is_extended_shape (hb_codepoint_t glyph) const
605 { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
607 hb_position_t get_kerning (hb_codepoint_t glyph,
608 hb_ot_math_kern_t kern,
609 hb_position_t correction_height,
610 hb_font_t *font) const
611 { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
613 hb_position_t get_kernings (hb_codepoint_t glyph,
614 hb_ot_math_kern_t kern,
615 unsigned int start_offset,
616 unsigned int *entries_count, /* IN/OUT */
617 hb_ot_math_kern_entry_t *kern_entries, /* OUT */
618 hb_font_t *font) const
619 { return (this+mathKernInfo).get_kernings (glyph,
620 kern,
621 start_offset,
622 entries_count,
623 kern_entries,
624 font); }
626 protected:
627 /* Offset to MathItalicsCorrectionInfo table -
628 * from the beginning of MathGlyphInfo table. */
629 Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
631 /* Offset to MathTopAccentAttachment table -
632 * from the beginning of MathGlyphInfo table. */
633 Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
635 /* Offset to coverage table for Extended Shape glyphs -
636 * from the beginning of MathGlyphInfo table. When the left or right glyph of
637 * a box is an extended shape variant, the (ink) box (and not the default
638 * position defined by values in MathConstants table) should be used for
639 * vertical positioning purposes. May be NULL.. */
640 Offset16To<Coverage> extendedShapeCoverage;
642 /* Offset to MathKernInfo table -
643 * from the beginning of MathGlyphInfo table. */
644 Offset16To<MathKernInfo> mathKernInfo;
646 public:
647 DEFINE_SIZE_STATIC (8);
650 struct MathGlyphVariantRecord
652 friend struct MathGlyphConstruction;
654 bool subset (hb_subset_context_t *c) const
656 TRACE_SUBSET (this);
657 auto *out = c->serializer->embed (this);
658 if (unlikely (!out)) return_trace (false);
660 const hb_map_t& glyph_map = *c->plan->glyph_map;
661 return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
664 bool sanitize (hb_sanitize_context_t *c) const
666 TRACE_SANITIZE (this);
667 return_trace (c->check_struct (this));
670 void closure_glyphs (hb_set_t *variant_glyphs) const
671 { variant_glyphs->add (variantGlyph); }
673 protected:
674 HBGlyphID16 variantGlyph; /* Glyph ID for the variant. */
675 HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the
676 * variant, in the direction of requested
677 * glyph extension. */
679 public:
680 DEFINE_SIZE_STATIC (4);
683 struct PartFlags : HBUINT16
685 enum Flags {
686 Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
688 Defined = 0x0001u, /* All defined flags. */
691 public:
692 DEFINE_SIZE_STATIC (2);
695 struct MathGlyphPartRecord
697 bool subset (hb_subset_context_t *c) const
699 TRACE_SUBSET (this);
700 auto *out = c->serializer->embed (this);
701 if (unlikely (!out)) return_trace (false);
703 const hb_map_t& glyph_map = *c->plan->glyph_map;
704 return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
707 bool sanitize (hb_sanitize_context_t *c) const
709 TRACE_SANITIZE (this);
710 return_trace (c->check_struct (this));
713 void extract (hb_ot_math_glyph_part_t &out,
714 int64_t mult,
715 hb_font_t *font) const
717 out.glyph = glyph;
719 out.start_connector_length = font->em_mult (startConnectorLength, mult);
720 out.end_connector_length = font->em_mult (endConnectorLength, mult);
721 out.full_advance = font->em_mult (fullAdvance, mult);
723 static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
724 (unsigned int) PartFlags::Extender, "");
726 out.flags = (hb_ot_math_glyph_part_flags_t)
727 (unsigned int)
728 (partFlags & PartFlags::Defined);
731 void closure_glyphs (hb_set_t *variant_glyphs) const
732 { variant_glyphs->add (glyph); }
734 protected:
735 HBGlyphID16 glyph; /* Glyph ID for the part. */
736 HBUINT16 startConnectorLength;
737 /* Advance width/ height of the straight bar
738 * connector material, in design units, is at
739 * the beginning of the glyph, in the
740 * direction of the extension. */
741 HBUINT16 endConnectorLength;
742 /* Advance width/ height of the straight bar
743 * connector material, in design units, is at
744 * the end of the glyph, in the direction of
745 * the extension. */
746 HBUINT16 fullAdvance; /* Full advance width/height for this part,
747 * in the direction of the extension.
748 * In design units. */
749 PartFlags partFlags; /* Part qualifiers. */
751 public:
752 DEFINE_SIZE_STATIC (10);
755 struct MathGlyphAssembly
757 bool subset (hb_subset_context_t *c) const
759 TRACE_SUBSET (this);
761 if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
762 if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
764 for (const auto& record : partRecords.iter ())
765 if (!record.subset (c)) return_trace (false);
766 return_trace (true);
769 bool sanitize (hb_sanitize_context_t *c) const
771 TRACE_SANITIZE (this);
772 return_trace (c->check_struct (this) &&
773 italicsCorrection.sanitize (c, this) &&
774 partRecords.sanitize (c));
777 unsigned int get_parts (hb_direction_t direction,
778 hb_font_t *font,
779 unsigned int start_offset,
780 unsigned int *parts_count, /* IN/OUT */
781 hb_ot_math_glyph_part_t *parts /* OUT */,
782 hb_position_t *italics_correction /* OUT */) const
784 if (parts_count)
786 int64_t mult = font->dir_mult (direction);
787 for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
788 hb_array (parts, *parts_count)))
789 _.first.extract (_.second, mult, font);
792 if (italics_correction)
793 *italics_correction = italicsCorrection.get_x_value (font, this);
795 return partRecords.len;
798 void closure_glyphs (hb_set_t *variant_glyphs) const
800 for (const auto& _ : partRecords.iter ())
801 _.closure_glyphs (variant_glyphs);
804 protected:
805 MathValueRecord
806 italicsCorrection;
807 /* Italics correction of this
808 * MathGlyphAssembly. Should not
809 * depend on the assembly size. */
810 Array16Of<MathGlyphPartRecord>
811 partRecords; /* Array of part records, from
812 * left to right and bottom to
813 * top. */
815 public:
816 DEFINE_SIZE_ARRAY (6, partRecords);
819 struct MathGlyphConstruction
821 bool subset (hb_subset_context_t *c) const
823 TRACE_SUBSET (this);
824 auto *out = c->serializer->start_embed (*this);
825 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
827 out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
829 if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
830 return_trace (false);
831 for (const auto& record : mathGlyphVariantRecord.iter ())
832 if (!record.subset (c)) return_trace (false);
834 return_trace (true);
837 bool sanitize (hb_sanitize_context_t *c) const
839 TRACE_SANITIZE (this);
840 return_trace (c->check_struct (this) &&
841 glyphAssembly.sanitize (c, this) &&
842 mathGlyphVariantRecord.sanitize (c));
845 const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
847 unsigned int get_variants (hb_direction_t direction,
848 hb_font_t *font,
849 unsigned int start_offset,
850 unsigned int *variants_count, /* IN/OUT */
851 hb_ot_math_glyph_variant_t *variants /* OUT */) const
853 if (variants_count)
855 int64_t mult = font->dir_mult (direction);
856 for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
857 hb_array (variants, *variants_count)))
858 _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
860 return mathGlyphVariantRecord.len;
863 void closure_glyphs (hb_set_t *variant_glyphs) const
865 (this+glyphAssembly).closure_glyphs (variant_glyphs);
867 for (const auto& _ : mathGlyphVariantRecord.iter ())
868 _.closure_glyphs (variant_glyphs);
871 protected:
872 /* Offset to MathGlyphAssembly table for this shape - from the beginning of
873 MathGlyphConstruction table. May be NULL. */
874 Offset16To<MathGlyphAssembly> glyphAssembly;
876 /* MathGlyphVariantRecords for alternative variants of the glyphs. */
877 Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
879 public:
880 DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
883 struct MathVariants
885 void closure_glyphs (const hb_set_t *glyph_set,
886 hb_set_t *variant_glyphs) const
888 const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
890 if (vertGlyphCoverage)
892 const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
893 + hb_zip (this+vertGlyphCoverage, vert_offsets)
894 | hb_filter (glyph_set, hb_first)
895 | hb_map (hb_second)
896 | hb_map (hb_add (this))
897 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
901 if (horizGlyphCoverage)
903 const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
904 + hb_zip (this+horizGlyphCoverage, hori_offsets)
905 | hb_filter (glyph_set, hb_first)
906 | hb_map (hb_second)
907 | hb_map (hb_add (this))
908 | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
913 void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
914 const Offset16To<Coverage>& coverage,
915 unsigned i,
916 unsigned end_index,
917 hb_set_t& indices,
918 const hb_set_t& glyphset,
919 const hb_map_t& glyph_map) const
921 if (!coverage) return;
923 for (const auto _ : (this+coverage).iter ())
925 if (i >= end_index) return;
926 if (glyphset.has (_))
928 unsigned new_gid = glyph_map.get (_);
929 new_coverage.push (new_gid);
930 indices.add (i);
932 i++;
936 bool subset (hb_subset_context_t *c) const
938 TRACE_SUBSET (this);
939 const hb_set_t &glyphset = c->plan->_glyphset_mathed;
940 const hb_map_t &glyph_map = *c->plan->glyph_map;
942 auto *out = c->serializer->start_embed (*this);
943 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
944 if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
945 return_trace (false);
947 hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
948 hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
949 hb_set_t indices;
950 collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
951 collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
953 if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
954 return_trace (false);
955 if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
956 return_trace (false);
958 for (unsigned i : indices.iter ())
960 auto *o = c->serializer->embed (glyphConstruction[i]);
961 if (!o) return_trace (false);
962 o->serialize_subset (c, glyphConstruction[i], this);
965 if (new_vert_coverage)
966 out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
968 if (new_hori_coverage)
969 out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
970 return_trace (true);
973 bool sanitize_offsets (hb_sanitize_context_t *c) const
975 TRACE_SANITIZE (this);
976 unsigned int count = vertGlyphCount + horizGlyphCount;
977 for (unsigned int i = 0; i < count; i++)
978 if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
979 return_trace (true);
982 bool sanitize (hb_sanitize_context_t *c) const
984 TRACE_SANITIZE (this);
985 return_trace (c->check_struct (this) &&
986 vertGlyphCoverage.sanitize (c, this) &&
987 horizGlyphCoverage.sanitize (c, this) &&
988 hb_barrier () &&
989 c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
990 sanitize_offsets (c));
993 hb_position_t get_min_connector_overlap (hb_direction_t direction,
994 hb_font_t *font) const
995 { return font->em_scale_dir (minConnectorOverlap, direction); }
997 unsigned int get_glyph_variants (hb_codepoint_t glyph,
998 hb_direction_t direction,
999 hb_font_t *font,
1000 unsigned int start_offset,
1001 unsigned int *variants_count, /* IN/OUT */
1002 hb_ot_math_glyph_variant_t *variants /* OUT */) const
1003 { return get_glyph_construction (glyph, direction, font)
1004 .get_variants (direction, font, start_offset, variants_count, variants); }
1006 unsigned int get_glyph_parts (hb_codepoint_t glyph,
1007 hb_direction_t direction,
1008 hb_font_t *font,
1009 unsigned int start_offset,
1010 unsigned int *parts_count, /* IN/OUT */
1011 hb_ot_math_glyph_part_t *parts /* OUT */,
1012 hb_position_t *italics_correction /* OUT */) const
1013 { return get_glyph_construction (glyph, direction, font)
1014 .get_assembly ()
1015 .get_parts (direction, font,
1016 start_offset, parts_count, parts,
1017 italics_correction); }
1019 private:
1020 const MathGlyphConstruction &
1021 get_glyph_construction (hb_codepoint_t glyph,
1022 hb_direction_t direction,
1023 hb_font_t *font HB_UNUSED) const
1025 bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1026 unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1027 const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1028 : horizGlyphCoverage;
1030 unsigned int index = (this+coverage).get_coverage (glyph);
1031 if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1033 if (!vertical)
1034 index += vertGlyphCount;
1036 return this+glyphConstruction[index];
1039 protected:
1040 HBUINT16 minConnectorOverlap;
1041 /* Minimum overlap of connecting
1042 * glyphs during glyph construction,
1043 * in design units. */
1044 Offset16To<Coverage> vertGlyphCoverage;
1045 /* Offset to Coverage table -
1046 * from the beginning of MathVariants
1047 * table. */
1048 Offset16To<Coverage> horizGlyphCoverage;
1049 /* Offset to Coverage table -
1050 * from the beginning of MathVariants
1051 * table. */
1052 HBUINT16 vertGlyphCount; /* Number of glyphs for which
1053 * information is provided for
1054 * vertically growing variants. */
1055 HBUINT16 horizGlyphCount;/* Number of glyphs for which
1056 * information is provided for
1057 * horizontally growing variants. */
1059 /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1060 the MathVariants table, for shapes growing in vertical/horizontal
1061 direction. */
1062 UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1063 glyphConstruction;
1065 public:
1066 DEFINE_SIZE_ARRAY (10, glyphConstruction);
1071 * MATH -- Mathematical typesetting
1072 * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1075 struct MATH
1077 static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1079 bool has_data () const { return version.to_int (); }
1081 void closure_glyphs (hb_set_t *glyph_set) const
1083 if (mathVariants)
1085 hb_set_t variant_glyphs;
1086 (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1087 hb_set_union (glyph_set, &variant_glyphs);
1091 bool subset (hb_subset_context_t *c) const
1093 TRACE_SUBSET (this);
1094 auto *out = c->serializer->embed (*this);
1095 if (unlikely (!out)) return_trace (false);
1097 out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1098 out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1099 out->mathVariants.serialize_subset (c, mathVariants, this);
1100 return_trace (true);
1103 bool sanitize (hb_sanitize_context_t *c) const
1105 TRACE_SANITIZE (this);
1106 return_trace (version.sanitize (c) &&
1107 likely (version.major == 1) &&
1108 hb_barrier () &&
1109 mathConstants.sanitize (c, this) &&
1110 mathGlyphInfo.sanitize (c, this) &&
1111 mathVariants.sanitize (c, this));
1114 hb_position_t get_constant (hb_ot_math_constant_t constant,
1115 hb_font_t *font) const
1116 { return (this+mathConstants).get_value (constant, font); }
1118 const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1120 const MathVariants &get_variants () const { return this+mathVariants; }
1122 protected:
1123 FixedVersion<>version; /* Version of the MATH table
1124 * initially set to 0x00010000u */
1125 Offset16To<MathConstants>
1126 mathConstants; /* MathConstants table */
1127 Offset16To<MathGlyphInfo>
1128 mathGlyphInfo; /* MathGlyphInfo table */
1129 Offset16To<MathVariants>
1130 mathVariants; /* MathVariants table */
1132 public:
1133 DEFINE_SIZE_STATIC (10);
1136 } /* namespace OT */
1139 #endif /* HB_OT_MATH_TABLE_HH */