Coverage Report

Created: 2023-03-23 11:51

/src/harfbuzz/src/hb-ot-math-table.hh
Line
Count
Source (jump to first uncovered line)
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
2.84M
  { 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
19.1M
  { 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
0
  {
46
0
    TRACE_SERIALIZE (this);
47
0
    auto *out = c->embed (this);
48
0
    if (unlikely (!out)) return_trace (nullptr);
49
0
    out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
50
0
51
0
    return_trace (out);
52
0
  }
53
54
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
55
332M
  {
56
332M
    TRACE_SANITIZE (this);
57
332M
    return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
58
332M
  }
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
0
  {
74
0
    TRACE_SERIALIZE (this);
75
0
    auto *out = c->start_embed (this);
76
0
    if (unlikely (!out)) return_trace (nullptr);
77
0
78
0
    HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
79
0
    if (unlikely (!p)) return_trace (nullptr);
80
0
    hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
81
0
82
0
    HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
83
0
    if (unlikely (!m)) return_trace (nullptr);
84
0
    hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
85
0
86
0
    unsigned count = ARRAY_LENGTH (mathValueRecords);
87
0
    for (unsigned i = 0; i < count; i++)
88
0
      if (!c->copy (mathValueRecords[i], this))
89
0
        return_trace (nullptr);
90
0
91
0
    if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
92
0
    return_trace (out);
93
0
  }
94
95
  bool sanitize_math_value_records (hb_sanitize_context_t *c) const
96
13.5k
  {
97
13.5k
    TRACE_SANITIZE (this);
98
99
13.5k
    unsigned int count = ARRAY_LENGTH (mathValueRecords);
100
601k
    for (unsigned int i = 0; i < count; i++)
101
590k
      if (!mathValueRecords[i].sanitize (c, this))
102
2.35k
  return_trace (false);
103
104
13.5k
    return_trace (true);
105
13.5k
  }
106
107
  bool sanitize (hb_sanitize_context_t *c) const
108
13.8k
  {
109
13.8k
    TRACE_SANITIZE (this);
110
13.8k
    return_trace (c->check_struct (this) && sanitize_math_value_records (c));
111
13.8k
  }
112
113
  hb_position_t get_value (hb_ot_math_constant_t constant,
114
         hb_font_t *font) const
115
22.7M
  {
116
22.7M
    switch (constant) {
117
118
406k
    case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
119
812k
    case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
120
812k
      return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
121
122
406k
    case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
123
812k
    case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
124
812k
      return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
125
126
406k
    case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
127
812k
    case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
128
1.21M
    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
129
1.62M
    case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
130
1.62M
      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
131
132
406k
    case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
133
812k
    case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
134
1.21M
    case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
135
1.62M
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
136
2.03M
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
137
2.43M
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
138
2.84M
    case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
139
3.25M
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
140
3.65M
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
141
4.06M
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
142
4.47M
    case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
143
4.87M
    case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
144
5.28M
    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
145
5.68M
    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
146
6.09M
    case HB_OT_MATH_CONSTANT_MATH_LEADING:
147
6.50M
    case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
148
6.90M
    case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
149
7.31M
    case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
150
7.72M
    case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
151
8.12M
    case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
152
8.53M
    case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
153
8.94M
    case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
154
9.34M
    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
155
9.75M
    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
156
10.1M
    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
157
10.5M
    case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
158
10.9M
    case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
159
11.3M
    case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
160
11.7M
    case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
161
12.1M
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
162
12.5M
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
163
13.0M
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
164
13.4M
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
165
13.8M
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
166
14.2M
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
167
14.6M
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
168
15.0M
    case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
169
15.4M
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
170
15.8M
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
171
16.2M
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
172
16.6M
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
173
17.0M
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
174
17.4M
    case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
175
17.8M
    case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
176
18.2M
    case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
177
18.6M
    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
178
19.1M
    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
179
19.1M
      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
180
181
406k
    case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
182
406k
      return radicalDegreeBottomRaisePercent;
183
184
0
    default:
185
0
      return 0;
186
22.7M
    }
187
22.7M
  }
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
{
201
  bool subset (hb_subset_context_t *c) const
202
0
  {
203
0
    TRACE_SUBSET (this);
204
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
205
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
206
0
207
0
    auto *out = c->serializer->start_embed (*this);
208
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
209
0
210
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
211
0
    + hb_zip (this+coverage, italicsCorrection)
212
0
    | hb_filter (glyphset, hb_first)
213
0
    | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
214
0
    | hb_map (hb_first)
215
0
    | hb_map (glyph_map)
216
0
    | hb_sink (new_coverage)
217
0
    ;
218
0
219
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
220
0
    return_trace (true);
221
0
  }
222
223
  bool sanitize (hb_sanitize_context_t *c) const
224
9.05k
  {
225
9.05k
    TRACE_SANITIZE (this);
226
9.05k
    return_trace (c->check_struct (this) &&
227
9.05k
      coverage.sanitize (c, this) &&
228
9.05k
      italicsCorrection.sanitize (c, this));
229
9.05k
  }
230
231
  hb_position_t get_value (hb_codepoint_t glyph,
232
         hb_font_t *font) const
233
406k
  {
234
406k
    unsigned int index = (this+coverage).get_coverage (glyph);
235
406k
    return italicsCorrection[index].get_x_value (font, this);
236
406k
  }
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
{
254
  bool subset (hb_subset_context_t *c) const
255
0
  {
256
0
    TRACE_SUBSET (this);
257
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
258
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
259
0
260
0
    auto *out = c->serializer->start_embed (*this);
261
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
262
0
263
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
264
0
    + hb_zip (this+topAccentCoverage, topAccentAttachment)
265
0
    | hb_filter (glyphset, hb_first)
266
0
    | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
267
0
    | hb_map (hb_first)
268
0
    | hb_map (glyph_map)
269
0
    | hb_sink (new_coverage)
270
0
    ;
271
0
272
0
    out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
273
0
    return_trace (true);
274
0
  }
275
276
  bool sanitize (hb_sanitize_context_t *c) const
277
8.15k
  {
278
8.15k
    TRACE_SANITIZE (this);
279
8.15k
    return_trace (c->check_struct (this) &&
280
8.15k
      topAccentCoverage.sanitize (c, this) &&
281
8.15k
      topAccentAttachment.sanitize (c, this));
282
8.15k
  }
283
284
  hb_position_t get_value (hb_codepoint_t glyph,
285
         hb_font_t *font) const
286
406k
  {
287
406k
    unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
288
406k
    if (index == NOT_COVERED)
289
406k
      return font->get_glyph_h_advance (glyph) / 2;
290
92
    return topAccentAttachment[index].get_x_value (font, this);
291
406k
  }
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
{
309
  MathKern* copy (hb_serialize_context_t *c) const
310
0
  {
311
0
    TRACE_SERIALIZE (this);
312
0
    auto *out = c->start_embed (this);
313
0
    if (unlikely (!out)) return_trace (nullptr);
314
0
315
0
    if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
316
0
317
0
    unsigned count = 2 * heightCount + 1;
318
0
    for (unsigned i = 0; i < count; i++)
319
0
      if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
320
0
        return_trace (nullptr);
321
0
322
0
    return_trace (out);
323
0
  }
324
325
  bool sanitize_math_value_records (hb_sanitize_context_t *c) const
326
259k
  {
327
259k
    TRACE_SANITIZE (this);
328
259k
    unsigned int count = 2 * heightCount + 1;
329
290M
    for (unsigned int i = 0; i < count; i++)
330
289M
      if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
331
259k
    return_trace (true);
332
259k
  }
333
334
  bool sanitize (hb_sanitize_context_t *c) const
335
270k
  {
336
270k
    TRACE_SANITIZE (this);
337
270k
    return_trace (c->check_struct (this) &&
338
270k
      c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
339
270k
      sanitize_math_value_records (c));
340
270k
  }
341
342
  hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
343
406k
  {
344
406k
    const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
345
406k
    const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
346
406k
    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
406k
    unsigned int i = 0;
357
406k
    unsigned int count = heightCount;
358
406k
    while (count > 0)
359
322
    {
360
322
      unsigned int half = count / 2;
361
322
      hb_position_t height = correctionHeight[i + half].get_y_value (font, this);
362
322
      if (sign * height < sign * correction_height)
363
26
      {
364
26
  i += half + 1;
365
26
  count -= half + 1;
366
26
      } else
367
296
  count = half;
368
322
    }
369
406k
    return kernValue[i].get_x_value (font, this);
370
406k
  }
371
372
  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
168
  {
377
168
    const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
378
168
    const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
379
168
    const unsigned int entriesCount = heightCount + 1;
380
381
168
    if (entries_count)
382
84
    {
383
84
      unsigned int start = hb_min (start_offset, entriesCount);
384
84
      unsigned int end = hb_min (start + *entries_count, entriesCount);
385
84
      *entries_count = end - start;
386
387
394
      for (unsigned int i = 0; i < *entries_count; i++) {
388
310
  unsigned int j = start + i;
389
390
310
  hb_position_t max_height;
391
310
  if (j == heightCount) {
392
44
    max_height = INT32_MAX;
393
266
  } else {
394
266
    max_height = correctionHeight[j].get_y_value (font, this);
395
266
  }
396
397
310
  kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
398
310
      }
399
84
    }
400
168
    return entriesCount;
401
168
  }
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
{
422
  MathKernInfoRecord* copy (hb_serialize_context_t *c, const void *base) const
423
0
  {
424
0
    TRACE_SERIALIZE (this);
425
0
    auto *out = c->embed (this);
426
0
    if (unlikely (!out)) return_trace (nullptr);
427
0
428
0
    unsigned count = ARRAY_LENGTH (mathKern);
429
0
    for (unsigned i = 0; i < count; i++)
430
0
      out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
431
0
432
0
    return_trace (out);
433
0
  }
434
435
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
436
107k
  {
437
107k
    TRACE_SANITIZE (this);
438
439
107k
    unsigned int count = ARRAY_LENGTH (mathKern);
440
530k
    for (unsigned int i = 0; i < count; i++)
441
425k
      if (unlikely (!mathKern[i].sanitize (c, base)))
442
1.88k
  return_trace (false);
443
444
107k
    return_trace (true);
445
107k
  }
446
447
  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
406k
  {
452
406k
    unsigned int idx = kern;
453
406k
    if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
454
406k
    return (base+mathKern[idx]).get_value (correction_height, font);
455
406k
  }
456
457
  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
812k
  {
464
812k
    unsigned int idx = kern;
465
812k
    if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
466
812k
      if (entries_count) *entries_count = 0;
467
812k
      return 0;
468
812k
    }
469
168
    return (base+mathKern[idx]).get_entries (start_offset,
470
168
               entries_count,
471
168
               kern_entries,
472
168
               font);
473
812k
  }
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
{
486
  bool subset (hb_subset_context_t *c) const
487
0
  {
488
0
    TRACE_SUBSET (this);
489
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
490
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
491
0
492
0
    auto *out = c->serializer->start_embed (*this);
493
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
494
0
495
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
496
0
    + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
497
0
    | hb_filter (glyphset, hb_first)
498
0
    | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
499
0
    | hb_map (hb_first)
500
0
    | hb_map (glyph_map)
501
0
    | hb_sink (new_coverage)
502
0
    ;
503
0
504
0
    out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
505
0
    return_trace (true);
506
0
  }
507
508
  bool sanitize (hb_sanitize_context_t *c) const
509
7.31k
  {
510
7.31k
    TRACE_SANITIZE (this);
511
7.31k
    return_trace (c->check_struct (this) &&
512
7.31k
      mathKernCoverage.sanitize (c, this) &&
513
7.31k
      mathKernInfoRecords.sanitize (c, this));
514
7.31k
  }
515
516
  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
406k
  {
521
406k
    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
522
406k
    return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
523
406k
  }
524
525
  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
812k
  {
532
812k
    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
533
812k
    return mathKernInfoRecords[index].get_kernings (kern,
534
812k
                start_offset,
535
812k
                entries_count,
536
812k
                kern_entries,
537
812k
                font,
538
812k
                this);
539
812k
  }
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
{
561
  bool subset (hb_subset_context_t *c) const
562
0
  {
563
0
    TRACE_SUBSET (this);
564
0
    auto *out = c->serializer->embed (*this);
565
0
    if (unlikely (!out)) return_trace (false);
566
0
567
0
    out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
568
0
    out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
569
0
570
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
571
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
572
0
573
0
    auto it =
574
0
    + hb_iter (this+extendedShapeCoverage)
575
0
    | hb_filter (glyphset)
576
0
    | hb_map_retains_sorting (glyph_map)
577
0
    ;
578
0
579
0
    if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
580
0
    else out->extendedShapeCoverage = 0;
581
0
582
0
    out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
583
0
    return_trace (true);
584
0
  }
585
586
  bool sanitize (hb_sanitize_context_t *c) const
587
11.8k
  {
588
11.8k
    TRACE_SANITIZE (this);
589
11.8k
    return_trace (c->check_struct (this) &&
590
11.8k
      mathItalicsCorrectionInfo.sanitize (c, this) &&
591
11.8k
      mathTopAccentAttachment.sanitize (c, this) &&
592
11.8k
      extendedShapeCoverage.sanitize (c, this) &&
593
11.8k
      mathKernInfo.sanitize (c, this));
594
11.8k
  }
595
596
  hb_position_t
597
  get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
598
406k
  { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
599
600
  hb_position_t
601
  get_top_accent_attachment (hb_codepoint_t  glyph, hb_font_t *font) const
602
406k
  { return (this+mathTopAccentAttachment).get_value (glyph, font); }
603
604
  bool is_extended_shape (hb_codepoint_t glyph) const
605
406k
  { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
606
607
  hb_position_t get_kerning (hb_codepoint_t glyph,
608
           hb_ot_math_kern_t kern,
609
           hb_position_t correction_height,
610
           hb_font_t *font) const
611
406k
  { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
612
613
  hb_position_t get_kernings (hb_codepoint_t glyph,
614
            hb_ot_math_kern_t kern,
615
            unsigned int start_offset,
616
            unsigned int *entries_count, /* IN/OUT */
617
            hb_ot_math_kern_entry_t *kern_entries, /* OUT */
618
            hb_font_t *font) const
619
812k
  { return (this+mathKernInfo).get_kernings (glyph,
620
812k
               kern,
621
812k
               start_offset,
622
812k
               entries_count,
623
812k
               kern_entries,
624
812k
               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
654
  bool subset (hb_subset_context_t *c) const
655
0
  {
656
0
    TRACE_SUBSET (this);
657
0
    auto *out = c->serializer->embed (this);
658
0
    if (unlikely (!out)) return_trace (false);
659
0
660
0
    const hb_map_t& glyph_map = *c->plan->glyph_map;
661
0
    return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
662
0
  }
663
664
  bool sanitize (hb_sanitize_context_t *c) const
665
0
  {
666
0
    TRACE_SANITIZE (this);
667
0
    return_trace (c->check_struct (this));
668
0
  }
669
670
  void closure_glyphs (hb_set_t *variant_glyphs) const
671
0
  { 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
{
697
  bool subset (hb_subset_context_t *c) const
698
0
  {
699
0
    TRACE_SUBSET (this);
700
0
    auto *out = c->serializer->embed (this);
701
0
    if (unlikely (!out)) return_trace (false);
702
0
703
0
    const hb_map_t& glyph_map = *c->plan->glyph_map;
704
0
    return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
705
0
  }
706
707
  bool sanitize (hb_sanitize_context_t *c) const
708
0
  {
709
0
    TRACE_SANITIZE (this);
710
0
    return_trace (c->check_struct (this));
711
0
  }
712
713
  void extract (hb_ot_math_glyph_part_t &out,
714
    int64_t mult,
715
    hb_font_t *font) const
716
262
  {
717
262
    out.glyph     = glyph;
718
719
262
    out.start_connector_length  = font->em_mult (startConnectorLength, mult);
720
262
    out.end_connector_length  = font->em_mult (endConnectorLength, mult);
721
262
    out.full_advance    = font->em_mult (fullAdvance, mult);
722
723
262
    static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
724
262
       (unsigned int) PartFlags::Extender, "");
725
726
262
    out.flags = (hb_ot_math_glyph_part_flags_t)
727
262
    (unsigned int)
728
262
    (partFlags & PartFlags::Defined);
729
262
  }
730
731
  void closure_glyphs (hb_set_t *variant_glyphs) const
732
0
  { 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
{
757
  bool subset (hb_subset_context_t *c) const
758
0
  {
759
0
    TRACE_SUBSET (this);
760
0
    auto *out = c->serializer->start_embed (*this);
761
0
    if (unlikely (!out)) return_trace (false);
762
0
763
0
    if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
764
0
    if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
765
0
766
0
    for (const auto& record : partRecords.iter ())
767
0
      if (!record.subset (c)) return_trace (false);
768
0
    return_trace (true);
769
0
  }
770
771
  bool sanitize (hb_sanitize_context_t *c) const
772
195k
  {
773
195k
    TRACE_SANITIZE (this);
774
195k
    return_trace (c->check_struct (this) &&
775
195k
      italicsCorrection.sanitize (c, this) &&
776
195k
      partRecords.sanitize (c));
777
195k
  }
778
779
  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
1.21M
  {
786
1.21M
    if (parts_count)
787
406k
    {
788
406k
      int64_t mult = font->dir_mult (direction);
789
406k
      for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
790
406k
          hb_array (parts, *parts_count)))
791
262
  _.first.extract (_.second, mult, font);
792
406k
    }
793
794
1.21M
    if (italics_correction)
795
406k
      *italics_correction = italicsCorrection.get_x_value (font, this);
796
797
1.21M
    return partRecords.len;
798
1.21M
  }
799
800
  void closure_glyphs (hb_set_t *variant_glyphs) const
801
0
  {
802
0
    for (const auto& _ : partRecords.iter ())
803
0
      _.closure_glyphs (variant_glyphs);
804
0
  }
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
{
823
  bool subset (hb_subset_context_t *c) const
824
0
  {
825
0
    TRACE_SUBSET (this);
826
0
    auto *out = c->serializer->start_embed (*this);
827
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
828
0
829
0
    out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
830
0
831
0
    if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
832
0
      return_trace (false);
833
0
    for (const auto& record : mathGlyphVariantRecord.iter ())
834
0
      if (!record.subset (c)) return_trace (false);
835
0
836
0
    return_trace (true);
837
0
  }
838
839
  bool sanitize (hb_sanitize_context_t *c) const
840
286k
  {
841
286k
    TRACE_SANITIZE (this);
842
286k
    return_trace (c->check_struct (this) &&
843
286k
      glyphAssembly.sanitize (c, this) &&
844
286k
      mathGlyphVariantRecord.sanitize (c));
845
286k
  }
846
847
1.21M
  const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
848
849
  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
1.21M
  {
855
1.21M
    if (variants_count)
856
406k
    {
857
406k
      int64_t mult = font->dir_mult (direction);
858
406k
      for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
859
406k
          hb_array (variants, *variants_count)))
860
393
  _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
861
406k
    }
862
1.21M
    return mathGlyphVariantRecord.len;
863
1.21M
  }
864
865
  void closure_glyphs (hb_set_t *variant_glyphs) const
866
0
  {
867
0
    (this+glyphAssembly).closure_glyphs (variant_glyphs);
868
0
869
0
    for (const auto& _ : mathGlyphVariantRecord.iter ())
870
0
      _.closure_glyphs (variant_glyphs);
871
0
  }
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
{
887
  void closure_glyphs (const hb_set_t *glyph_set,
888
                       hb_set_t *variant_glyphs) const
889
0
  {
890
0
    const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
891
0
892
0
    if (vertGlyphCoverage)
893
0
    {
894
0
      const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
895
0
      + hb_zip (this+vertGlyphCoverage, vert_offsets)
896
0
      | hb_filter (glyph_set, hb_first)
897
0
      | hb_map (hb_second)
898
0
      | hb_map (hb_add (this))
899
0
      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
900
0
      ;
901
0
    }
902
0
903
0
    if (horizGlyphCoverage)
904
0
    {
905
0
      const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
906
0
      + hb_zip (this+horizGlyphCoverage, hori_offsets)
907
0
      | hb_filter (glyph_set, hb_first)
908
0
      | hb_map (hb_second)
909
0
      | hb_map (hb_add (this))
910
0
      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
911
0
      ;
912
0
    }
913
0
  }
914
915
  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
0
  {
923
0
    if (!coverage) return;
924
0
925
0
    for (const auto _ : (this+coverage).iter ())
926
0
    {
927
0
      if (i >= end_index) return;
928
0
      if (glyphset.has (_))
929
0
      {
930
0
        unsigned new_gid = glyph_map.get (_);
931
0
        new_coverage.push (new_gid);
932
0
        indices.add (i);
933
0
      }
934
0
      i++;
935
0
    }
936
0
  }
937
938
  bool subset (hb_subset_context_t *c) const
939
0
  {
940
0
    TRACE_SUBSET (this);
941
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
942
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
943
0
944
0
    auto *out = c->serializer->start_embed (*this);
945
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
946
0
    if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
947
0
      return_trace (false);
948
0
    
949
0
    hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
950
0
    hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
951
0
    hb_set_t indices;
952
0
    collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
953
0
    collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
954
0
    
955
0
    if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
956
0
      return_trace (false);
957
0
    if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
958
0
      return_trace (false);
959
0
960
0
    for (unsigned i : indices.iter ())
961
0
    {
962
0
      auto *o = c->serializer->embed (glyphConstruction[i]);
963
0
      if (!o) return_trace (false);
964
0
      o->serialize_subset (c, glyphConstruction[i], this);
965
0
    }
966
0
    
967
0
    if (new_vert_coverage)
968
0
      out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
969
0
    
970
0
    if (new_hori_coverage)
971
0
    out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
972
0
    return_trace (true);
973
0
  }
974
975
  bool sanitize_offsets (hb_sanitize_context_t *c) const
976
5.18k
  {
977
5.18k
    TRACE_SANITIZE (this);
978
5.18k
    unsigned int count = vertGlyphCount + horizGlyphCount;
979
612k
    for (unsigned int i = 0; i < count; i++)
980
608k
      if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
981
5.18k
    return_trace (true);
982
5.18k
  }
983
984
  bool sanitize (hb_sanitize_context_t *c) const
985
6.80k
  {
986
6.80k
    TRACE_SANITIZE (this);
987
6.80k
    return_trace (c->check_struct (this) &&
988
6.80k
      vertGlyphCoverage.sanitize (c, this) &&
989
6.80k
      horizGlyphCoverage.sanitize (c, this) &&
990
6.80k
      c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
991
6.80k
      sanitize_offsets (c));
992
6.80k
  }
993
994
  hb_position_t get_min_connector_overlap (hb_direction_t direction,
995
              hb_font_t *font) const
996
406k
  { return font->em_scale_dir (minConnectorOverlap, direction); }
997
998
  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
1.21M
  { return get_glyph_construction (glyph, direction, font)
1005
1.21M
     .get_variants (direction, font, start_offset, variants_count, variants); }
1006
1007
  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
1.21M
  { return get_glyph_construction (glyph, direction, font)
1015
1.21M
     .get_assembly ()
1016
1.21M
     .get_parts (direction, font,
1017
1.21M
           start_offset, parts_count, parts,
1018
1.21M
           italics_correction); }
1019
1020
  private:
1021
  const MathGlyphConstruction &
1022
  get_glyph_construction (hb_codepoint_t glyph,
1023
        hb_direction_t direction,
1024
        hb_font_t *font HB_UNUSED) const
1025
2.43M
  {
1026
2.43M
    bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1027
2.43M
    unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1028
2.43M
    const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1029
2.43M
              : horizGlyphCoverage;
1030
1031
2.43M
    unsigned int index = (this+coverage).get_coverage (glyph);
1032
2.43M
    if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1033
1034
654
    if (!vertical)
1035
524
      index += vertGlyphCount;
1036
1037
654
    return this+glyphConstruction[index];
1038
2.43M
  }
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
1080
406k
  bool has_data () const { return version.to_int (); }
1081
1082
  void closure_glyphs (hb_set_t *glyph_set) const
1083
0
  {
1084
0
    if (mathVariants)
1085
0
    {
1086
0
      hb_set_t variant_glyphs;
1087
0
      (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1088
0
      hb_set_union (glyph_set, &variant_glyphs);
1089
0
    }
1090
0
  }
1091
1092
  bool subset (hb_subset_context_t *c) const
1093
0
  {
1094
0
    TRACE_SUBSET (this);
1095
0
    auto *out = c->serializer->embed (*this);
1096
0
    if (unlikely (!out)) return_trace (false);
1097
0
1098
0
    out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1099
0
    out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1100
0
    out->mathVariants.serialize_subset (c, mathVariants, this);
1101
0
    return_trace (true);
1102
0
  }
1103
1104
  bool sanitize (hb_sanitize_context_t *c) const
1105
16.0k
  {
1106
16.0k
    TRACE_SANITIZE (this);
1107
16.0k
    return_trace (version.sanitize (c) &&
1108
16.0k
      likely (version.major == 1) &&
1109
16.0k
      mathConstants.sanitize (c, this) &&
1110
16.0k
      mathGlyphInfo.sanitize (c, this) &&
1111
16.0k
      mathVariants.sanitize (c, this));
1112
16.0k
  }
1113
1114
  hb_position_t get_constant (hb_ot_math_constant_t  constant,
1115
            hb_font_t      *font) const
1116
22.7M
  { return (this+mathConstants).get_value (constant, font); }
1117
1118
2.43M
  const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1119
1120
2.84M
  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 */