• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 		  c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
337 		  sanitize_math_value_records (c));
338   }
339 
get_valueOT::MathKern340   hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
341   {
342     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
343     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
344     int sign = font->y_scale < 0 ? -1 : +1;
345 
346     /* The description of the MathKern table is a ambiguous, but interpreting
347      * "between the two heights found at those indexes" for 0 < i < len as
348      *
349      *   correctionHeight[i-1] < correction_height <= correctionHeight[i]
350      *
351      * makes the result consistent with the limit cases and we can just use the
352      * binary search algorithm of std::upper_bound:
353      */
354     unsigned int i = 0;
355     unsigned int count = heightCount;
356     while (count > 0)
357     {
358       unsigned int half = count / 2;
359       hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
360       if (sign * height < sign * correction_height)
361       {
362 	i += half + 1;
363 	count -= half + 1;
364       } else
365 	count = half;
366     }
367     return kernValue[i].get_x_value (font, this);
368   }
369 
get_entriesOT::MathKern370   unsigned int get_entries (unsigned int start_offset,
371 			    unsigned int *entries_count, /* IN/OUT */
372 			    hb_ot_math_kern_entry_t *kern_entries, /* OUT */
373 			    hb_font_t *font) const
374   {
375     const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
376     const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
377     const unsigned int entriesCount = heightCount + 1;
378 
379     if (entries_count)
380     {
381       unsigned int start = hb_min (start_offset, entriesCount);
382       unsigned int end = hb_min (start + *entries_count, entriesCount);
383       *entries_count = end - start;
384 
385       for (unsigned int i = 0; i < *entries_count; i++) {
386 	unsigned int j = start + i;
387 
388 	hb_position_t max_height;
389 	if (j == heightCount) {
390 	  max_height = INT32_MAX;
391 	} else {
392 	  max_height = correctionHeight[j].get_y_value (font, this);
393 	}
394 
395 	kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
396       }
397     }
398     return entriesCount;
399   }
400 
401   protected:
402   HBUINT16	heightCount;
403   UnsizedArrayOf<MathValueRecord>
404 		mathValueRecordsZ;
405 				/* Array of correction heights at
406 				 * which the kern value changes.
407 				 * Sorted by the height value in
408 				 * design units (heightCount entries),
409 				 * Followed by:
410 				 * Array of kern values corresponding
411 				 * to heights. (heightCount+1 entries).
412 				 */
413 
414   public:
415   DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
416 };
417 
418 struct MathKernInfoRecord
419 {
copyOT::MathKernInfoRecord420   MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
421   {
422     TRACE_SERIALIZE (this);
423     auto *out = c->embed (this);
424     if (unlikely (!out)) return_trace (nullptr);
425 
426     unsigned count = ARRAY_LENGTH (mathKern);
427     for (unsigned i = 0; i < count; i++)
428       out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
429 
430     return_trace (out);
431   }
432 
sanitizeOT::MathKernInfoRecord433   bool sanitize (hb_sanitize_context_t *c, const void *base) const
434   {
435     TRACE_SANITIZE (this);
436 
437     unsigned int count = ARRAY_LENGTH (mathKern);
438     for (unsigned int i = 0; i < count; i++)
439       if (unlikely (!mathKern[i].sanitize (c, base)))
440 	return_trace (false);
441 
442     return_trace (true);
443   }
444 
get_kerningOT::MathKernInfoRecord445   hb_position_t get_kerning (hb_ot_math_kern_t kern,
446 			     hb_position_t correction_height,
447 			     hb_font_t *font,
448 			     const void *base) const
449   {
450     unsigned int idx = kern;
451     if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
452     return (base+mathKern[idx]).get_value (correction_height, font);
453   }
454 
get_kerningsOT::MathKernInfoRecord455   unsigned int get_kernings (hb_ot_math_kern_t kern,
456 			     unsigned int start_offset,
457 			     unsigned int *entries_count, /* IN/OUT */
458 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
459 			     hb_font_t *font,
460 			     const void *base) const
461   {
462     unsigned int idx = kern;
463     if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
464       if (entries_count) *entries_count = 0;
465       return 0;
466     }
467     return (base+mathKern[idx]).get_entries (start_offset,
468 					     entries_count,
469 					     kern_entries,
470 					     font);
471   }
472 
473   protected:
474   /* Offset to MathKern table for each corner -
475    * from the beginning of MathKernInfo table.  May be NULL. */
476   Offset16To<MathKern> mathKern[4];
477 
478   public:
479   DEFINE_SIZE_STATIC (8);
480 };
481 
482 struct MathKernInfo
483 {
subsetOT::MathKernInfo484   bool subset (hb_subset_context_t *c) const
485   {
486     TRACE_SUBSET (this);
487     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
488     const hb_map_t &glyph_map = *c->plan->glyph_map;
489 
490     auto *out = c->serializer->start_embed (*this);
491     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
492 
493     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
494     + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
495     | hb_filter (glyphset, hb_first)
496     | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
497     | hb_map (hb_first)
498     | hb_map (glyph_map)
499     | hb_sink (new_coverage)
500     ;
501 
502     out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
503     return_trace (true);
504   }
505 
sanitizeOT::MathKernInfo506   bool sanitize (hb_sanitize_context_t *c) const
507   {
508     TRACE_SANITIZE (this);
509     return_trace (c->check_struct (this) &&
510 		  mathKernCoverage.sanitize (c, this) &&
511 		  mathKernInfoRecords.sanitize (c, this));
512   }
513 
get_kerningOT::MathKernInfo514   hb_position_t get_kerning (hb_codepoint_t glyph,
515 			     hb_ot_math_kern_t kern,
516 			     hb_position_t correction_height,
517 			     hb_font_t *font) const
518   {
519     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
520     return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
521   }
522 
get_kerningsOT::MathKernInfo523   unsigned int get_kernings (hb_codepoint_t glyph,
524 			     hb_ot_math_kern_t kern,
525 			     unsigned int start_offset,
526 			     unsigned int *entries_count, /* IN/OUT */
527 			     hb_ot_math_kern_entry_t *kern_entries, /* OUT */
528 			     hb_font_t *font) const
529   {
530     unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
531     return mathKernInfoRecords[index].get_kernings (kern,
532 						    start_offset,
533 						    entries_count,
534 						    kern_entries,
535 						    font,
536 						    this);
537   }
538 
539   protected:
540   Offset16To<Coverage>
541 		mathKernCoverage;
542 				/* Offset to Coverage table -
543 				 * from the beginning of the
544 				 * MathKernInfo table. */
545   Array16Of<MathKernInfoRecord>
546 		mathKernInfoRecords;
547 				/* Array of MathKernInfoRecords,
548 				 * per-glyph information for
549 				 * mathematical positioning
550 				 * of subscripts and
551 				 * superscripts. */
552 
553   public:
554   DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
555 };
556 
557 struct MathGlyphInfo
558 {
subsetOT::MathGlyphInfo559   bool subset (hb_subset_context_t *c) const
560   {
561     TRACE_SUBSET (this);
562     auto *out = c->serializer->embed (*this);
563     if (unlikely (!out)) return_trace (false);
564 
565     out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
566     out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
567 
568     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
569     const hb_map_t &glyph_map = *c->plan->glyph_map;
570 
571     auto it =
572     + hb_iter (this+extendedShapeCoverage)
573     | hb_take (c->plan->source->get_num_glyphs ())
574     | hb_filter (glyphset)
575     | hb_map_retains_sorting (glyph_map)
576     ;
577 
578     if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
579     else out->extendedShapeCoverage = 0;
580 
581     out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
582     return_trace (true);
583   }
584 
sanitizeOT::MathGlyphInfo585   bool sanitize (hb_sanitize_context_t *c) const
586   {
587     TRACE_SANITIZE (this);
588     return_trace (c->check_struct (this) &&
589 		  mathItalicsCorrectionInfo.sanitize (c, this) &&
590 		  mathTopAccentAttachment.sanitize (c, this) &&
591 		  extendedShapeCoverage.sanitize (c, this) &&
592 		  mathKernInfo.sanitize (c, this));
593   }
594 
595   hb_position_t
get_italics_correctionOT::MathGlyphInfo596   get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
597   { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
598 
599   hb_position_t
get_top_accent_attachmentOT::MathGlyphInfo600   get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
601   { return (this+mathTopAccentAttachment).get_value (glyph, font); }
602 
is_extended_shapeOT::MathGlyphInfo603   bool is_extended_shape (hb_codepoint_t glyph) const
604   { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
605 
get_kerningOT::MathGlyphInfo606   hb_position_t get_kerning (hb_codepoint_t glyph,
607 			     hb_ot_math_kern_t kern,
608 			     hb_position_t correction_height,
609 			     hb_font_t *font) const
610   { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
611 
get_kerningsOT::MathGlyphInfo612   hb_position_t get_kernings (hb_codepoint_t glyph,
613 			      hb_ot_math_kern_t kern,
614 			      unsigned int start_offset,
615 			      unsigned int *entries_count, /* IN/OUT */
616 			      hb_ot_math_kern_entry_t *kern_entries, /* OUT */
617 			      hb_font_t *font) const
618   { return (this+mathKernInfo).get_kernings (glyph,
619 					     kern,
620 					     start_offset,
621 					     entries_count,
622 					     kern_entries,
623 					     font); }
624 
625   protected:
626   /* Offset to MathItalicsCorrectionInfo table -
627    * from the beginning of MathGlyphInfo table. */
628   Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
629 
630   /* Offset to MathTopAccentAttachment table -
631    * from the beginning of MathGlyphInfo table. */
632   Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
633 
634   /* Offset to coverage table for Extended Shape glyphs -
635    * from the beginning of MathGlyphInfo table. When the left or right glyph of
636    * a box is an extended shape variant, the (ink) box (and not the default
637    * position defined by values in MathConstants table) should be used for
638    * vertical positioning purposes.  May be NULL.. */
639   Offset16To<Coverage> extendedShapeCoverage;
640 
641    /* Offset to MathKernInfo table -
642     * from the beginning of MathGlyphInfo table. */
643   Offset16To<MathKernInfo> mathKernInfo;
644 
645   public:
646   DEFINE_SIZE_STATIC (8);
647 };
648 
649 struct MathGlyphVariantRecord
650 {
651   friend struct MathGlyphConstruction;
652 
subsetOT::MathGlyphVariantRecord653   bool subset (hb_subset_context_t *c) const
654   {
655     TRACE_SUBSET (this);
656     auto *out = c->serializer->embed (this);
657     if (unlikely (!out)) return_trace (false);
658 
659     const hb_map_t& glyph_map = *c->plan->glyph_map;
660     return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
661   }
662 
sanitizeOT::MathGlyphVariantRecord663   bool sanitize (hb_sanitize_context_t *c) const
664   {
665     TRACE_SANITIZE (this);
666     return_trace (c->check_struct (this));
667   }
668 
closure_glyphsOT::MathGlyphVariantRecord669   void closure_glyphs (hb_set_t *variant_glyphs) const
670   { variant_glyphs->add (variantGlyph); }
671 
672   protected:
673   HBGlyphID16 variantGlyph;       /* Glyph ID for the variant. */
674   HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
675 				 * variant, in the direction of requested
676 				 * glyph extension. */
677 
678   public:
679   DEFINE_SIZE_STATIC (4);
680 };
681 
682 struct PartFlags : HBUINT16
683 {
684   enum Flags {
685     Extender	= 0x0001u, /* If set, the part can be skipped or repeated. */
686 
687     Defined	= 0x0001u, /* All defined flags. */
688   };
689 
690   public:
691   DEFINE_SIZE_STATIC (2);
692 };
693 
694 struct MathGlyphPartRecord
695 {
subsetOT::MathGlyphPartRecord696   bool subset (hb_subset_context_t *c) const
697   {
698     TRACE_SUBSET (this);
699     auto *out = c->serializer->embed (this);
700     if (unlikely (!out)) return_trace (false);
701 
702     const hb_map_t& glyph_map = *c->plan->glyph_map;
703     return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
704   }
705 
sanitizeOT::MathGlyphPartRecord706   bool sanitize (hb_sanitize_context_t *c) const
707   {
708     TRACE_SANITIZE (this);
709     return_trace (c->check_struct (this));
710   }
711 
extractOT::MathGlyphPartRecord712   void extract (hb_ot_math_glyph_part_t &out,
713 		int64_t mult,
714 		hb_font_t *font) const
715   {
716     out.glyph			= glyph;
717 
718     out.start_connector_length	= font->em_mult (startConnectorLength, mult);
719     out.end_connector_length	= font->em_mult (endConnectorLength, mult);
720     out.full_advance		= font->em_mult (fullAdvance, mult);
721 
722     static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
723 		   (unsigned int) PartFlags::Extender, "");
724 
725     out.flags = (hb_ot_math_glyph_part_flags_t)
726 		(unsigned int)
727 		(partFlags & PartFlags::Defined);
728   }
729 
closure_glyphsOT::MathGlyphPartRecord730   void closure_glyphs (hb_set_t *variant_glyphs) const
731   { variant_glyphs->add (glyph); }
732 
733   protected:
734   HBGlyphID16	glyph;		/* Glyph ID for the part. */
735   HBUINT16	startConnectorLength;
736 				/* Advance width/ height of the straight bar
737 				 * connector material, in design units, is at
738 				 * the beginning of the glyph, in the
739 				 * direction of the extension. */
740   HBUINT16	endConnectorLength;
741 				/* Advance width/ height of the straight bar
742 				 * connector material, in design units, is at
743 				 * the end of the glyph, in the direction of
744 				 * the extension. */
745   HBUINT16	fullAdvance;	/* Full advance width/height for this part,
746 				 * in the direction of the extension.
747 				 * In design units. */
748   PartFlags	partFlags;	/* Part qualifiers. */
749 
750   public:
751   DEFINE_SIZE_STATIC (10);
752 };
753 
754 struct MathGlyphAssembly
755 {
subsetOT::MathGlyphAssembly756   bool subset (hb_subset_context_t *c) const
757   {
758     TRACE_SUBSET (this);
759 
760     if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
761     if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
762 
763     for (const auto& record : partRecords.iter ())
764       if (!record.subset (c)) return_trace (false);
765     return_trace (true);
766   }
767 
sanitizeOT::MathGlyphAssembly768   bool sanitize (hb_sanitize_context_t *c) const
769   {
770     TRACE_SANITIZE (this);
771     return_trace (c->check_struct (this) &&
772 		  italicsCorrection.sanitize (c, this) &&
773 		  partRecords.sanitize (c));
774   }
775 
get_partsOT::MathGlyphAssembly776   unsigned int get_parts (hb_direction_t direction,
777 			  hb_font_t *font,
778 			  unsigned int start_offset,
779 			  unsigned int *parts_count, /* IN/OUT */
780 			  hb_ot_math_glyph_part_t *parts /* OUT */,
781 			  hb_position_t *italics_correction /* OUT */) const
782   {
783     if (parts_count)
784     {
785       int64_t mult = font->dir_mult (direction);
786       for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
787 			    hb_array (parts, *parts_count)))
788 	_.first.extract (_.second, mult, font);
789     }
790 
791     if (italics_correction)
792       *italics_correction = italicsCorrection.get_x_value (font, this);
793 
794     return partRecords.len;
795   }
796 
closure_glyphsOT::MathGlyphAssembly797   void closure_glyphs (hb_set_t *variant_glyphs) const
798   {
799     for (const auto& _ : partRecords.iter ())
800       _.closure_glyphs (variant_glyphs);
801   }
802 
803   protected:
804   MathValueRecord
805 		italicsCorrection;
806 				/* Italics correction of this
807 				 * MathGlyphAssembly. Should not
808 				 * depend on the assembly size. */
809   Array16Of<MathGlyphPartRecord>
810 		partRecords;	/* Array of part records, from
811 				 * left to right and bottom to
812 				 * top. */
813 
814   public:
815   DEFINE_SIZE_ARRAY (6, partRecords);
816 };
817 
818 struct MathGlyphConstruction
819 {
subsetOT::MathGlyphConstruction820   bool subset (hb_subset_context_t *c) const
821   {
822     TRACE_SUBSET (this);
823     auto *out = c->serializer->start_embed (*this);
824     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
825 
826     out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
827 
828     if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
829       return_trace (false);
830     for (const auto& record : mathGlyphVariantRecord.iter ())
831       if (!record.subset (c)) return_trace (false);
832 
833     return_trace (true);
834   }
835 
sanitizeOT::MathGlyphConstruction836   bool sanitize (hb_sanitize_context_t *c) const
837   {
838     TRACE_SANITIZE (this);
839     return_trace (c->check_struct (this) &&
840 		  glyphAssembly.sanitize (c, this) &&
841 		  mathGlyphVariantRecord.sanitize (c));
842   }
843 
get_assemblyOT::MathGlyphConstruction844   const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
845 
get_variantsOT::MathGlyphConstruction846   unsigned int get_variants (hb_direction_t direction,
847 			     hb_font_t *font,
848 			     unsigned int start_offset,
849 			     unsigned int *variants_count, /* IN/OUT */
850 			     hb_ot_math_glyph_variant_t *variants /* OUT */) const
851   {
852     if (variants_count)
853     {
854       int64_t mult = font->dir_mult (direction);
855       for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
856 			    hb_array (variants, *variants_count)))
857 	_.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
858     }
859     return mathGlyphVariantRecord.len;
860   }
861 
closure_glyphsOT::MathGlyphConstruction862   void closure_glyphs (hb_set_t *variant_glyphs) const
863   {
864     (this+glyphAssembly).closure_glyphs (variant_glyphs);
865 
866     for (const auto& _ : mathGlyphVariantRecord.iter ())
867       _.closure_glyphs (variant_glyphs);
868   }
869 
870   protected:
871   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
872      MathGlyphConstruction table.  May be NULL. */
873   Offset16To<MathGlyphAssembly>	  glyphAssembly;
874 
875   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
876   Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
877 
878   public:
879   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
880 };
881 
882 struct MathVariants
883 {
closure_glyphsOT::MathVariants884   void closure_glyphs (const hb_set_t *glyph_set,
885                        hb_set_t *variant_glyphs) const
886   {
887     const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
888 
889     if (vertGlyphCoverage)
890     {
891       const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
892       + hb_zip (this+vertGlyphCoverage, vert_offsets)
893       | hb_filter (glyph_set, hb_first)
894       | hb_map (hb_second)
895       | hb_map (hb_add (this))
896       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
897       ;
898     }
899 
900     if (horizGlyphCoverage)
901     {
902       const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
903       + hb_zip (this+horizGlyphCoverage, hori_offsets)
904       | hb_filter (glyph_set, hb_first)
905       | hb_map (hb_second)
906       | hb_map (hb_add (this))
907       | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
908       ;
909     }
910   }
911 
collect_coverage_and_indicesOT::MathVariants912   void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
913                                      const Offset16To<Coverage>& coverage,
914                                      unsigned i,
915                                      unsigned end_index,
916                                      hb_set_t& indices,
917                                      const hb_set_t& glyphset,
918                                      const hb_map_t& glyph_map) const
919   {
920     if (!coverage) return;
921 
922     for (const auto _ : (this+coverage).iter ())
923     {
924       if (i >= end_index) return;
925       if (glyphset.has (_))
926       {
927         unsigned new_gid = glyph_map.get (_);
928         new_coverage.push (new_gid);
929         indices.add (i);
930       }
931       i++;
932     }
933   }
934 
subsetOT::MathVariants935   bool subset (hb_subset_context_t *c) const
936   {
937     TRACE_SUBSET (this);
938     const hb_set_t &glyphset = c->plan->_glyphset_mathed;
939     const hb_map_t &glyph_map = *c->plan->glyph_map;
940 
941     auto *out = c->serializer->start_embed (*this);
942     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
943     if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
944       return_trace (false);
945 
946     hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
947     hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
948     hb_set_t indices;
949     collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
950     collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
951 
952     if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
953       return_trace (false);
954     if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
955       return_trace (false);
956 
957     for (unsigned i : indices.iter ())
958     {
959       auto *o = c->serializer->embed (glyphConstruction[i]);
960       if (!o) return_trace (false);
961       o->serialize_subset (c, glyphConstruction[i], this);
962     }
963 
964     if (new_vert_coverage)
965       out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
966 
967     if (new_hori_coverage)
968     out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
969     return_trace (true);
970   }
971 
sanitize_offsetsOT::MathVariants972   bool sanitize_offsets (hb_sanitize_context_t *c) const
973   {
974     TRACE_SANITIZE (this);
975     unsigned int count = vertGlyphCount + horizGlyphCount;
976     for (unsigned int i = 0; i < count; i++)
977       if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
978     return_trace (true);
979   }
980 
sanitizeOT::MathVariants981   bool sanitize (hb_sanitize_context_t *c) const
982   {
983     TRACE_SANITIZE (this);
984     return_trace (c->check_struct (this) &&
985 		  vertGlyphCoverage.sanitize (c, this) &&
986 		  horizGlyphCoverage.sanitize (c, this) &&
987 		  c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
988 		  sanitize_offsets (c));
989   }
990 
get_min_connector_overlapOT::MathVariants991   hb_position_t get_min_connector_overlap (hb_direction_t direction,
992 						  hb_font_t *font) const
993   { return font->em_scale_dir (minConnectorOverlap, direction); }
994 
get_glyph_variantsOT::MathVariants995   unsigned int get_glyph_variants (hb_codepoint_t glyph,
996 				   hb_direction_t direction,
997 				   hb_font_t *font,
998 				   unsigned int start_offset,
999 				   unsigned int *variants_count, /* IN/OUT */
1000 				   hb_ot_math_glyph_variant_t *variants /* OUT */) const
1001   { return get_glyph_construction (glyph, direction, font)
1002 	   .get_variants (direction, font, start_offset, variants_count, variants); }
1003 
get_glyph_partsOT::MathVariants1004   unsigned int get_glyph_parts (hb_codepoint_t glyph,
1005 				hb_direction_t direction,
1006 				hb_font_t *font,
1007 				unsigned int start_offset,
1008 				unsigned int *parts_count, /* IN/OUT */
1009 				hb_ot_math_glyph_part_t *parts /* OUT */,
1010 				hb_position_t *italics_correction /* OUT */) const
1011   { return get_glyph_construction (glyph, direction, font)
1012 	   .get_assembly ()
1013 	   .get_parts (direction, font,
1014 		       start_offset, parts_count, parts,
1015 		       italics_correction); }
1016 
1017   private:
1018   const MathGlyphConstruction &
get_glyph_constructionOT::MathVariants1019   get_glyph_construction (hb_codepoint_t glyph,
1020 			  hb_direction_t direction,
1021 			  hb_font_t *font HB_UNUSED) const
1022   {
1023     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1024     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1025     const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1026 						  : horizGlyphCoverage;
1027 
1028     unsigned int index = (this+coverage).get_coverage (glyph);
1029     if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1030 
1031     if (!vertical)
1032       index += vertGlyphCount;
1033 
1034     return this+glyphConstruction[index];
1035   }
1036 
1037   protected:
1038   HBUINT16	minConnectorOverlap;
1039 				/* Minimum overlap of connecting
1040 				 * glyphs during glyph construction,
1041 				 * in design units. */
1042   Offset16To<Coverage> vertGlyphCoverage;
1043 				/* Offset to Coverage table -
1044 				 * from the beginning of MathVariants
1045 				 * table. */
1046   Offset16To<Coverage> horizGlyphCoverage;
1047 				/* Offset to Coverage table -
1048 				 * from the beginning of MathVariants
1049 				 * table. */
1050   HBUINT16	vertGlyphCount;	/* Number of glyphs for which
1051 				 * information is provided for
1052 				 * vertically growing variants. */
1053   HBUINT16	horizGlyphCount;/* Number of glyphs for which
1054 				 * information is provided for
1055 				 * horizontally growing variants. */
1056 
1057   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1058      the MathVariants table, for shapes growing in vertical/horizontal
1059      direction. */
1060   UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1061 			glyphConstruction;
1062 
1063   public:
1064   DEFINE_SIZE_ARRAY (10, glyphConstruction);
1065 };
1066 
1067 
1068 /*
1069  * MATH -- Mathematical typesetting
1070  * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1071  */
1072 
1073 struct MATH
1074 {
1075   static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1076 
has_dataOT::MATH1077   bool has_data () const { return version.to_int (); }
1078 
closure_glyphsOT::MATH1079   void closure_glyphs (hb_set_t *glyph_set) const
1080   {
1081     if (mathVariants)
1082     {
1083       hb_set_t variant_glyphs;
1084       (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1085       hb_set_union (glyph_set, &variant_glyphs);
1086     }
1087   }
1088 
subsetOT::MATH1089   bool subset (hb_subset_context_t *c) const
1090   {
1091     TRACE_SUBSET (this);
1092     auto *out = c->serializer->embed (*this);
1093     if (unlikely (!out)) return_trace (false);
1094 
1095     out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1096     out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1097     out->mathVariants.serialize_subset (c, mathVariants, this);
1098     return_trace (true);
1099   }
1100 
sanitizeOT::MATH1101   bool sanitize (hb_sanitize_context_t *c) const
1102   {
1103     TRACE_SANITIZE (this);
1104     return_trace (version.sanitize (c) &&
1105 		  likely (version.major == 1) &&
1106 		  mathConstants.sanitize (c, this) &&
1107 		  mathGlyphInfo.sanitize (c, this) &&
1108 		  mathVariants.sanitize (c, this));
1109   }
1110 
get_constantOT::MATH1111   hb_position_t get_constant (hb_ot_math_constant_t  constant,
1112 			      hb_font_t		   *font) const
1113   { return (this+mathConstants).get_value (constant, font); }
1114 
get_glyph_infoOT::MATH1115   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1116 
get_variantsOT::MATH1117   const MathVariants &get_variants () const    { return this+mathVariants; }
1118 
1119   protected:
1120   FixedVersion<>version;	/* Version of the MATH table
1121 				 * initially set to 0x00010000u */
1122   Offset16To<MathConstants>
1123 		mathConstants;	/* MathConstants table */
1124   Offset16To<MathGlyphInfo>
1125 		mathGlyphInfo;	/* MathGlyphInfo table */
1126   Offset16To<MathVariants>
1127 		mathVariants;	/* MathVariants table */
1128 
1129   public:
1130   DEFINE_SIZE_STATIC (10);
1131 };
1132 
1133 } /* namespace OT */
1134 
1135 
1136 #endif /* HB_OT_MATH_TABLE_HH */
1137