Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-math-table.hh
Line
Count
Source
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
#include "hb-depend-data.hh"
34
35
namespace OT {
36
37
38
struct MathValueRecord
39
{
40
  hb_position_t get_x_value (hb_font_t *font, const void *base) const
41
0
  { return hb_saturate_add (font->em_scale_x (value), (base+deviceTable).get_x_delta (font)); }
42
  hb_position_t get_y_value (hb_font_t *font, const void *base) const
43
0
  { return hb_saturate_add (font->em_scale_y (value), (base+deviceTable).get_y_delta (font)); }
44
45
  MathValueRecord* copy (hb_serialize_context_t *c, const void *base) const
46
0
  {
47
0
    TRACE_SERIALIZE (this);
48
0
    auto *out = c->embed (this);
49
0
    if (unlikely (!out)) return_trace (nullptr);
50
0
    out->deviceTable.serialize_copy (c, deviceTable, base, 0, hb_serialize_context_t::Head);
51
52
0
    return_trace (out);
53
0
  }
54
55
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
56
0
  {
57
0
    TRACE_SANITIZE (this);
58
0
    return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
59
0
  }
60
61
  protected:
62
  HBINT16   value;    /* The X or Y value in design units */
63
  Offset16To<Device>  deviceTable;  /* Offset to the device table - from the
64
           * beginning of parent table.  May be NULL.
65
           * Suggested format for device table is 1. */
66
67
  public:
68
  DEFINE_SIZE_STATIC (4);
69
};
70
71
struct MathConstants
72
{
73
  friend struct MATH;
74
75
  MathConstants* copy (hb_serialize_context_t *c) const
76
0
  {
77
0
    TRACE_SERIALIZE (this);
78
0
    auto *out = c->start_embed (this);
79
80
0
    HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
81
0
    if (unlikely (!p)) return_trace (nullptr);
82
0
    hb_memcpy (p, percentScaleDown, HBINT16::static_size * 2);
83
84
0
    HBUINT16 *m = c->allocate_size<HBUINT16> (HBUINT16::static_size * 2);
85
0
    if (unlikely (!m)) return_trace (nullptr);
86
0
    hb_memcpy (m, minHeight, HBUINT16::static_size * 2);
87
88
0
    unsigned count = ARRAY_LENGTH (mathValueRecords);
89
0
    for (unsigned i = 0; i < count; i++)
90
0
      if (!c->copy (mathValueRecords[i], this))
91
0
        return_trace (nullptr);
92
93
0
    if (!c->embed (radicalDegreeBottomRaisePercent)) return_trace (nullptr);
94
0
    return_trace (out);
95
0
  }
96
97
  bool sanitize_math_value_records (hb_sanitize_context_t *c) const
98
0
  {
99
0
    TRACE_SANITIZE (this);
100
101
0
    unsigned int count = ARRAY_LENGTH (mathValueRecords);
102
0
    for (unsigned int i = 0; i < count; i++)
103
0
      if (!mathValueRecords[i].sanitize (c, this))
104
0
  return_trace (false);
105
106
0
    return_trace (true);
107
0
  }
108
109
  bool sanitize (hb_sanitize_context_t *c) const
110
0
  {
111
0
    TRACE_SANITIZE (this);
112
0
    return_trace (c->check_struct (this) && sanitize_math_value_records (c));
113
0
  }
114
115
  hb_position_t get_value (hb_ot_math_constant_t constant,
116
         hb_font_t *font) const
117
0
  {
118
0
    switch (constant) {
119
120
0
    case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
121
0
    case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
122
0
      return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
123
124
0
    case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
125
0
    case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
126
0
      return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
127
128
0
    case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
129
0
    case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
130
0
    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
131
0
    case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
132
0
      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value (font, this);
133
134
0
    case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
135
0
    case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
136
0
    case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
137
0
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
138
0
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
139
0
    case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
140
0
    case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
141
0
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
142
0
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
143
0
    case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
144
0
    case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
145
0
    case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
146
0
    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
147
0
    case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
148
0
    case HB_OT_MATH_CONSTANT_MATH_LEADING:
149
0
    case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
150
0
    case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
151
0
    case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
152
0
    case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
153
0
    case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
154
0
    case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
155
0
    case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
156
0
    case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
157
0
    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
158
0
    case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
159
0
    case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
160
0
    case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
161
0
    case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
162
0
    case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
163
0
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
164
0
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
165
0
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
166
0
    case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
167
0
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
168
0
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
169
0
    case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
170
0
    case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
171
0
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
172
0
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
173
0
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
174
0
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
175
0
    case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
176
0
    case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
177
0
    case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
178
0
    case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
179
0
    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
180
0
    case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
181
0
      return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value (font, this);
182
183
0
    case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
184
0
      return radicalDegreeBottomRaisePercent;
185
186
0
    default:
187
0
      return 0;
188
0
    }
189
0
  }
190
191
  protected:
192
  HBINT16 percentScaleDown[2];
193
  HBUINT16 minHeight[2];
194
  MathValueRecord mathValueRecords[51];
195
  HBINT16 radicalDegreeBottomRaisePercent;
196
197
  public:
198
  DEFINE_SIZE_STATIC (214);
199
};
200
201
struct MathItalicsCorrectionInfo
202
{
203
  bool subset (hb_subset_context_t *c) const
204
0
  {
205
0
    TRACE_SUBSET (this);
206
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
207
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
208
209
0
    auto *out = c->serializer->start_embed (*this);
210
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
211
212
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
213
0
    + hb_zip (this+coverage, italicsCorrection)
214
0
    | hb_filter (glyphset, hb_first)
215
0
    | hb_filter (serialize_math_record_array (c->serializer, out->italicsCorrection, this), hb_second)
216
0
    | hb_map (hb_first)
217
0
    | hb_map (glyph_map)
218
0
    | hb_sink (new_coverage)
219
0
    ;
220
221
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
222
0
    return_trace (true);
223
0
  }
224
225
  bool sanitize (hb_sanitize_context_t *c) const
226
0
  {
227
0
    TRACE_SANITIZE (this);
228
0
    return_trace (c->check_struct (this) &&
229
0
      coverage.sanitize (c, this) &&
230
0
      italicsCorrection.sanitize (c, this));
231
0
  }
232
233
  hb_position_t get_value (hb_codepoint_t glyph,
234
         hb_font_t *font) const
235
0
  {
236
0
    unsigned int index = (this+coverage).get_coverage (glyph);
237
0
    return italicsCorrection[index].get_x_value (font, this);
238
0
  }
239
240
  protected:
241
  Offset16To<Coverage>       coverage;    /* Offset to Coverage table -
242
             * from the beginning of
243
             * MathItalicsCorrectionInfo
244
             * table. */
245
  Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
246
             * defining italics correction
247
             * values for each
248
             * covered glyph. */
249
250
  public:
251
  DEFINE_SIZE_ARRAY (4, italicsCorrection);
252
};
253
254
struct MathTopAccentAttachment
255
{
256
  bool subset (hb_subset_context_t *c) const
257
0
  {
258
0
    TRACE_SUBSET (this);
259
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
260
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
261
262
0
    auto *out = c->serializer->start_embed (*this);
263
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
264
265
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
266
0
    + hb_zip (this+topAccentCoverage, topAccentAttachment)
267
0
    | hb_filter (glyphset, hb_first)
268
0
    | hb_filter (serialize_math_record_array (c->serializer, out->topAccentAttachment, this), hb_second)
269
0
    | hb_map (hb_first)
270
0
    | hb_map (glyph_map)
271
0
    | hb_sink (new_coverage)
272
0
    ;
273
274
0
    out->topAccentCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
275
0
    return_trace (true);
276
0
  }
277
278
  bool sanitize (hb_sanitize_context_t *c) const
279
0
  {
280
0
    TRACE_SANITIZE (this);
281
0
    return_trace (c->check_struct (this) &&
282
0
      topAccentCoverage.sanitize (c, this) &&
283
0
      topAccentAttachment.sanitize (c, this));
284
0
  }
285
286
  hb_position_t get_value (hb_codepoint_t glyph,
287
         hb_font_t *font) const
288
0
  {
289
0
    unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
290
0
    if (index == NOT_COVERED)
291
0
      return font->get_glyph_h_advance (glyph) / 2;
292
0
    return topAccentAttachment[index].get_x_value (font, this);
293
0
  }
294
295
  protected:
296
  Offset16To<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
297
             * from the beginning of
298
             * MathTopAccentAttachment
299
             * table. */
300
  Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
301
             * defining top accent
302
             * attachment points for each
303
             * covered glyph. */
304
305
  public:
306
  DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
307
};
308
309
struct MathKern
310
{
311
  MathKern* copy (hb_serialize_context_t *c) const
312
0
  {
313
0
    TRACE_SERIALIZE (this);
314
0
    auto *out = c->start_embed (this);
315
316
0
    if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
317
318
0
    unsigned count = 2 * heightCount + 1;
319
0
    for (unsigned i = 0; i < count; i++)
320
0
      if (!c->copy (mathValueRecordsZ.arrayZ[i], this))
321
0
        return_trace (nullptr);
322
323
0
    return_trace (out);
324
0
  }
325
326
  bool sanitize_math_value_records (hb_sanitize_context_t *c) const
327
0
  {
328
0
    TRACE_SANITIZE (this);
329
0
    unsigned int count = 2 * heightCount + 1;
330
0
    for (unsigned int i = 0; i < count; i++)
331
0
      if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
332
0
    return_trace (true);
333
0
  }
334
335
  bool sanitize (hb_sanitize_context_t *c) const
336
0
  {
337
0
    TRACE_SANITIZE (this);
338
0
    return_trace (c->check_struct (this) &&
339
0
      hb_barrier () &&
340
0
      c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
341
0
      sanitize_math_value_records (c));
342
0
  }
343
344
  hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
345
0
  {
346
0
    const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
347
0
    const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
348
0
    int sign = font->y_scale < 0 ? -1 : +1;
349
350
    /* According to OpenType spec (v1.9), except for the boundary cases, the index
351
     * chosen for kern value should be i such that
352
     *    correctionHeight[i-1] <= correction_height < correctionHeight[i]
353
     * We can use the binary search algorithm of std::upper_bound(). Or, we can
354
     * use the internal hb_bsearch_impl.
355
     */
356
0
    unsigned int pos;
357
0
    auto cmp = +[](const void* key, const void* p,
358
0
                   int sign, hb_font_t* font, const MathKern* mathKern) -> int {
359
0
      hb_position_t a = *(hb_position_t *) key;
360
0
      hb_position_t b = ((MathValueRecord *) p)->get_y_value (font, mathKern);
361
0
      if (a == b) return 0;
362
0
      return sign > 0 ? (a < b ? -1 : +1) : (b < a ? -1 : +1);
363
0
    };
364
0
    unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
365
0
                                     heightCount, MathValueRecord::static_size,
366
0
                                     cmp, sign, font, this) ? pos + 1 : pos;
367
0
    return kernValue[i].get_x_value (font, this);
368
0
  }
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
0
  {
375
0
    const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
376
0
    const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
377
0
    const unsigned int entriesCount = heightCount + 1;
378
379
0
    if (entries_count && kern_entries)
380
0
    {
381
0
      unsigned int start = hb_min (start_offset, entriesCount);
382
0
      unsigned int end = hb_min (start + *entries_count, entriesCount);
383
0
      *entries_count = end - start;
384
385
0
      for (unsigned int i = 0; i < *entries_count; i++) {
386
0
  unsigned int j = start + i;
387
388
0
  hb_position_t max_height;
389
0
  if (j == heightCount) {
390
0
    max_height = INT32_MAX;
391
0
  } else {
392
0
    max_height = correctionHeight[j].get_y_value (font, this);
393
0
  }
394
395
0
  kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)};
396
0
      }
397
0
    }
