xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-math-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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 {
get_x_valueOT::MathValueRecord39   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); }
get_y_valueOT::MathValueRecord41   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 
copyOT::MathValueRecord44   MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const
45   {
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);
50 
51     return_trace (out);
52   }
53 
sanitizeOT::MathValueRecord54   bool sanitize (hb_sanitize_context_t *c, const void *base) const
55   {
56     TRACE_SANITIZE (this);
57     return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
58   }
59 
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. */
65 
66   public:
67   DEFINE_SIZE_STATIC (4);
68 };
69 
70 struct MathConstants
71 {
copyOT::MathConstants72   MathConstants* copy (hb_serialize_context_t *c) const
73   {
74     TRACE_SERIALIZE (this);
75     auto *out = c->start_embed (this);
76 
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);
80 
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);
84 
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);
89 
90     if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
91     return_trace (out);
92   }
93 
sanitize_math_value_recordsOT::MathConstants94   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
95   {
96     TRACE_SANITIZE (this);
97 
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);
102 
103     return_trace (true);
104   }
105 
sanitizeOT::MathConstants106   bool sanitize (hb_sanitize_context_t *c) const
107   {
108     TRACE_SANITIZE (this);
109     return_trace (c->check_struct (this) && sanitize_math_value_records (c));
110   }
111 
get_valueOT::MathConstants112   hb_position_t get_value (hb_ot_math_constant_t constant,
113 			   hb_font_t *font) const
114   {
115     switch (constant) {
116 
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];
120 
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]);
124 
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);
130 
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);
179 
180     case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
181       return radicalDegreeBottomRaisePercent;
182 
183     default:
184       return 0;
185     }
186   }
187 
188   protected:
189   HBINT16 percentScaleDown[2];
190   HBUINT16 minHeight[2];
191   MathValueRecord mathValueRecords[51];
192   HBINT16 radicalDegreeBottomRaisePercent;
193 
194   public:
195   DEFINE_SIZE_STATIC (214);
196 };
197 
198 struct MathItalicsCorrectionInfo
199 {
subsetOT::MathItalicsCorrectionInfo200   bool subset (hb_subset_context_t *c) const
201   {
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;
205 
206     auto *out = c->serializer->start_embed (*this);
207     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
208 
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)
216     ;
217 
218     out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
219     return_trace (true);
220   }
221 
sanitizeOT::MathItalicsCorrectionInfo222   bool sanitize (hb_sanitize_context_t *c) const
223   {
224     TRACE_SANITIZE (this);
225     return_trace (c->check_struct (this) &&
226 		  coverage.sanitize (c, this) &&
227 		  italicsCorrection.sanitize (c, this));
228   }
229 
get_valueOT::MathItalicsCorrectionInfo230   hb_position_t get_value (hb_codepoint_t glyph,
231 			   hb_font_t *font) const
232   {
233     unsigned int index = (this+coverage).get_coverage (glyph);
234     return italicsCorrection[index].get_x_value (font, this);
235   }
236 
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. */
246 
247   public:
248   DEFINE_SIZE_ARRAY (4, italicsCorrection);
249 };
250 
251 struct MathTopAccentAttachment
252 {
subsetOT::MathTopAccentAttachment253   bool subset (hb_subset_context_t *c) const
254   {
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;
258 
259     auto *out = c->serializer->start_embed (*this);
260     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
261 
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)
269     ;
270 
271     out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
272     return_trace (true);
273   }
274 
sanitizeOT::MathTopAccentAttachment275   bool sanitize (hb_sanitize_context_t *c) const
276   {
277     TRACE_SANITIZE (this);
278     return_trace (c->check_struct (this) &&
279 		  topAccentCoverage.sanitize (c, this) &&
280 		  topAccentAttachment.sanitize (c, this));
281   }
282 
get_valueOT::MathTopAccentAttachment283   hb_position_t get_value (hb_codepoint_t glyph,
284 			   hb_font_t *font) const
285   {
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);
290   }
291 
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. */
301 
302   public:
303   DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
304 };
305 
306 struct MathKern
307 {
copyOT::MathKern308   MathKern* copy (hb_serialize_context_t *c) const
309   {
310     TRACE_SERIALIZE (this);
311     auto *out = c->start_embed (this);
312 
313     if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
314 
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);
319 
320     return_trace (out);
321   }
322 
sanitize_math_value_recordsOT::MathKern323   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
324   {
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);
330   }
331 
sanitizeOT::MathKern332   bool sanitize (hb_sanitize_context_t *c) const
333   {
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));
339   }
340 
get_valueOT::MathKern341   hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
342   {
343     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
344     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
345     int sign = font->y_scale < 0 ? -1 : +1;
346 
347     /* According to OpenType spec (v1.9), except for the boundary cases, the index
348      * chosen for kern value should be i such that
349      *    correctionHeight[i-1] <= correction_height < correctionHeight[i]
350      * We can use the binary search algorithm of std::upper_bound(). Or, we can
351      * use the internal hb_bsearch_impl.
352      */
353     unsigned int pos;
354     auto cmp = +[](const void* key, const void* p,
355                    int sign, hb_font_t* font, const MathKern* mathKern) -> int {
356       return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
357     };
358     unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
359                                      heightCount, MathValueRecord::static_size,
360                                      cmp, sign, font, this) ? pos + 1 : pos;
361     return kernValue[i].get_x_value (font, this);
362   }
363 
get_entriesOT::MathKern364   unsigned int get_entries (unsigned int start_offset,
365 			    unsigned int *entries_count, /* IN/OUT */
366 			    hb_ot_math_kern_entry_t *kern_entries, /* OUT */
367 			    hb_font_t *font) const
368   {
369     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
370     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
371     const unsigned int entriesCount = heightCount + 1;
372 
373     if (entries_count)
374     {
375       unsigned int start = hb_min (start_offset, entriesCount);
376       unsigned int end = hb_min (start + *entries_count, entriesCount);
377       *entries_count = end - start;
378 
379       for (unsigned int i = 0; i < *entries_count; i++) {
380 	unsigned int j = start + i;
381 
382 	hb_position_t max_height;
383 	if (j == heightCount) {
384 	  max_height = INT32_MAX;
385 	} else {
386 	  max_height = correctionHeight[j].get_y_value (font, this);
387 	}
388 
389 	kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
390       }
391     }
392     return entriesCount;
393   }
394 
395   protected:
396   HBUINT16	heightCount;
397   UnsizedArrayOf<MathValueRecord>
398 		mathValueRecordsZ;
399 				/* Array of correction heights at
400 				 * which the kern value changes.
401 				 * Sorted by the height value in
402 				 * design units (heightCount entries),
403 				 * Followed by:
404 				 * Array of kern values corresponding
405 				 * to heights. (heightCount+1 entries).
406 				 */
407 
408   public:
409   DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
410 };
411 
412 struct MathKernInfoRecord
413 {
copyOT::MathKernInfoRecord414   MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
415   {
416     TRACE_SERIALIZE (this);
417     auto *out = c->embed (this);
418     if (unlikely (!out)) return_trace (nullptr);
419 
420     unsigned count = ARRAY_LENGTH (mathKern);
421     for (unsigned i = 0; i < count; i++)
422       out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
423 
424     return_trace (out);
425   }
426 
sanitizeOT::MathKernInfoRecord427   bool sanitize (hb_sanitize_context_t *c, const void *base) const
428   {
429     TRACE_SANITIZE (this);
430 
431     unsigned int count = ARRAY_LENGTH (mathKern);
432     for (unsigned int i = 0; i < count; i++)
433       if (unlikely (!mathKern[i].sanitize (c, base)))
434 	return_trace (false);
435 
436     return_trace (true);
437   }
438 
get_kerningOT::MathKernInfoRecord439   hb_position_t get_kerning (hb_ot_math_kern_t kern,
440 			     hb_position_t correction_height,
441 			     hb_font_t *font,
442 			     const void *base) const
443   {
444     unsigned int idx = kern;
445     if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
446     return (base+mathKern[idx]).get_value (correction_height, font);
447   }
448 
get_kerningsOT::MathKernInfoRecord449   unsigned int get_kernings (hb_ot_math_kern_t kern,
450 			     unsigned int start_offset,
451 			     unsigned int *entries_count, /* IN/OUT */
452 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
453 			     hb_font_t *font,
454 			     const void *base) const
455   {
456     unsigned int idx = kern;
457     if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
458       if (entries_count) *entries_count = 0;
459       return 0;
460     }
461     return (base+mathKern[idx]).get_entries (start_offset,
462 					     entries_count,
463 					     kern_entries,
464 					     font);
465   }
466 
467   protected:
468   /* Offset to MathKern table for each corner -
469    * from the beginning of MathKernInfo table.  May be NULL. */
470   Offset16To<MathKern> mathKern[4];
471 
472   public:
473   DEFINE_SIZE_STATIC (8);
474 };
475 
476 struct MathKernInfo
477 {
subsetOT::MathKernInfo478   bool subset (hb_subset_context_t *c) const
479   {
480     TRACE_SUBSET (this);
481     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
482     const hb_map_t &glyph_map = *c->plan->glyph_map;
483 
484     auto *out = c->serializer->start_embed (*this);
485     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
486 
487     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
488     + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
489     | hb_filter (glyphset, hb_first)
490     | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
491     | hb_map (hb_first)
492     | hb_map (glyph_map)
493     | hb_sink (new_coverage)
494     ;
495 
496     out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
497     return_trace (true);
498   }
499 
sanitizeOT::MathKernInfo500   bool sanitize (hb_sanitize_context_t *c) const
501   {
502     TRACE_SANITIZE (this);
503     return_trace (c->check_struct (this) &&
504 		  mathKernCoverage.sanitize (c, this) &&
505 		  mathKernInfoRecords.sanitize (c, this));
506   }
507 
get_kerningOT::MathKernInfo508   hb_position_t get_kerning (hb_codepoint_t glyph,
509 			     hb_ot_math_kern_t kern,
510 			     hb_position_t correction_height,
511 			     hb_font_t *font) const
512   {
513     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
514     return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
515   }
516 
get_kerningsOT::MathKernInfo517   unsigned int get_kernings (hb_codepoint_t glyph,
518 			     hb_ot_math_kern_t kern,
519 			     unsigned int start_offset,
520 			     unsigned int *entries_count, /* IN/OUT */
521 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
522 			     hb_font_t *font) const
523   {
524     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
525     return mathKernInfoRecords[index].get_kernings (kern,
526 						    start_offset,
527 						    entries_count,
528 						    kern_entries,
529 						    font,
530 						    this);
531   }
532 
533   protected:
534   Offset16To<Coverage>
535 		mathKernCoverage;
536 				/* Offset to Coverage table -
537 				 * from the beginning of the
538 				 * MathKernInfo table. */
539   Array16Of<MathKernInfoRecord>
540 		mathKernInfoRecords;
541 				/* Array of MathKernInfoRecords,
542 				 * per-glyph information for
543 				 * mathematical positioning
544 				 * of subscripts and
545 				 * superscripts. */
546 
547   public:
548   DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
549 };
550 
551 struct MathGlyphInfo
552 {
subsetOT::MathGlyphInfo553   bool subset (hb_subset_context_t *c) const
554   {
555     TRACE_SUBSET (this);
556     auto *out = c->serializer->embed (*this);
557     if (unlikely (!out)) return_trace (false);
558 
559     out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
560     out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
561 
562     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
563     const hb_map_t &glyph_map = *c->plan->glyph_map;
564 
565     auto it =
566     + hb_iter (this+extendedShapeCoverage)
567     | hb_take (c->plan->source->get_num_glyphs ())
568     | hb_filter (glyphset)
569     | hb_map_retains_sorting (glyph_map)
570     ;
571 
572     if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
573     else out->extendedShapeCoverage = 0;
574 
575     out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
576     return_trace (true);
577   }
578 
sanitizeOT::MathGlyphInfo579   bool sanitize (hb_sanitize_context_t *c) const
580   {
581     TRACE_SANITIZE (this);
582     return_trace (c->check_struct (this) &&
583 		  mathItalicsCorrectionInfo.sanitize (c, this) &&
584 		  mathTopAccentAttachment.sanitize (c, this) &&
585 		  extendedShapeCoverage.sanitize (c, this) &&
586 		  mathKernInfo.sanitize (c, this));
587   }
588 
589   hb_position_t
get_italics_correctionOT::MathGlyphInfo590   get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
591   { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
592 
593   hb_position_t
get_top_accent_attachmentOT::MathGlyphInfo594   get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
595   { return (this+mathTopAccentAttachment).get_value (glyph, font); }
596 
is_extended_shapeOT::MathGlyphInfo597   bool is_extended_shape (hb_codepoint_t glyph) const
598   { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
599 
get_kerningOT::MathGlyphInfo600   hb_position_t get_kerning (hb_codepoint_t glyph,
601 			     hb_ot_math_kern_t kern,
602 			     hb_position_t correction_height,
603 			     hb_font_t *font) const
604   { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
605 
get_kerningsOT::MathGlyphInfo606   hb_position_t get_kernings (hb_codepoint_t glyph,
607 			      hb_ot_math_kern_t kern,
608 			      unsigned int start_offset,
609 			      unsigned int *entries_count, /* IN/OUT */
610 			      hb_ot_math_kern_entry_t *kern_entries, /* OUT */
611 			      hb_font_t *font) const
612   { return (this+mathKernInfo).get_kernings (glyph,
613 					     kern,
614 					     start_offset,
615 					     entries_count,
616 					     kern_entries,
617 					     font); }
618 
619   protected:
620   /* Offset to MathItalicsCorrectionInfo table -
621    * from the beginning of MathGlyphInfo table. */
622   Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
623 
624   /* Offset to MathTopAccentAttachment table -
625    * from the beginning of MathGlyphInfo table. */
626   Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
627 
628   /* Offset to coverage table for Extended Shape glyphs -
629    * from the beginning of MathGlyphInfo table. When the left or right glyph of
630    * a box is an extended shape variant, the (ink) box (and not the default
631    * position defined by values in MathConstants table) should be used for
632    * vertical positioning purposes.  May be NULL.. */
633   Offset16To<Coverage> extendedShapeCoverage;
634 
635    /* Offset to MathKernInfo table -
636     * from the beginning of MathGlyphInfo table. */
637   Offset16To<MathKernInfo> mathKernInfo;
638 
639   public:
640   DEFINE_SIZE_STATIC (8);
641 };
642 
643 struct MathGlyphVariantRecord
644 {
645   friend struct MathGlyphConstruction;
646 
subsetOT::MathGlyphVariantRecord647   bool subset (hb_subset_context_t *c) const
648   {
649     TRACE_SUBSET (this);
650     auto *out = c->serializer->embed (this);
651     if (unlikely (!out)) return_trace (false);
652 
653     const hb_map_t& glyph_map = *c->plan->glyph_map;
654     return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
655   }
656 
sanitizeOT::MathGlyphVariantRecord657   bool sanitize (hb_sanitize_context_t *c) const
658   {
659     TRACE_SANITIZE (this);
660     return_trace (c->check_struct (this));
661   }
662 
closure_glyphsOT::MathGlyphVariantRecord663   void closure_glyphs (hb_set_t *variant_glyphs) const
664   { variant_glyphs->add (variantGlyph); }
665 
666   protected:
667   HBGlyphID16 variantGlyph;       /* Glyph ID for the variant. */
668   HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
669 				 * variant, in the direction of requested
670 				 * glyph extension. */
671 
672   public:
673   DEFINE_SIZE_STATIC (4);
674 };
675 
676 struct PartFlags : HBUINT16
677 {
678   enum Flags {
679     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
680 
681     Defined	= 0x0001u, /* All defined flags. */
682   };
683 
684   public:
685   DEFINE_SIZE_STATIC (2);
686 };
687 
688 struct MathGlyphPartRecord
689 {
subsetOT::MathGlyphPartRecord690   bool subset (hb_subset_context_t *c) const
691   {
692     TRACE_SUBSET (this);
693     auto *out = c->serializer->embed (this);
694     if (unlikely (!out)) return_trace (false);
695 
696     const hb_map_t& glyph_map = *c->plan->glyph_map;
697     return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
698   }
699 
sanitizeOT::MathGlyphPartRecord700   bool sanitize (hb_sanitize_context_t *c) const
701   {
702     TRACE_SANITIZE (this);
703     return_trace (c->check_struct (this));
704   }
705 
extractOT::MathGlyphPartRecord706   void extract (hb_ot_math_glyph_part_t &out,
707 		int64_t mult,
708 		hb_font_t *font) const
709   {
710     out.glyph			= glyph;
711 
712     out.start_connector_length	= font->em_mult (startConnectorLength, mult);
713     out.end_connector_length	= font->em_mult (endConnectorLength, mult);
714     out.full_advance		= font->em_mult (fullAdvance, mult);
715 
716     static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
717 		   (unsigned int) PartFlags::Extender, "");
718 
719     out.flags = (hb_ot_math_glyph_part_flags_t)
720 		(unsigned int)
721 		(partFlags & PartFlags::Defined);
722   }
723 
closure_glyphsOT::MathGlyphPartRecord724   void closure_glyphs (hb_set_t *variant_glyphs) const
725   { variant_glyphs->add (glyph); }
726 
727   protected:
728   HBGlyphID16	glyph;		/* Glyph ID for the part. */
729   HBUINT16	startConnectorLength;
730 				/* Advance width/ height of the straight bar
731 				 * connector material, in design units, is at
732 				 * the beginning of the glyph, in the
733 				 * direction of the extension. */
734   HBUINT16	endConnectorLength;
735 				/* Advance width/ height of the straight bar
736 				 * connector material, in design units, is at
737 				 * the end of the glyph, in the direction of
738 				 * the extension. */
739   HBUINT16	fullAdvance;	/* Full advance width/height for this part,
740 				 * in the direction of the extension.
741 				 * In design units. */
742   PartFlags	partFlags;	/* Part qualifiers. */
743 
744   public:
745   DEFINE_SIZE_STATIC (10);
746 };
747 
748 struct MathGlyphAssembly
749 {
subsetOT::MathGlyphAssembly750   bool subset (hb_subset_context_t *c) const
751   {
752     TRACE_SUBSET (this);
753 
754     if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
755     if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
756 
757     for (const auto& record : partRecords.iter ())
758       if (!record.subset (c)) return_trace (false);
759     return_trace (true);
760   }
761 
sanitizeOT::MathGlyphAssembly762   bool sanitize (hb_sanitize_context_t *c) const
763   {
764     TRACE_SANITIZE (this);
765     return_trace (c->check_struct (this) &&
766 		  italicsCorrection.sanitize (c, this) &&
767 		  partRecords.sanitize (c));
768   }
769 
get_partsOT::MathGlyphAssembly770   unsigned int get_parts (hb_direction_t direction,
771 			  hb_font_t *font,
772 			  unsigned int start_offset,
773 			  unsigned int *parts_count, /* IN/OUT */
774 			  hb_ot_math_glyph_part_t *parts /* OUT */,
775 			  hb_position_t *italics_correction /* OUT */) const
776   {
777     if (parts_count)
778     {
779       int64_t mult = font->dir_mult (direction);
780       for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
781 			    hb_array (parts, *parts_count)))
782 	_.first.extract (_.second, mult, font);
783     }
784 
785     if (italics_correction)
786       *italics_correction = italicsCorrection.get_x_value (font, this);
787 
788     return partRecords.len;
789   }
790 
closure_glyphsOT::MathGlyphAssembly791   void closure_glyphs (hb_set_t *variant_glyphs) const
792   {
793     for (const auto& _ : partRecords.iter ())
794       _.closure_glyphs (variant_glyphs);
795   }
796 
797   protected:
798   MathValueRecord
799 		italicsCorrection;
800 				/* Italics correction of this
801 				 * MathGlyphAssembly. Should not
802 				 * depend on the assembly size. */
803   Array16Of<MathGlyphPartRecord>
804 		partRecords;	/* Array of part records, from
805 				 * left to right and bottom to
806 				 * top. */
807 
808   public:
809   DEFINE_SIZE_ARRAY (6, partRecords);
810 };
811 
812 struct MathGlyphConstruction
813 {
subsetOT::MathGlyphConstruction814   bool subset (hb_subset_context_t *c) const
815   {
816     TRACE_SUBSET (this);
817     auto *out = c->serializer->start_embed (*this);
818     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
819 
820     out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
821 
822     if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
823       return_trace (false);
824     for (const auto& record : mathGlyphVariantRecord.iter ())
825       if (!record.subset (c)) return_trace (false);
826 
827     return_trace (true);
828   }
829 
sanitizeOT::MathGlyphConstruction830   bool sanitize (hb_sanitize_context_t *c) const
831   {
832     TRACE_SANITIZE (this);
833     return_trace (c->check_struct (this) &&
834 		  glyphAssembly.sanitize (c, this) &&
835 		  mathGlyphVariantRecord.sanitize (c));
836   }
837 
get_assemblyOT::MathGlyphConstruction838   const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
839 
get_variantsOT::MathGlyphConstruction840   unsigned int get_variants (hb_direction_t direction,
841 			     hb_font_t *font,
842 			     unsigned int start_offset,
843 			     unsigned int *variants_count, /* IN/OUT */
844 			     hb_ot_math_glyph_variant_t *variants /* OUT */) const
845   {
846     if (variants_count)
847     {
848       int64_t mult = font->dir_mult (direction);
849       for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
850 			    hb_array (variants, *variants_count)))
851 	_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
852     }
853     return mathGlyphVariantRecord.len;
854   }
855 
closure_glyphsOT::MathGlyphConstruction856   void closure_glyphs (hb_set_t *variant_glyphs) const
857   {
858     (this+glyphAssembly).closure_glyphs (variant_glyphs);
859 
860     for (const auto& _ : mathGlyphVariantRecord.iter ())
861       _.closure_glyphs (variant_glyphs);
862   }
863 
864   protected:
865   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
866      MathGlyphConstruction table.  May be NULL. */
867   Offset16To<MathGlyphAssembly>	  glyphAssembly;
868 
869   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
870   Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
871 
872   public:
873   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
874 };
875 
876 struct MathVariants
877 {
closure_glyphsOT::MathVariants878   void closure_glyphs (const hb_set_t *glyph_set,
879                        hb_set_t *variant_glyphs) const
880   {
881     const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
882 
883     if (vertGlyphCoverage)
884     {
885       const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
886       + hb_zip (this+vertGlyphCoverage, vert_offsets)
887       | hb_filter (glyph_set, hb_first)
888       | hb_map (hb_second)
889       | hb_map (hb_add (this))
890       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
891       ;
892     }
893 
894     if (horizGlyphCoverage)
895     {
896       const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
897       + hb_zip (this+horizGlyphCoverage, hori_offsets)
898       | hb_filter (glyph_set, hb_first)
899       | hb_map (hb_second)
900       | hb_map (hb_add (this))
901       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
902       ;
903     }
904   }
905 
collect_coverage_and_indicesOT::MathVariants906   void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
907                                      const Offset16To<Coverage>& coverage,
908                                      unsigned i,
909                                      unsigned end_index,
910                                      hb_set_t& indices,
911                                      const hb_set_t& glyphset,
912                                      const hb_map_t& glyph_map) const
913   {
914     if (!coverage) return;
915 
916     for (const auto _ : (this+coverage).iter ())
917     {
918       if (i >= end_index) return;
919       if (glyphset.has (_))
920       {
921         unsigned new_gid = glyph_map.get (_);
922         new_coverage.push (new_gid);
923         indices.add (i);
924       }
925       i++;
926     }
927   }
928 
subsetOT::MathVariants929   bool subset (hb_subset_context_t *c) const
930   {
931     TRACE_SUBSET (this);
932     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
933     const hb_map_t &glyph_map = *c->plan->glyph_map;
934 
935     auto *out = c->serializer->start_embed (*this);
936     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
937     if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
938       return_trace (false);
939 
940     hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
941     hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
942     hb_set_t indices;
943     collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
944     collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
945 
946     if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
947       return_trace (false);
948     if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
949       return_trace (false);
950 
951     for (unsigned i : indices.iter ())
952     {
953       auto *o = c->serializer->embed (glyphConstruction[i]);
954       if (!o) return_trace (false);
955       o->serialize_subset (c, glyphConstruction[i], this);
956     }
957 
958     if (new_vert_coverage)
959       out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
960 
961     if (new_hori_coverage)
962     out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
963     return_trace (true);
964   }
965 
sanitize_offsetsOT::MathVariants966   bool sanitize_offsets (hb_sanitize_context_t *c) const
967   {
968     TRACE_SANITIZE (this);
969     unsigned int count = vertGlyphCount + horizGlyphCount;
970     for (unsigned int i = 0; i < count; i++)
971       if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
972     return_trace (true);
973   }
974 
sanitizeOT::MathVariants975   bool sanitize (hb_sanitize_context_t *c) const
976   {
977     TRACE_SANITIZE (this);
978     return_trace (c->check_struct (this) &&
979 		  vertGlyphCoverage.sanitize (c, this) &&
980 		  horizGlyphCoverage.sanitize (c, this) &&
981 		  hb_barrier () &&
982 		  c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
983 		  sanitize_offsets (c));
984   }
985 
get_min_connector_overlapOT::MathVariants986   hb_position_t get_min_connector_overlap (hb_direction_t direction,
987 						  hb_font_t *font) const
988   { return font->em_scale_dir (minConnectorOverlap, direction); }
989 
get_glyph_variantsOT::MathVariants990   unsigned int get_glyph_variants (hb_codepoint_t glyph,
991 				   hb_direction_t direction,
992 				   hb_font_t *font,
993 				   unsigned int start_offset,
994 				   unsigned int *variants_count, /* IN/OUT */
995 				   hb_ot_math_glyph_variant_t *variants /* OUT */) const
996   { return get_glyph_construction (glyph, direction, font)
997 	   .get_variants (direction, font, start_offset, variants_count, variants); }
998 
get_glyph_partsOT::MathVariants999   unsigned int get_glyph_parts (hb_codepoint_t glyph,
1000 				hb_direction_t direction,
1001 				hb_font_t *font,
1002 				unsigned int start_offset,
1003 				unsigned int *parts_count, /* IN/OUT */
1004 				hb_ot_math_glyph_part_t *parts /* OUT */,
1005 				hb_position_t *italics_correction /* OUT */) const
1006   { return get_glyph_construction (glyph, direction, font)
1007 	   .get_assembly ()
1008 	   .get_parts (direction, font,
1009 		       start_offset, parts_count, parts,
1010 		       italics_correction); }
1011 
1012   private:
1013   const MathGlyphConstruction &
get_glyph_constructionOT::MathVariants1014   get_glyph_construction (hb_codepoint_t glyph,
1015 			  hb_direction_t direction,
1016 			  hb_font_t *font HB_UNUSED) const
1017   {
1018     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1019     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1020     const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1021 						  : horizGlyphCoverage;
1022 
1023     unsigned int index = (this+coverage).get_coverage (glyph);
1024     if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1025 
1026     if (!vertical)
1027       index += vertGlyphCount;
1028 
1029     return this+glyphConstruction[index];
1030   }
1031 
1032   protected:
1033   HBUINT16	minConnectorOverlap;
1034 				/* Minimum overlap of connecting
1035 				 * glyphs during glyph construction,
1036 				 * in design units. */
1037   Offset16To<Coverage> vertGlyphCoverage;
1038 				/* Offset to Coverage table -
1039 				 * from the beginning of MathVariants
1040 				 * table. */
1041   Offset16To<Coverage> horizGlyphCoverage;
1042 				/* Offset to Coverage table -
1043 				 * from the beginning of MathVariants
1044 				 * table. */
1045   HBUINT16	vertGlyphCount;	/* Number of glyphs for which
1046 				 * information is provided for
1047 				 * vertically growing variants. */
1048   HBUINT16	horizGlyphCount;/* Number of glyphs for which
1049 				 * information is provided for
1050 				 * horizontally growing variants. */
1051 
1052   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1053      the MathVariants table, for shapes growing in vertical/horizontal
1054      direction. */
1055   UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1056 			glyphConstruction;
1057 
1058   public:
1059   DEFINE_SIZE_ARRAY (10, glyphConstruction);
1060 };
1061 
1062 
1063 /*
1064  * MATH -- Mathematical typesetting
1065  * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1066  */
1067 
1068 struct MATH
1069 {
1070   static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1071 
has_dataOT::MATH1072   bool has_data () const { return version.to_int (); }
1073 
closure_glyphsOT::MATH1074   void closure_glyphs (hb_set_t *glyph_set) const
1075   {
1076     if (mathVariants)
1077     {
1078       hb_set_t variant_glyphs;
1079       (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1080       hb_set_union (glyph_set, &variant_glyphs);
1081     }
1082   }
1083 
subsetOT::MATH1084   bool subset (hb_subset_context_t *c) const
1085   {
1086     TRACE_SUBSET (this);
1087     auto *out = c->serializer->embed (*this);
1088     if (unlikely (!out)) return_trace (false);
1089 
1090     out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1091     out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1092     out->mathVariants.serialize_subset (c, mathVariants, this);
1093     return_trace (true);
1094   }
1095 
sanitizeOT::MATH1096   bool sanitize (hb_sanitize_context_t *c) const
1097   {
1098     TRACE_SANITIZE (this);
1099     return_trace (version.sanitize (c) &&
1100 		  likely (version.major == 1) &&
1101 		  hb_barrier () &&
1102 		  mathConstants.sanitize (c, this) &&
1103 		  mathGlyphInfo.sanitize (c, this) &&
1104 		  mathVariants.sanitize (c, this));
1105   }
1106 
get_constantOT::MATH1107   hb_position_t get_constant (hb_ot_math_constant_t  constant,
1108 			      hb_font_t		   *font) const
1109   { return (this+mathConstants).get_value (constant, font); }
1110 
get_glyph_infoOT::MATH1111   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1112 
get_variantsOT::MATH1113   const MathVariants &get_variants () const    { return this+mathVariants; }
1114 
1115   protected:
1116   FixedVersion<>version;	/* Version of the MATH table
1117 				 * initially set to 0x00010000u */
1118   Offset16To<MathConstants>
1119 		mathConstants;	/* MathConstants table */
1120   Offset16To<MathGlyphInfo>
1121 		mathGlyphInfo;	/* MathGlyphInfo table */
1122   Offset16To<MathVariants>
1123 		mathVariants;	/* MathVariants table */
1124 
1125   public:
1126   DEFINE_SIZE_STATIC (10);
1127 };
1128 
1129 } /* namespace OT */
1130 
1131 
1132 #endif /* HB_OT_MATH_TABLE_HH */
1133