Coverage Report

Created: 2026-11-06 11:29

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