398
0
    return entriesCount;
399
0
  }
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
0
  {
422
0
    TRACE_SERIALIZE (this);
423
0
    auto *out = c->embed (this);
424
0
    if (unlikely (!out)) return_trace (nullptr);
425
426
0
    unsigned count = ARRAY_LENGTH (mathKern);
427
0
    for (unsigned i = 0; i < count; i++)
428
0
      out->mathKern[i].serialize_copy (c, mathKern[i], base, 0, hb_serialize_context_t::Head);
429
430
0
    return_trace (out);
431
0
  }
432
433
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
434
0
  {
435
0
    TRACE_SANITIZE (this);
436
437
0
    unsigned int count = ARRAY_LENGTH (mathKern);
438
0
    for (unsigned int i = 0; i < count; i++)
439
0
      if (unlikely (!mathKern[i].sanitize (c, base)))
440
0
  return_trace (false);
441
442
0
    return_trace (true);
443
0
  }
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
0
  {
450
0
    unsigned int idx = kern;
451
0
    if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
452
0
    return (base+mathKern[idx]).get_value (correction_height, font);
453
0
  }
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
0
  {
462
0
    unsigned int idx = kern;
463
0
    if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) {
464
0
      if (entries_count) *entries_count = 0;
465
0
      return 0;
466
0
    }
