Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / hb-ot-math-table.hh
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 {
39   hb_position_t get_x_value (hb_font_t *font, const void *base) const
40   { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
41   hb_position_t get_y_value (hb_font_t *font, const void *base) const
42   { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
43
44   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
54   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 {
72   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
94   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
106   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
112   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 {
200   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
222   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
230   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 {
253   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
275   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
283   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 {
308   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
323   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
332   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
340   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
370   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 {
420   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
433   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
445   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
455   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 {
484   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
506   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
514   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
523   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 {
559   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
585   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
596   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
600   get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
601   { return (this+mathTopAccentAttachment).get_value (glyph, font); }
602
603   bool is_extended_shape (hb_codepoint_t glyph) const
604   { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
605
606   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
612   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
653   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
663   bool sanitize (hb_sanitize_context_t *c) const
664   {
665     TRACE_SANITIZE (this);
666     return_trace (c->check_struct (this));
667   }
668
669   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 {
696   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
706   bool sanitize (hb_sanitize_context_t *c) const
707   {
708     TRACE_SANITIZE (this);
709     return_trace (c->check_struct (this));
710   }
711
712   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
730   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 {
756   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
768   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
776   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
797   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 {
820   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
836   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
844   const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
845
846   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
862   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 {
884   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
912   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
935   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
972   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
981   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
991   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
995   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
1004   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 &
1019   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
1077   bool has_data () const { return version.to_int (); }
1078
1079   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
1089   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
1101   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
1111   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
1115   const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1116
1117   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 */