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     if (unlikely (!out)) return_trace (nullptr);
77 
78     HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
79     if (unlikely (!p)) return_trace (nullptr);
80     memcpy (p, percentScaleDown, HBINT16::static_size * 2);
81 
82     HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
83     if (unlikely (!m)) return_trace (nullptr);
84     memcpy (m, minHeight, HBUINT16::static_size * 2);
85 
86     unsigned count = ARRAY_LENGTH (mathValueRecords);
87     for (unsigned i = 0; i < count; i++)
88       if (!c->copy (mathValueRecords[i], this))
89         return_trace (nullptr);
90 
91     if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
92     return_trace (out);
93   }
94 
sanitize_math_value_recordsOT::MathConstants95   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
96   {
97     TRACE_SANITIZE (this);
98 
99     unsigned int count = ARRAY_LENGTH (mathValueRecords);
100     for (unsigned int i = 0; i < count; i++)
101       if (!mathValueRecords[i].sanitize (c, this))
102 	return_trace (false);
103 
104     return_trace (true);
105   }
106 
sanitizeOT::MathConstants107   bool sanitize (hb_sanitize_context_t *c) const
108   {
109     TRACE_SANITIZE (this);
110     return_trace (c->check_struct (this) && sanitize_math_value_records (c));
111   }
112 
get_valueOT::MathConstants113   hb_position_t get_value (hb_ot_math_constant_t constant,
114 			   hb_font_t *font) const
115   {
116     switch (constant) {
117 
118     case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
119     case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
120       return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
121 
122     case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
123     case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
124       return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
125 
126     case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
127     case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
128     case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
129     case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
130       return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
131 
132     case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
133     case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
134     case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
135     case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
136     case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
137     case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
138     case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
139     case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
140     case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
141     case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
142     case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
143     case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
144     case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
145     case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
146     case HB_OT_MATH_CONSTANT_MATH_LEADING:
147     case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
148     case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
149     case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
150     case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
151     case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
152     case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
153     case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
154     case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
155     case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
156     case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
157     case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
158     case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
159     case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
160     case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
161     case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
162     case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
163     case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
164     case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
165     case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
166     case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
167     case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
168     case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
169     case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
170     case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
171     case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
172     case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
173     case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
174     case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
175     case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
176     case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
177     case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
178     case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
179       return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
180 
181     case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
182       return radicalDegreeBottomRaisePercent;
183 
184     default:
185       return 0;
186     }
187   }
188 
189   protected:
190   HBINT16 percentScaleDown[2];
191   HBUINT16 minHeight[2];
192   MathValueRecord mathValueRecords[51];
193   HBINT16 radicalDegreeBottomRaisePercent;
194 
195   public:
196   DEFINE_SIZE_STATIC (214);
197 };
198 
199 struct MathItalicsCorrectionInfo
200 {
subsetOT::MathItalicsCorrectionInfo201   bool subset (hb_subset_context_t *c) const
202   {
203     TRACE_SUBSET (this);
204     const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
205     const hb_map_t &glyph_map = *c->plan->glyph_map;
206 
207     auto *out = c->serializer->start_embed (*this);
208     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
209 
210     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
211     + hb_zip (this+coverage, italicsCorrection)
212     | hb_filter (glyphset, hb_first)
213     | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
214     | hb_map (hb_first)
215     | hb_map (glyph_map)
216     | hb_sink (new_coverage)
217     ;
218 
219     out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
220     return_trace (true);
221   }
222 
sanitizeOT::MathItalicsCorrectionInfo223   bool sanitize (hb_sanitize_context_t *c) const
224   {
225     TRACE_SANITIZE (this);
226     return_trace (c->check_struct (this) &&
227 		  coverage.sanitize (c, this) &&
228 		  italicsCorrection.sanitize (c, this));
229   }
230 
get_valueOT::MathItalicsCorrectionInfo231   hb_position_t get_value (hb_codepoint_t glyph,
232 			   hb_font_t *font) const
233   {
234     unsigned int index = (this+coverage).get_coverage (glyph);
235     return italicsCorrection[index].get_x_value (font, this);
236   }
237 
238   protected:
239   Offset16To<Coverage>       coverage;		/* Offset to Coverage table -
240 						 * from the beginning of
241 						 * MathItalicsCorrectionInfo
242 						 * table. */
243   Array16Of<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
244 						 * defining italics correction
245 						 * values for each
246 						 * covered glyph. */
247 
248   public:
249   DEFINE_SIZE_ARRAY (4, italicsCorrection);
250 };
251 
252 struct MathTopAccentAttachment
253 {
subsetOT::MathTopAccentAttachment254   bool subset (hb_subset_context_t *c) const
255   {
256     TRACE_SUBSET (this);
257     const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
258     const hb_map_t &glyph_map = *c->plan->glyph_map;
259 
260     auto *out = c->serializer->start_embed (*this);
261     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
262 
263     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
264     + hb_zip (this+topAccentCoverage, topAccentAttachment)
265     | hb_filter (glyphset, hb_first)
266     | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
267     | hb_map (hb_first)
268     | hb_map (glyph_map)
269     | hb_sink (new_coverage)
270     ;
271 
272     out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
273     return_trace (true);
274   }
275 
sanitizeOT::MathTopAccentAttachment276   bool sanitize (hb_sanitize_context_t *c) const
277   {
278     TRACE_SANITIZE (this);
279     return_trace (c->check_struct (this) &&
280 		  topAccentCoverage.sanitize (c, this) &&
281 		  topAccentAttachment.sanitize (c, this));
282   }
283 
get_valueOT::MathTopAccentAttachment284   hb_position_t get_value (hb_codepoint_t glyph,
285 			   hb_font_t *font) const
286   {
287     unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
288     if (index == NOT_COVERED)
289       return font->get_glyph_h_advance (glyph) / 2;
290     return topAccentAttachment[index].get_x_value (font, this);
291   }
292 
293   protected:
294   Offset16To<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
295 						 * from the beginning of
296 						 * MathTopAccentAttachment
297 						 * table. */
298   Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
299 						 * defining top accent
300 						 * attachment points for each
301 						 * covered glyph. */
302 
303   public:
304   DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
305 };
306 
307 struct MathKern
308 {
copyOT::MathKern309   MathKern* copy (hb_serialize_context_t *c) const
310   {
311     TRACE_SERIALIZE (this);
312     auto *out = c->start_embed (this);
313     if (unlikely (!out)) return_trace (nullptr);
314 
315     if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
316 
317     unsigned count = 2 * heightCount + 1;
318     for (unsigned i = 0; i < count; i++)
319       if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
320         return_trace (nullptr);
321 
322     return_trace (out);
323   }
324 
sanitize_math_value_recordsOT::MathKern325   bool sanitize_math_value_records (hb_sanitize_context_t *c) const
326   {
327     TRACE_SANITIZE (this);
328     unsigned int count = 2 * heightCount + 1;
329     for (unsigned int i = 0; i < count; i++)
330       if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
331     return_trace (true);
332   }
333 
sanitizeOT::MathKern334   bool sanitize (hb_sanitize_context_t *c) const
335   {
336     TRACE_SANITIZE (this);
337     return_trace (c->check_struct (this) &&
338 		  c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
339 		  sanitize_math_value_records (c));
340   }
341 
get_valueOT::MathKern342   hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
343   {
344     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
345     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
346     int sign = font->y_scale < 0 ? -1 : +1;
347 
348     /* The description of the MathKern table is a ambiguous, but interpreting
349      * "between the two heights found at those indexes" for 0 < i < len as
350      *
351      *   correctionHeight[i-1] < correction_height <= correctionHeight[i]
352      *
353      * makes the result consistent with the limit cases and we can just use the
354      * binary search algorithm of std::upper_bound:
355      */
356     unsigned int i = 0;
357     unsigned int count = heightCount;
358     while (count > 0)
359     {
360       unsigned int half = count / 2;
361       hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
362       if (sign * height < sign * correction_height)
363       {
364 	i += half + 1;
365 	count -= half + 1;
366       } else
367 	count = half;
368     }
369     return kernValue[i].get_x_value (font, this);
370   }
371 
get_entriesOT::MathKern372   unsigned int get_entries (unsigned int start_offset,
373 			    unsigned int *entries_count, /* IN/OUT */
374 			    hb_ot_math_kern_entry_t *kern_entries, /* OUT */
375 			    hb_font_t *font) const
376   {
377     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
378     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
379     const unsigned int entriesCount = heightCount + 1;
380 
381     if (entries_count)
382     {
383       unsigned int start = hb_min (start_offset, entriesCount);
384       unsigned int end = hb_min (start + *entries_count, entriesCount);
385       *entries_count = end - start;
386 
387       for (unsigned int i = 0; i < *entries_count; i++) {
388 	unsigned int j = start + i;
389 
390 	hb_position_t max_height;
391 	if (j == heightCount) {
392 	  max_height = INT32_MAX;
393 	} else {
394 	  max_height = correctionHeight[j].get_y_value (font, this);
395 	}
396 
397 	kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
398       }
399     }
400     return entriesCount;
401   }
402 
403   protected:
404   HBUINT16	heightCount;
405   UnsizedArrayOf<MathValueRecord>
406 		mathValueRecordsZ;
407 				/* Array of correction heights at
408 				 * which the kern value changes.
409 				 * Sorted by the height value in
410 				 * design units (heightCount entries),
411 				 * Followed by:
412 				 * Array of kern values corresponding
413 				 * to heights. (heightCount+1 entries).
414 				 */
415 
416   public:
417   DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
418 };
419 
420 struct MathKernInfoRecord
421 {
copyOT::MathKernInfoRecord422   MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
423   {
424     TRACE_SERIALIZE (this);
425     auto *out = c->embed (this);
426     if (unlikely (!out)) return_trace (nullptr);
427 
428     unsigned count = ARRAY_LENGTH (mathKern);
429     for (unsigned i = 0; i < count; i++)
430       out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
431 
432     return_trace (out);
433   }
434 
sanitizeOT::MathKernInfoRecord435   bool sanitize (hb_sanitize_context_t *c, const void *base) const
436   {
437     TRACE_SANITIZE (this);
438 
439     unsigned int count = ARRAY_LENGTH (mathKern);
440     for (unsigned int i = 0; i < count; i++)
441       if (unlikely (!mathKern[i].sanitize (c, base)))
442 	return_trace (false);
443 
444     return_trace (true);
445   }
446 
get_kerningOT::MathKernInfoRecord447   hb_position_t get_kerning (hb_ot_math_kern_t kern,
448 			     hb_position_t correction_height,
449 			     hb_font_t *font,
450 			     const void *base) const
451   {
452     unsigned int idx = kern;
453     if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
454     return (base+mathKern[idx]).get_value (correction_height, font);
455   }
456 
get_kerningsOT::MathKernInfoRecord457   unsigned int get_kernings (hb_ot_math_kern_t kern,
458 			     unsigned int start_offset,
459 			     unsigned int *entries_count, /* IN/OUT */
460 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
461 			     hb_font_t *font,
462 			     const void *base) const
463   {
464     unsigned int idx = kern;
465     if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
466       if (entries_count) *entries_count = 0;
467       return 0;
468     }
469     return (base+mathKern[idx]).get_entries (start_offset,
470 					     entries_count,
471 					     kern_entries,
472 					     font);
473   }
474 
475   protected:
476   /* Offset to MathKern table for each corner -
477    * from the beginning of MathKernInfo table.  May be NULL. */
478   Offset16To<MathKern> mathKern[4];
479 
480   public:
481   DEFINE_SIZE_STATIC (8);
482 };
483 
484 struct MathKernInfo
485 {
subsetOT::MathKernInfo486   bool subset (hb_subset_context_t *c) const
487   {
488     TRACE_SUBSET (this);
489     const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
490     const hb_map_t &glyph_map = *c->plan->glyph_map;
491 
492     auto *out = c->serializer->start_embed (*this);
493     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
494 
495     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
496     + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
497     | hb_filter (glyphset, hb_first)
498     | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
499     | hb_map (hb_first)
500     | hb_map (glyph_map)
501     | hb_sink (new_coverage)
502     ;
503 
504     out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
505     return_trace (true);
506   }
507 
sanitizeOT::MathKernInfo508   bool sanitize (hb_sanitize_context_t *c) const
509   {
510     TRACE_SANITIZE (this);
511     return_trace (c->check_struct (this) &&
512 		  mathKernCoverage.sanitize (c, this) &&
513 		  mathKernInfoRecords.sanitize (c, this));
514   }
515 
get_kerningOT::MathKernInfo516   hb_position_t get_kerning (hb_codepoint_t glyph,
517 			     hb_ot_math_kern_t kern,
518 			     hb_position_t correction_height,
519 			     hb_font_t *font) const
520   {
521     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
522     return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
523   }
524 
get_kerningsOT::MathKernInfo525   unsigned int get_kernings (hb_codepoint_t glyph,
526 			     hb_ot_math_kern_t kern,
527 			     unsigned int start_offset,
528 			     unsigned int *entries_count, /* IN/OUT */
529 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
530 			     hb_font_t *font) const
531   {
532     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
533     return mathKernInfoRecords[index].get_kernings (kern,
534 						    start_offset,
535 						    entries_count,
536 						    kern_entries,
537 						    font,
538 						    this);
539   }
540 
541   protected:
542   Offset16To<Coverage>
543 		mathKernCoverage;
544 				/* Offset to Coverage table -
545 				 * from the beginning of the
546 				 * MathKernInfo table. */
547   Array16Of<MathKernInfoRecord>
548 		mathKernInfoRecords;
549 				/* Array of MathKernInfoRecords,
550 				 * per-glyph information for
551 				 * mathematical positioning
552 				 * of subscripts and
553 				 * superscripts. */
554 
555   public:
556   DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
557 };
558 
559 struct MathGlyphInfo
560 {
subsetOT::MathGlyphInfo561   bool subset (hb_subset_context_t *c) const
562   {
563     TRACE_SUBSET (this);
564     auto *out = c->serializer->embed (*this);
565     if (unlikely (!out)) return_trace (false);
566 
567     out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
568     out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
569 
570     const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
571     const hb_map_t &glyph_map = *c->plan->glyph_map;
572 
573     auto it =
574     + hb_iter (this+extendedShapeCoverage)
575     | hb_filter (glyphset)
576     | hb_map_retains_sorting (glyph_map)
577     ;
578 
579     if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
580     else out->extendedShapeCoverage = 0;
581 
582     out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
583     return_trace (true);
584   }
585 
sanitizeOT::MathGlyphInfo586   bool sanitize (hb_sanitize_context_t *c) const
587   {
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));
594   }
595 
596   hb_position_t
get_italics_correctionOT::MathGlyphInfo597   get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
598   { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
599 
600   hb_position_t
get_top_accent_attachmentOT::MathGlyphInfo601   get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
602   { return (this+mathTopAccentAttachment).get_value (glyph, font); }
603 
is_extended_shapeOT::MathGlyphInfo604   bool is_extended_shape (hb_codepoint_t glyph) const
605   { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
606 
get_kerningOT::MathGlyphInfo607   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); }
612 
get_kerningsOT::MathGlyphInfo613   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); }
625 
626   protected:
627   /* Offset to MathItalicsCorrectionInfo table -
628    * from the beginning of MathGlyphInfo table. */
629   Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
630 
631   /* Offset to MathTopAccentAttachment table -
632    * from the beginning of MathGlyphInfo table. */
633   Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
634 
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;
641 
642    /* Offset to MathKernInfo table -
643     * from the beginning of MathGlyphInfo table. */
644   Offset16To<MathKernInfo> mathKernInfo;
645 
646   public:
647   DEFINE_SIZE_STATIC (8);
648 };
649 
650 struct MathGlyphVariantRecord
651 {
652   friend struct MathGlyphConstruction;
653 
subsetOT::MathGlyphVariantRecord654   bool subset (hb_subset_context_t *c) const
655   {
656     TRACE_SUBSET (this);
657     auto *out = c->serializer->embed (this);
658     if (unlikely (!out)) return_trace (false);
659 
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));
662   }
663 
sanitizeOT::MathGlyphVariantRecord664   bool sanitize (hb_sanitize_context_t *c) const
665   {
666     TRACE_SANITIZE (this);
667     return_trace (c->check_struct (this));
668   }
669 
closure_glyphsOT::MathGlyphVariantRecord670   void closure_glyphs (hb_set_t *variant_glyphs) const
671   { variant_glyphs->add (variantGlyph); }
672 
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. */
678 
679   public:
680   DEFINE_SIZE_STATIC (4);
681 };
682 
683 struct PartFlags : HBUINT16
684 {
685   enum Flags {
686     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
687 
688     Defined	= 0x0001u, /* All defined flags. */
689   };
690 
691   public:
692   DEFINE_SIZE_STATIC (2);
693 };
694 
695 struct MathGlyphPartRecord
696 {
subsetOT::MathGlyphPartRecord697   bool subset (hb_subset_context_t *c) const
698   {
699     TRACE_SUBSET (this);
700     auto *out = c->serializer->embed (this);
701     if (unlikely (!out)) return_trace (false);
702 
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));
705   }
706 
sanitizeOT::MathGlyphPartRecord707   bool sanitize (hb_sanitize_context_t *c) const
708   {
709     TRACE_SANITIZE (this);
710     return_trace (c->check_struct (this));
711   }
712 
extractOT::MathGlyphPartRecord713   void extract (hb_ot_math_glyph_part_t &out,
714 		int64_t mult,
715 		hb_font_t *font) const
716   {
717     out.glyph			= glyph;
718 
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);
722 
723     static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
724 		   (unsigned int) PartFlags::Extender, "");
725 
726     out.flags = (hb_ot_math_glyph_part_flags_t)
727 		(unsigned int)
728 		(partFlags & PartFlags::Defined);
729   }
730 
closure_glyphsOT::MathGlyphPartRecord731   void closure_glyphs (hb_set_t *variant_glyphs) const
732   { variant_glyphs->add (glyph); }
733 
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. */
750 
751   public:
752   DEFINE_SIZE_STATIC (10);
753 };
754 
755 struct MathGlyphAssembly
756 {
subsetOT::MathGlyphAssembly757   bool subset (hb_subset_context_t *c) const
758   {
759     TRACE_SUBSET (this);
760     auto *out = c->serializer->start_embed (*this);
761     if (unlikely (!out)) return_trace (false);
762 
763     if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
764     if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
765 
766     for (const auto& record : partRecords.iter ())
767       if (!record.subset (c)) return_trace (false);
768     return_trace (true);
769   }
770 
sanitizeOT::MathGlyphAssembly771   bool sanitize (hb_sanitize_context_t *c) const
772   {
773     TRACE_SANITIZE (this);
774     return_trace (c->check_struct (this) &&
775 		  italicsCorrection.sanitize (c, this) &&
776 		  partRecords.sanitize (c));
777   }
778 
get_partsOT::MathGlyphAssembly779   unsigned int get_parts (hb_direction_t direction,
780 			  hb_font_t *font,
781 			  unsigned int start_offset,
782 			  unsigned int *parts_count, /* IN/OUT */
783 			  hb_ot_math_glyph_part_t *parts /* OUT */,
784 			  hb_position_t *italics_correction /* OUT */) const
785   {
786     if (parts_count)
787     {
788       int64_t mult = font->dir_mult (direction);
789       for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count),
790 			    hb_array (parts, *parts_count)))
791 	_.first.extract (_.second, mult, font);
792     }
793 
794     if (italics_correction)
795       *italics_correction = italicsCorrection.get_x_value (font, this);
796 
797     return partRecords.len;
798   }
799 
closure_glyphsOT::MathGlyphAssembly800   void closure_glyphs (hb_set_t *variant_glyphs) const
801   {
802     for (const auto& _ : partRecords.iter ())
803       _.closure_glyphs (variant_glyphs);
804   }
805 
806   protected:
807   MathValueRecord
808 		italicsCorrection;
809 				/* Italics correction of this
810 				 * MathGlyphAssembly. Should not
811 				 * depend on the assembly size. */
812   Array16Of<MathGlyphPartRecord>
813 		partRecords;	/* Array of part records, from
814 				 * left to right and bottom to
815 				 * top. */
816 
817   public:
818   DEFINE_SIZE_ARRAY (6, partRecords);
819 };
820 
821 struct MathGlyphConstruction
822 {
subsetOT::MathGlyphConstruction823   bool subset (hb_subset_context_t *c) const
824   {
825     TRACE_SUBSET (this);
826     auto *out = c->serializer->start_embed (*this);
827     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
828 
829     out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
830 
831     if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
832       return_trace (false);
833     for (const auto& record : mathGlyphVariantRecord.iter ())
834       if (!record.subset (c)) return_trace (false);
835 
836     return_trace (true);
837   }
838 
sanitizeOT::MathGlyphConstruction839   bool sanitize (hb_sanitize_context_t *c) const
840   {
841     TRACE_SANITIZE (this);
842     return_trace (c->check_struct (this) &&
843 		  glyphAssembly.sanitize (c, this) &&
844 		  mathGlyphVariantRecord.sanitize (c));
845   }
846 
get_assemblyOT::MathGlyphConstruction847   const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
848 
get_variantsOT::MathGlyphConstruction849   unsigned int get_variants (hb_direction_t direction,
850 			     hb_font_t *font,
851 			     unsigned int start_offset,
852 			     unsigned int *variants_count, /* IN/OUT */
853 			     hb_ot_math_glyph_variant_t *variants /* OUT */) const
854   {
855     if (variants_count)
856     {
857       int64_t mult = font->dir_mult (direction);
858       for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count),
859 			    hb_array (variants, *variants_count)))
860 	_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
861     }
862     return mathGlyphVariantRecord.len;
863   }
864 
closure_glyphsOT::MathGlyphConstruction865   void closure_glyphs (hb_set_t *variant_glyphs) const
866   {
867     (this+glyphAssembly).closure_glyphs (variant_glyphs);
868 
869     for (const auto& _ : mathGlyphVariantRecord.iter ())
870       _.closure_glyphs (variant_glyphs);
871   }
872 
873   protected:
874   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
875      MathGlyphConstruction table.  May be NULL. */
876   Offset16To<MathGlyphAssembly>	  glyphAssembly;
877 
878   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
879   Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
880 
881   public:
882   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
883 };
884 
885 struct MathVariants
886 {
closure_glyphsOT::MathVariants887   void closure_glyphs (const hb_set_t *glyph_set,
888                        hb_set_t *variant_glyphs) const
889   {
890     const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
891 
892     if (vertGlyphCoverage)
893     {
894       const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
895       + hb_zip (this+vertGlyphCoverage, vert_offsets)
896       | hb_filter (glyph_set, hb_first)
897       | hb_map (hb_second)
898       | hb_map (hb_add (this))
899       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
900       ;
901     }
902 
903     if (horizGlyphCoverage)
904     {
905       const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
906       + hb_zip (this+horizGlyphCoverage, hori_offsets)
907       | hb_filter (glyph_set, hb_first)
908       | hb_map (hb_second)
909       | hb_map (hb_add (this))
910       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
911       ;
912     }
913   }
914 
collect_coverage_and_indicesOT::MathVariants915   void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
916                                      const Offset16To<Coverage>& coverage,
917                                      unsigned i,
918                                      unsigned end_index,
919                                      hb_set_t& indices,
920                                      const hb_set_t& glyphset,
921                                      const hb_map_t& glyph_map) const
922   {
923     if (!coverage) return;
924 
925     for (const auto _ : (this+coverage).iter ())
926     {
927       if (i >= end_index) return;
928       if (glyphset.has (_))
929       {
930         unsigned new_gid = glyph_map.get (_);
931         new_coverage.push (new_gid);
932         indices.add (i);
933       }
934       i++;
935     }
936   }
937 
subsetOT::MathVariants938   bool subset (hb_subset_context_t *c) const
939   {
940     TRACE_SUBSET (this);
941     const hb_set_t &glyphset = *c->plan->_glyphset_mathed;
942     const hb_map_t &glyph_map = *c->plan->glyph_map;
943 
944     auto *out = c->serializer->start_embed (*this);
945     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
946     if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
947       return_trace (false);
948 
949     hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
950     hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
951     hb_set_t indices;
952     collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
953     collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
954 
955     if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
956       return_trace (false);
957     if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
958       return_trace (false);
959 
960     for (unsigned i : indices.iter ())
961     {
962       auto *o = c->serializer->embed (glyphConstruction[i]);
963       if (!o) return_trace (false);
964       o->serialize_subset (c, glyphConstruction[i], this);
965     }
966 
967     if (new_vert_coverage)
968       out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
969 
970     if (new_hori_coverage)
971     out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
972     return_trace (true);
973   }
974 
sanitize_offsetsOT::MathVariants975   bool sanitize_offsets (hb_sanitize_context_t *c) const
976   {
977     TRACE_SANITIZE (this);
978     unsigned int count = vertGlyphCount + horizGlyphCount;
979     for (unsigned int i = 0; i < count; i++)
980       if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
981     return_trace (true);
982   }
983 
sanitizeOT::MathVariants984   bool sanitize (hb_sanitize_context_t *c) const
985   {
986     TRACE_SANITIZE (this);
987     return_trace (c->check_struct (this) &&
988 		  vertGlyphCoverage.sanitize (c, this) &&
989 		  horizGlyphCoverage.sanitize (c, this) &&
990 		  c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
991 		  sanitize_offsets (c));
992   }
993 
get_min_connector_overlapOT::MathVariants994   hb_position_t get_min_connector_overlap (hb_direction_t direction,
995 						  hb_font_t *font) const
996   { return font->em_scale_dir (minConnectorOverlap, direction); }
997 
get_glyph_variantsOT::MathVariants998   unsigned int get_glyph_variants (hb_codepoint_t glyph,
999 				   hb_direction_t direction,
1000 				   hb_font_t *font,
1001 				   unsigned int start_offset,
1002 				   unsigned int *variants_count, /* IN/OUT */
1003 				   hb_ot_math_glyph_variant_t *variants /* OUT */) const
1004   { return get_glyph_construction (glyph, direction, font)
1005 	   .get_variants (direction, font, start_offset, variants_count, variants); }
1006 
get_glyph_partsOT::MathVariants1007   unsigned int get_glyph_parts (hb_codepoint_t glyph,
1008 				hb_direction_t direction,
1009 				hb_font_t *font,
1010 				unsigned int start_offset,
1011 				unsigned int *parts_count, /* IN/OUT */
1012 				hb_ot_math_glyph_part_t *parts /* OUT */,
1013 				hb_position_t *italics_correction /* OUT */) const
1014   { return get_glyph_construction (glyph, direction, font)
1015 	   .get_assembly ()
1016 	   .get_parts (direction, font,
1017 		       start_offset, parts_count, parts,
1018 		       italics_correction); }
1019 
1020   private:
1021   const MathGlyphConstruction &
get_glyph_constructionOT::MathVariants1022   get_glyph_construction (hb_codepoint_t glyph,
1023 			  hb_direction_t direction,
1024 			  hb_font_t *font HB_UNUSED) const
1025   {
1026     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1027     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1028     const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1029 						  : horizGlyphCoverage;
1030 
1031     unsigned int index = (this+coverage).get_coverage (glyph);
1032     if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1033 
1034     if (!vertical)
1035       index += vertGlyphCount;
1036 
1037     return this+glyphConstruction[index];
1038   }
1039 
1040   protected:
1041   HBUINT16	minConnectorOverlap;
1042 				/* Minimum overlap of connecting
1043 				 * glyphs during glyph construction,
1044 				 * in design units. */
1045   Offset16To<Coverage> vertGlyphCoverage;
1046 				/* Offset to Coverage table -
1047 				 * from the beginning of MathVariants
1048 				 * table. */
1049   Offset16To<Coverage> horizGlyphCoverage;
1050 				/* Offset to Coverage table -
1051 				 * from the beginning of MathVariants
1052 				 * table. */
1053   HBUINT16	vertGlyphCount;	/* Number of glyphs for which
1054 				 * information is provided for
1055 				 * vertically growing variants. */
1056   HBUINT16	horizGlyphCount;/* Number of glyphs for which
1057 				 * information is provided for
1058 				 * horizontally growing variants. */
1059 
1060   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1061      the MathVariants table, for shapes growing in vertical/horizontal
1062      direction. */
1063   UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1064 			glyphConstruction;
1065 
1066   public:
1067   DEFINE_SIZE_ARRAY (10, glyphConstruction);
1068 };
1069 
1070 
1071 /*
1072  * MATH -- Mathematical typesetting
1073  * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1074  */
1075 
1076 struct MATH
1077 {
1078   static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1079 
has_dataOT::MATH1080   bool has_data () const { return version.to_int (); }
1081 
closure_glyphsOT::MATH1082   void closure_glyphs (hb_set_t *glyph_set) const
1083   {
1084     if (mathVariants)
1085     {
1086       hb_set_t variant_glyphs;
1087       (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1088       hb_set_union (glyph_set, &variant_glyphs);
1089     }
1090   }
1091 
subsetOT::MATH1092   bool subset (hb_subset_context_t *c) const
1093   {
1094     TRACE_SUBSET (this);
1095     auto *out = c->serializer->embed (*this);
1096     if (unlikely (!out)) return_trace (false);
1097 
1098     out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1099     out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1100     out->mathVariants.serialize_subset (c, mathVariants, this);
1101     return_trace (true);
1102   }
1103 
sanitizeOT::MATH1104   bool sanitize (hb_sanitize_context_t *c) const
1105   {
1106     TRACE_SANITIZE (this);
1107     return_trace (version.sanitize (c) &&
1108 		  likely (version.major == 1) &&
1109 		  mathConstants.sanitize (c, this) &&
1110 		  mathGlyphInfo.sanitize (c, this) &&
1111 		  mathVariants.sanitize (c, this));
1112   }
1113 
get_constantOT::MATH1114   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); }
1117 
get_glyph_infoOT::MATH1118   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1119 
get_variantsOT::MATH1120   const MathVariants &get_variants () const    { return this+mathVariants; }
1121 
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 */
1131 
1132   public:
1133   DEFINE_SIZE_STATIC (10);
1134 };
1135 
1136 } /* namespace OT */
1137 
1138 
1139 #endif /* HB_OT_MATH_TABLE_HH */
1140