467
0
    return (base+mathKern[idx]).get_entries (start_offset,
468
0
               entries_count,
469
0
               kern_entries,
470
0
               font);
471
0
  }
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
0
  {
486
0
    TRACE_SUBSET (this);
487
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
488
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
489
490
0
    auto *out = c->serializer->start_embed (*this);
491
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
492
493
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
494
0
    + hb_zip (this+mathKernCoverage, mathKernInfoRecords)
495
0
    | hb_filter (glyphset, hb_first)
496
0
    | hb_filter (serialize_math_record_array (c->serializer, out->mathKernInfoRecords, this), hb_second)
497
0
    | hb_map (hb_first)
498
0
    | hb_map (glyph_map)
499
0
    | hb_sink (new_coverage)
500
0
    ;
501
502
0
    out->mathKernCoverage.serialize_serialize (c->serializer, new_coverage.iter ());
503
0
    return_trace (true);
504
0
  }
505
506
  bool sanitize (hb_sanitize_context_t *c) const
507
0
  {
508
0
    TRACE_SANITIZE (this);
509
0
    return_trace (c->check_struct (this) &&
510
0
      mathKernCoverage.sanitize (c, this) &&
511
0
      mathKernInfoRecords.sanitize (c, this));
512
0
  }
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
0
  {
519
0
    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
520
0
    return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
521
0
  }
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
0
  {
530
0
    unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
531
0
    return mathKernInfoRecords[index].get_kernings (kern,
532
0
                start_offset,
533
0
                entries_count,
534
0
                kern_entries,
535
0
                font,
536
0
                this);
537
0
  }
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
0
  {
561
0
    TRACE_SUBSET (this);
562
0
    auto *out = c->serializer->embed (*this);
563
0
    if (unlikely (!out)) return_trace (false);
564
565
0
    out->mathItalicsCorrectionInfo.serialize_subset (c, mathItalicsCorrectionInfo, this);
566
0
    out->mathTopAccentAttachment.serialize_subset (c, mathTopAccentAttachment, this);
567
568
0
    const hb_set_t &glyphset = c->plan->_glyphset_mathed;
569
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
570
571
0
    auto it =
572
0
    + hb_iter (this+extendedShapeCoverage)
573
0
    | hb_take (c->plan->source->get_num_glyphs ())
574
0
    | hb_filter (glyphset)
575
0
    | hb_map_retains_sorting (glyph_map)
576
0
    ;
577
578
0
    if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it);
579
0
    else out->extendedShapeCoverage = 0;
580
581
0
    out->mathKernInfo.serialize_subset (c, mathKernInfo, this);
582
0
    return_trace (true);
583
0
  }
584
585
  bool sanitize (hb_sanitize_context_t *c) const
586
0
  {
587
0
    TRACE_SANITIZE (this);
588
0
    return_trace (c->check_struct (this) &&
589
0
      mathItalicsCorrectionInfo.sanitize (c, this) &&
590
0
      mathTopAccentAttachment.sanitize (c, this) &&
591
0
      extendedShapeCoverage.sanitize (c, this) &&
592
0
      mathKernInfo.sanitize (c, this));
593
0
  }
594
595
  hb_position_t
596
  get_italics_correction (hb_codepoint_t  glyph, hb_font_t *font) const
597
0
  { 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
0
  { return (this+mathTopAccentAttachment).get_value (glyph, font); }
602
603
  bool is_extended_shape (hb_codepoint_t glyph) const
604
0
  { 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
0
  { 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
0
  { return (this+mathKernInfo).get_kernings (glyph,
619
0
               kern,
620
0
               start_offset,
621
0
               entries_count,
622
0
               kern_entries,
623
0
               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
0
  {
655
0
    TRACE_SUBSET (this);
656
0
    auto *out = c->serializer->embed (this);
657
0
    if (unlikely (!out)) return_trace (false);
658
659
0
    const hb_map_t& glyph_map = *c->plan->glyph_map;
660
0
    return_trace (c->serializer->check_assign (out->variantGlyph, glyph_map.get (variantGlyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
661
0
  }
662
663
  bool sanitize (hb_sanitize_context_t *c) const
664
0
  {
665
0
    TRACE_SANITIZE (this);
666
0
    return_trace (c->check_struct (this));
667
0
  }
668
669
  void depend (hb_depend_data_builder_t *depend_data, unsigned source) const
670
0
  { depend_data->add_depend(source, HB_OT_TAG_MATH, variantGlyph); }
671
672
  void closure_glyphs (hb_set_t *variant_glyphs) const
673
0
  { variant_glyphs->add (variantGlyph); }
674
675
  protected:
676
  HBGlyphID16 variantGlyph;       /* Glyph ID for the variant. */
677
  HBUINT16  advanceMeasurement; /* Advance width/height, in design units, of the
678
         * variant, in the direction of requested
679
         * glyph extension. */
680
681
  public:
682
  DEFINE_SIZE_STATIC (4);
683
};
684
685
struct PartFlags : HBUINT16
686
{
687
  enum Flags {
688
    Extender  = 0x0001u, /* If set, the part can be skipped or repeated. */
689
690
    Defined = 0x0001u, /* All defined flags. */
691
  };
692
693
  public:
694
  DEFINE_SIZE_STATIC (2);
695
};
696
697
struct MathGlyphPartRecord
698
{
699
  bool subset (hb_subset_context_t *c) const
700
0
  {
701
0
    TRACE_SUBSET (this);
702
0
    auto *out = c->serializer->embed (this);
703
0
    if (unlikely (!out)) return_trace (false);
704
705
0
    const hb_map_t& glyph_map = *c->plan->glyph_map;
706
0
    return_trace (c->serializer->check_assign (out->glyph, glyph_map.get (glyph), HB_SERIALIZE_ERROR_INT_OVERFLOW));
707
0
  }
708
709
  bool sanitize (hb_sanitize_context_t *c) const
710
0
  {
711
0
    TRACE_SANITIZE (this);
712
0
    return_trace (c->check_struct (this));
713
0
  }
714
715
  void extract (hb_ot_math_glyph_part_t &out,
716
    int64_t mult,
717
    hb_font_t *font) const
718
0
  {
719
0
    out.glyph     = glyph;
720
721
0
    out.start_connector_length  = font->em_mult (startConnectorLength, mult);
722
0
    out.end_connector_length  = font->em_mult (endConnectorLength, mult);
723
0
    out.full_advance    = font->em_mult (fullAdvance, mult);
724
725
0
    static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER ==
726
0
       (unsigned int) PartFlags::Extender, "");
727
728
0
    out.flags = (hb_ot_math_glyph_part_flags_t)
729
0
    (unsigned int)
730
0
    (partFlags & PartFlags::Defined);
731
0
  }
732
733
  void depend (hb_depend_data_builder_t *depend_data, unsigned source) const
734
0
  { depend_data->add_depend(source, HB_OT_TAG_MATH, glyph); }
735
736
  void closure_glyphs (hb_set_t *variant_glyphs) const
737
0
  { variant_glyphs->add (glyph); }
738
739
  protected:
740
  HBGlyphID16 glyph;    /* Glyph ID for the part. */
741
  HBUINT16  startConnectorLength;
742
        /* Advance width/ height of the straight bar
743
         * connector material, in design units, is at
744
         * the beginning of the glyph, in the
745
         * direction of the extension. */
746
  HBUINT16  endConnectorLength;
747
        /* Advance width/ height of the straight bar
748
         * connector material, in design units, is at
749
         * the end of the glyph, in the direction of
750
         * the extension. */
751
  HBUINT16  fullAdvance;  /* Full advance width/height for this part,
752
         * in the direction of the extension.
753
         * In design units. */
754
  PartFlags partFlags;  /* Part qualifiers. */
755
756
  public:
757
  DEFINE_SIZE_STATIC (10);
758
};
759
760
struct MathGlyphAssembly
761
{
762
  bool subset (hb_subset_context_t *c) const
763
0
  {
764
0
    TRACE_SUBSET (this);
765
766
0
    if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
767
0
    if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
768
769
0
    for (const auto& record : partRecords.iter ())
770
0
      if (!record.subset (c)) return_trace (false);
771
0
    return_trace (true);
772
0
  }
773
774
  bool sanitize (hb_sanitize_context_t *c) const
775
0
  {
776
0
    TRACE_SANITIZE (this);
777
0
    return_trace (c->check_struct (this) &&
778
0
      italicsCorrection.sanitize (c, this) &&
779
0
      partRecords.sanitize (c));
780
0
  }
781
782
  unsigned int get_parts (hb_direction_t direction,
783
        hb_font_t *font,
784
        unsigned int start_offset,
785
        unsigned int *parts_count, /* IN/OUT */
786
        hb_ot_math_glyph_part_t *parts /* OUT */,
787
        hb_position_t *italics_correction /* OUT */) const
788
0
  {
789
0
    if (parts_count && parts)
790
0
    {
791
0
      int64_t mult = font->dir_mult (direction);
792
0
      for (auto _ : hb_zip (partRecords.as_array ().sub_array (start_offset, parts_count),
793
0
          hb_array (parts, *parts_count)))
794
0
  _.first.extract (_.second, mult, font);
795
0
    }
796
797
0
    if (italics_correction)
798
0
      *italics_correction = italicsCorrection.get_x_value (font, this);
799
800
0
    return partRecords.len;
801
0
  }
802
803
  void depend (hb_depend_data_builder_t *depend_data, unsigned source) const
804
0
  {
805
0
    for (const auto& _ : partRecords.iter ())
806
0
      _.depend (depend_data, source);
807
0
  }
808
809
  void closure_glyphs (hb_set_t *variant_glyphs) const
810
0
  {
811
0
    for (const auto& _ : partRecords.iter ())
812
0
      _.closure_glyphs (variant_glyphs);
813
0
  }
814
815
  protected:
816
  MathValueRecord
817
    italicsCorrection;
818
        /* Italics correction of this
819
         * MathGlyphAssembly. Should not
820
         * depend on the assembly size. */
821
  Array16Of<MathGlyphPartRecord>
822
    partRecords;  /* Array of part records, from
823
         * left to right and bottom to
824
         * top. */
825
826
  public:
827
  DEFINE_SIZE_ARRAY (6, partRecords);
828
};
829
830
struct MathGlyphConstruction
831
{
832
  bool subset (hb_subset_context_t *c) const
833
0
  {
834
0
    TRACE_SUBSET (this);
835
0
    auto *out = c->serializer->start_embed (*this);
836
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
837
838
0
    out->glyphAssembly.serialize_subset (c, glyphAssembly, this);
839
840
0
    if (!c->serializer->check_assign (out->mathGlyphVariantRecord.len, mathGlyphVariantRecord.len, HB_SERIALIZE_ERROR_INT_OVERFLOW))
841
0
      return_trace (false);
842
0
    for (const auto& record : mathGlyphVariantRecord.iter ())
843
0
      if (!record.subset (c)) return_trace (false);
844
845
0
    return_trace (true);
846
0
  }
847
848
  bool sanitize (hb_sanitize_context_t *c) const
849
0
  {
850
0
    TRACE_SANITIZE (this);
851
0
    return_trace (c->check_struct (this) &&
852
0
      glyphAssembly.sanitize (c, this) &&
853
0
      mathGlyphVariantRecord.sanitize (c));
854
0
  }
855
856
0
  const MathGlyphAssembly &get_assembly () const { return this+glyphAssembly; }
857
858
  unsigned int get_variants (hb_direction_t direction,
859
           hb_font_t *font,
860
           unsigned int start_offset,
861
           unsigned int *variants_count, /* IN/OUT */
862
           hb_ot_math_glyph_variant_t *variants /* OUT */) const
863
0
  {
864
0
    if (variants_count && variants)
865
0
    {
866
0
      int64_t mult = font->dir_mult (direction);
867
0
      for (auto _ : hb_zip (mathGlyphVariantRecord.as_array ().sub_array (start_offset, variants_count),
868
0
          hb_array (variants, *variants_count)))
869
0
  _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)};
870
0
    }
871
0
    return mathGlyphVariantRecord.len;
872
0
  }
873
874
  void depend (hb_depend_data_builder_t *depend_data, unsigned source) const
875
0
  {
876
0
    (this+glyphAssembly).depend (depend_data, source);
877
0
878
0
    for (const auto& _ : mathGlyphVariantRecord.iter ())
879
0
      _.depend (depend_data, source);
880
0
  }
881
882
  void closure_glyphs (hb_set_t *variant_glyphs) const
883
0
  {
884
0
    (this+glyphAssembly).closure_glyphs (variant_glyphs);
885
886
0
    for (const auto& _ : mathGlyphVariantRecord.iter ())
887
0
      _.closure_glyphs (variant_glyphs);
888
0
  }
889
890
  protected:
891
  /* Offset to MathGlyphAssembly table for this shape - from the beginning of
892
     MathGlyphConstruction table.  May be NULL. */
893
  Offset16To<MathGlyphAssembly>   glyphAssembly;
894
895
  /* MathGlyphVariantRecords for alternative variants of the glyphs. */
896
  Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
897
898
  public:
899
  DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
900
};
901
902
struct MathVariants
903
{
904
  void depend (hb_depend_data_builder_t *depend_data) const
905
0
  {
906
0
    const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
907
0
908
0
    if (vertGlyphCoverage)
909
0
    {
910
0
      const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
911
0
      + hb_zip (this+vertGlyphCoverage, vert_offsets)
912
0
      | hb_apply ([&] (const hb_pair_t<hb_codepoint_t, const Offset16To<MathGlyphConstruction>&> &_)
913
0
                  {
914
0
                    const MathGlyphConstruction &mgc = this+_.second;
915
0
                    mgc.depend (depend_data, _.first);
916
0
                  })
917
0
      ;
918
0
    }
919
0
    if (horizGlyphCoverage)
920
0
    {
921
0
      const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
922
0
      + hb_zip (this+horizGlyphCoverage, hori_offsets)
923
0
      | hb_apply ([&] (const hb_pair_t<hb_codepoint_t, const Offset16To<MathGlyphConstruction>&> &_)
924
0
                  {
925
0
                    const MathGlyphConstruction &mgc = this+_.second;
926
0
                    mgc.depend (depend_data, _.first);
927
0
                  })
928
0
      ;
929
0
    }
930
0
  }
931
932
  void closure_glyphs (const hb_set_t *glyph_set,
933
                       hb_set_t *variant_glyphs) const
934
0
  {
935
0
    const hb_array_t<const Offset16To<MathGlyphConstruction>> glyph_construction_offsets = glyphConstruction.as_array (vertGlyphCount + horizGlyphCount);
936
937
0
    if (vertGlyphCoverage)
938
0
    {
939
0
      const auto vert_offsets = glyph_construction_offsets.sub_array (0, vertGlyphCount);
940
0
      + hb_zip (this+vertGlyphCoverage, vert_offsets)
941
0
      | hb_filter (glyph_set, hb_first)
942
0
      | hb_map (hb_second)
943
0
      | hb_map (hb_add (this))
944
0
      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
945
0
      ;
946
0
    }
947
948
0
    if (horizGlyphCoverage)
949
0
    {
950
0
      const auto hori_offsets = glyph_construction_offsets.sub_array (vertGlyphCount, horizGlyphCount);
951
0
      + hb_zip (this+horizGlyphCoverage, hori_offsets)
952
0
      | hb_filter (glyph_set, hb_first)
953
0
      | hb_map (hb_second)
954
0
      | hb_map (hb_add (this))
955
0
      | hb_apply ([=] (const MathGlyphConstruction &_) { _.closure_glyphs (variant_glyphs); })
956
0
      ;
957
0
    }
958
0
  }
959
960
  void collect_coverage_and_indices (hb_sorted_vector_t<hb_codepoint_t>& new_coverage,
961
                                     const Offset16To<Coverage>& coverage,
962
                                     unsigned i,
963
                                     unsigned end_index,
964
                                     hb_set_t& indices,
965
                                     const hb_set_t& glyphset,
966
                                     const hb_map_t& glyph_map) const
967
0
  {
968
0
    if (!coverage) return;
969
970
0
    for (const auto _ : (this+coverage).iter ())
971
0
    {
972
0
      if (i >= end_index) return;
973
0
      if (glyphset.has (_))
974
0
      {
975
0
        unsigned new_gid = glyph_map.get (_);
976
0
        new_coverage.push (new_gid);
977
0
        indices.add (i);
978
0
      }
979
0
      i++;
980
0
    }
981
0
  }
982
983
  bool subset (hb_subset_context_t *c) const
984
0
  {
985
0
    TRACE_SUBSET (this);
986
0
    const hb_set_t &glyphset = c->plan->_glyphset_cmaped;
987
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
988
989
0
    auto *out = c->serializer->start_embed (*this);
990
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
991
0
    if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
992
0
      return_trace (false);
993
994
0
    hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
995
0
    hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
996
0
    hb_set_t indices;
997
0
    collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
998
0
    collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
999
1000
0
    if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
1001
0
      return_trace (false);
1002
0
    if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
1003
0
      return_trace (false);
1004
1005
0
    for (unsigned i : indices.iter ())
1006
0
    {
1007
0
      auto *o = c->serializer->embed (glyphConstruction[i]);
1008
0
      if (!o) return_trace (false);
1009
0
      o->serialize_subset (c, glyphConstruction[i], this);
1010
0
    }
1011
1012
0
    if (new_vert_coverage)
1013
0
      out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
1014
1015
0
    if (new_hori_coverage)
1016
0
    out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
1017
0
    return_trace (true);
1018
0
  }
1019
1020
  bool sanitize_offsets (hb_sanitize_context_t *c) const
1021
0
  {
1022
0
    TRACE_SANITIZE (this);
1023
0
    unsigned int count = vertGlyphCount + horizGlyphCount;
1024
0
    for (unsigned int i = 0; i < count; i++)
1025
0
      if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
1026
0
    return_trace (true);
1027
0
  }
1028
1029
  bool sanitize (hb_sanitize_context_t *c) const
1030
0
  {
1031
0
    TRACE_SANITIZE (this);
1032
0
    return_trace (c->check_struct (this) &&
1033
0
      vertGlyphCoverage.sanitize (c, this) &&
1034
0
      horizGlyphCoverage.sanitize (c, this) &&
1035
0
      hb_barrier () &&
1036
0
      c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
1037
0
      sanitize_offsets (c));
1038
0
  }
1039
1040
  hb_position_t get_min_connector_overlap (hb_direction_t direction,
1041
              hb_font_t *font) const
1042
0
  { return font->em_scale_dir (minConnectorOverlap, direction); }
1043
1044
  unsigned int get_glyph_variants (hb_codepoint_t glyph,
1045
           hb_direction_t direction,
1046
           hb_font_t *font,
1047
           unsigned int start_offset,
1048
           unsigned int *variants_count, /* IN/OUT */
1049
           hb_ot_math_glyph_variant_t *variants /* OUT */) const
1050
0
  { return get_glyph_construction (glyph, direction, font)
1051
0
     .get_variants (direction, font, start_offset, variants_count, variants); }
1052
1053
  unsigned int get_glyph_parts (hb_codepoint_t glyph,
1054
        hb_direction_t direction,
1055
        hb_font_t *font,
1056
        unsigned int start_offset,
1057
        unsigned int *parts_count, /* IN/OUT */
1058
        hb_ot_math_glyph_part_t *parts /* OUT */,
1059
        hb_position_t *italics_correction /* OUT */) const
1060
0
  { return get_glyph_construction (glyph, direction, font)
1061
0
     .get_assembly ()
1062
0
     .get_parts (direction, font,
1063
0
           start_offset, parts_count, parts,
1064
0
           italics_correction); }
1065
1066
  private:
1067
  const MathGlyphConstruction &
1068
  get_glyph_construction (hb_codepoint_t glyph,
1069
        hb_direction_t direction,
1070
        hb_font_t *font HB_UNUSED) const
1071
0
  {
1072
0
    bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
1073
0
    unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
1074
0
    const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
1075
0
              : horizGlyphCoverage;
1076
1077
0
    unsigned int index = (this+coverage).get_coverage (glyph);
1078
0
    if (unlikely (index >= count)) return Null (MathGlyphConstruction);
1079
1080
0
    if (!vertical)
1081
0
      index += vertGlyphCount;
1082
1083
0
    return this+glyphConstruction[index];
1084
0
  }
1085
1086
  protected:
1087
  HBUINT16  minConnectorOverlap;
1088
        /* Minimum overlap of connecting
1089
         * glyphs during glyph construction,
1090
         * in design units. */
1091
  Offset16To<Coverage> vertGlyphCoverage;
1092
        /* Offset to Coverage table -
1093
         * from the beginning of MathVariants
1094
         * table. */
1095
  Offset16To<Coverage> horizGlyphCoverage;
1096
        /* Offset to Coverage table -
1097
         * from the beginning of MathVariants
1098
         * table. */
1099
  HBUINT16  vertGlyphCount; /* Number of glyphs for which
1100
         * information is provided for
1101
         * vertically growing variants. */
1102
  HBUINT16  horizGlyphCount;/* Number of glyphs for which
1103
         * information is provided for
1104
         * horizontally growing variants. */
1105
1106
  /* Array of offsets to MathGlyphConstruction tables - from the beginning of
1107
     the MathVariants table, for shapes growing in vertical/horizontal
1108
     direction. */
1109
  UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
1110
      glyphConstruction;
1111
1112
  public:
1113
  DEFINE_SIZE_ARRAY (10, glyphConstruction);
1114
};
1115
1116
1117
/*
1118
 * MATH -- Mathematical typesetting
1119
 * https://docs.microsoft.com/en-us/typography/opentype/spec/math
1120
 */
1121
1122
struct MATH
1123
{
1124
  static constexpr hb_tag_t tableTag = HB_OT_TAG_MATH;
1125
1126
0
  bool has_data () const { return version.to_int (); }
1127
1128
  void depend (hb_depend_data_builder_t *depend_data) const
1129
0
  {
1130
0
    if (mathVariants)
1131
0
      (this+mathVariants).depend (depend_data);
1132
0
  }
1133
1134
  void closure_glyphs (hb_set_t *glyph_set) const
1135
0
  {
1136
0
    if (mathVariants)
1137
0
    {
1138
0
      hb_set_t variant_glyphs;
1139
0
      (this+mathVariants).closure_glyphs (glyph_set, &variant_glyphs);
1140
0
      hb_set_union (glyph_set, &variant_glyphs);
1141
0
    }
1142
0
  }
1143
1144
  bool subset (hb_subset_context_t *c) const
1145
0
  {
1146
0
    TRACE_SUBSET (this);
1147
0
    auto *out = c->serializer->embed (*this);
1148
0
    if (unlikely (!out)) return_trace (false);
1149
1150
0
    out->mathConstants.serialize_copy (c->serializer, mathConstants, this, 0, hb_serialize_context_t::Head);
1151
0
    out->mathGlyphInfo.serialize_subset (c, mathGlyphInfo, this);
1152
0
    out->mathVariants.serialize_subset (c, mathVariants, this);
1153
0
    return_trace (true);
1154
0
  }
1155
1156
  bool sanitize (hb_sanitize_context_t *c) const
1157
0
  {
1158
0
    TRACE_SANITIZE (this);
1159
0
    return_trace (version.sanitize (c) &&
1160
0
      likely (version.major == 1) &&
1161
0
      hb_barrier () &&
1162
0
      mathConstants.sanitize (c, this) &&
1163
0
      mathGlyphInfo.sanitize (c, this) &&
1164
0
      mathVariants.sanitize (c, this));
1165
0
  }
1166
1167
  // https://github.com/harfbuzz/harfbuzz/issues/4653
1168
  HB_INTERNAL bool is_bad_cambria (hb_font_t *font) const
1169
0
  {
1170
0
#ifndef HB_NO_MATH
1171
0
    switch HB_CODEPOINT_ENCODE3 (font->face->table.MATH.get_blob ()->length,
1172
0
                                 (this+mathConstants).minHeight[1], // displayOperatorMinHeight
1173
                                 (this+mathConstants).minHeight[0]) // delimitedSubFormulaMinHeight
1174
0
    {
1175
      /* sha1sum:ab4a4fe054d23061f3c039493d6f665cfda2ecf5  cambria.ttc
1176
       * sha1sum:086855301bff644f9d8827b88491fcf73a6d4cb9  cambria.ttc
1177
       * sha1sum:b1e5a3feaca2ea3dfcf79ccb377de749ecf60343  cambria.ttc */
1178
0
      case HB_CODEPOINT_ENCODE3 (25722, 2500, 3000):
1179
0
        return true;
1180
0
    }
1181
0
#endif
1182
0
    return false;
1183
0
  }
1184
1185
  hb_position_t get_constant (hb_ot_math_constant_t  constant,
1186
            hb_font_t      *font) const
1187
0
  { return (this+mathConstants).get_value (constant, font); }
1188
1189
0
  const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; }
1190
1191
0
  const MathVariants &get_variants () const    { return this+mathVariants; }
1192
1193
  protected:
1194
  FixedVersion<>version;  /* Version of the MATH table
1195
         * initially set to 0x00010000u */
1196
  Offset16To<MathConstants>
1197
    mathConstants;  /* MathConstants table */
1198
  Offset16To<MathGlyphInfo>
1199
    mathGlyphInfo;  /* MathGlyphInfo table */
1200
  Offset16To<MathVariants>
1201
    mathVariants; /* MathVariants table */
1202
1203
  public:
1204
  DEFINE_SIZE_STATIC (10);
1205
};
1206
1207
} /* namespace OT */
1208
1209
1210
#endif /* HB_OT_MATH_TABLE_HH */