Coverage Report

Created: 2026-01-10 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
Line
Count
Source
1
/*
2
 * Copyright © 2007,2008,2009  Red Hat, Inc.
3
 * Copyright © 2010,2011,2012  Google, Inc.
4
 *
5
 *  This is part of HarfBuzz, a text shaping library.
6
 *
7
 * Permission is hereby granted, without written agreement and without
8
 * license or royalty fees, to use, copy, modify, and distribute this
9
 * software and its documentation for any purpose, provided that the
10
 * above copyright notice and the following two paragraphs appear in
11
 * all copies of this software.
12
 *
13
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
 * DAMAGE.
18
 *
19
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
 *
25
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
27
 */
28
29
#ifndef OT_LAYOUT_GDEF_GDEF_HH
30
#define OT_LAYOUT_GDEF_GDEF_HH
31
32
#include "../../../hb-ot-var-common.hh"
33
34
#include "../../../hb-font.hh"
35
#include "../../../hb-cache.hh"
36
37
38
namespace OT {
39
40
41
/*
42
 * Attachment List Table
43
 */
44
45
/* Array of contour point indices--in increasing numerical order */
46
struct AttachPoint : Array16Of<HBUINT16>
47
{
48
  bool subset (hb_subset_context_t *c) const
49
9
  {
50
9
    TRACE_SUBSET (this);
51
9
    auto *out = c->serializer->start_embed (*this);
52
9
    return_trace (out->serialize (c->serializer, + iter ()));
53
9
  }
54
};
55
56
struct AttachList
57
{
58
  unsigned int get_attach_points (hb_codepoint_t glyph_id,
59
          unsigned int start_offset,
60
          unsigned int *point_count /* IN/OUT */,
61
          unsigned int *point_array /* OUT */) const
62
0
  {
63
0
    unsigned int index = (this+coverage).get_coverage (glyph_id);
64
0
    if (index == NOT_COVERED)
65
0
    {
66
0
      if (point_count)
67
0
  *point_count = 0;
68
0
      return 0;
69
0
    }
70
71
0
    const AttachPoint &points = this+attachPoint[index];
72
73
0
    if (point_count)
74
0
    {
75
0
      + points.as_array ().sub_array (start_offset, point_count)
76
0
      | hb_sink (hb_array (point_array, *point_count))
77
0
      ;
78
0
    }
79
80
0
    return points.len;
81
0
  }
82
83
  bool subset (hb_subset_context_t *c) const
84
571
  {
85
571
    TRACE_SUBSET (this);
86
571
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
87
571
    const hb_map_t &glyph_map = *c->plan->glyph_map;
88
89
571
    auto *out = c->serializer->start_embed (*this);
90
571
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
91
92
571
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
93
571
    + hb_zip (this+coverage, attachPoint)
94
571
    | hb_filter (glyphset, hb_first)
95
571
    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
96
571
    | hb_map (hb_first)
97
571
    | hb_map (glyph_map)
98
571
    | hb_sink (new_coverage)
99
571
    ;
100
571
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
101
571
    return_trace (bool (new_coverage));
102
571
  }
103
104
  bool sanitize (hb_sanitize_context_t *c) const
105
664
  {
106
664
    TRACE_SANITIZE (this);
107
664
    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
108
664
  }
109
110
  protected:
111
  Offset16To<Coverage>
112
    coverage;   /* Offset to Coverage table -- from
113
           * beginning of AttachList table */
114
  Array16OfOffset16To<AttachPoint>
115
    attachPoint;    /* Array of AttachPoint tables
116
           * in Coverage Index order */
117
  public:
118
  DEFINE_SIZE_ARRAY (4, attachPoint);
119
};
120
121
/*
122
 * Ligature Caret Table
123
 */
124
125
struct CaretValueFormat1
126
{
127
  friend struct CaretValue;
128
  bool subset (hb_subset_context_t *c) const
129
3.93M
  {
130
3.93M
    TRACE_SUBSET (this);
131
3.93M
    auto *out = c->serializer->embed (this);
132
3.93M
    if (unlikely (!out)) return_trace (false);
133
3.93M
    return_trace (true);
134
3.93M
  }
135
136
  private:
137
  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
138
0
  {
139
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
140
0
  }
141
142
  bool sanitize (hb_sanitize_context_t *c) const
143
5.67M
  {
144
5.67M
    TRACE_SANITIZE (this);
145
5.67M
    return_trace (c->check_struct (this));
146
5.67M
  }
147
148
  protected:
149
  HBUINT16  caretValueFormat; /* Format identifier--format = 1 */
150
  FWORD   coordinate;   /* X or Y value, in design units */
151
  public:
152
  DEFINE_SIZE_STATIC (4);
153
};
154
155
struct CaretValueFormat2
156
{
157
  friend struct CaretValue;
158
  bool subset (hb_subset_context_t *c) const
159
2.29M
  {
160
2.29M
    TRACE_SUBSET (this);
161
2.29M
    auto *out = c->serializer->embed (this);
162
2.29M
    if (unlikely (!out)) return_trace (false);
163
2.29M
    return_trace (true);
164
2.29M
  }
165
166
  private:
167
  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
168
0
  {
169
0
    hb_position_t x, y;
170
0
    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
171
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
172
0
  }
173
174
  bool sanitize (hb_sanitize_context_t *c) const
175
2.69M
  {
176
2.69M
    TRACE_SANITIZE (this);
177
2.69M
    return_trace (c->check_struct (this));
178
2.69M
  }
179
180
  protected:
181
  HBUINT16  caretValueFormat; /* Format identifier--format = 2 */
182
  HBUINT16  caretValuePoint;  /* Contour point index on glyph */
183
  public:
184
  DEFINE_SIZE_STATIC (4);
185
};
186
187
struct CaretValueFormat3
188
{
189
  friend struct CaretValue;
190
191
  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
192
         const ItemVariationStore &var_store) const
193
0
  {
194
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
195
0
     font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
196
0
     font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
197
0
  }
198
199
  bool subset (hb_subset_context_t *c) const
200
788k
  {
201
788k
    TRACE_SUBSET (this);
202
788k
    auto *out = c->serializer->start_embed (*this);
203
788k
    if (!c->serializer->embed (caretValueFormat)) return_trace (false);
204
788k
    if (!c->serializer->embed (coordinate)) return_trace (false);
205
206
788k
    unsigned varidx = (this+deviceTable).get_variation_index ();
207
788k
    hb_pair_t<unsigned, int> *new_varidx_delta;
208
788k
    if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
209
0
      uint32_t new_varidx = hb_first (*new_varidx_delta);
210
0
      int delta = hb_second (*new_varidx_delta);
211
0
      if (delta != 0)
212
0
      {
213
0
        if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
214
0
          return_trace (false);
215
0
      }
216
217
0
      if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
218
0
        return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
219
0
    }
220
221
788k
    if (!c->serializer->embed (deviceTable))
222
2
      return_trace (false);
223
224
788k
    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
225
788k
               hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
226
788k
  }
227
228
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
229
0
  { (this+deviceTable).collect_variation_indices (c); }
230
231
  bool sanitize (hb_sanitize_context_t *c) const
232
1.10M
  {
233
1.10M
    TRACE_SANITIZE (this);
234
1.10M
    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
235
1.10M
  }
236
237
  protected:
238
  HBUINT16  caretValueFormat; /* Format identifier--format = 3 */
239
  FWORD   coordinate;   /* X or Y value, in design units */
240
  Offset16To<Device>
241
    deviceTable;    /* Offset to Device table for X or Y
242
           * value--from beginning of CaretValue
243
           * table */
244
  public:
245
  DEFINE_SIZE_STATIC (6);
246
};
247
248
struct CaretValue
249
{
250
  hb_position_t get_caret_value (hb_font_t *font,
251
         hb_direction_t direction,
252
         hb_codepoint_t glyph_id,
253
         const ItemVariationStore &var_store) const
254
0
  {
255
0
    switch (u.format.v) {
256
0
    case 1: return u.format1.get_caret_value (font, direction);
257
0
    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
258
0
    case 3: return u.format3.get_caret_value (font, direction, var_store);
259
0
    default:return 0;
260
0
    }
261
0
  }
262
263
  template <typename context_t, typename ...Ts>
264
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
265
106M
  {
266
106M
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
267
106M
    TRACE_DISPATCH (this, u.format.v);
268
106M
    switch (u.format.v) {
269
3.93M
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
270
2.29M
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
271
788k
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
272
99.7M
    default:return_trace (c->default_return_value ());
273
106M
    }
274
106M
  }
275
276
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
277
0
  {
278
0
    switch (u.format.v) {
279
0
    case 1:
280
0
    case 2:
281
0
      return;
282
0
    case 3:
283
0
      u.format3.collect_variation_indices (c);
284
0
      return;
285
0
    default: return;
286
0
    }
287
0
  }
288
289
  bool sanitize (hb_sanitize_context_t *c) const
290
138M
  {
291
138M
    TRACE_SANITIZE (this);
292
138M
    if (!u.format.v.sanitize (c)) return_trace (false);
293
138M
    hb_barrier ();
294
138M
    switch (u.format.v) {
295
5.67M
    case 1: return_trace (u.format1.sanitize (c));
296
2.69M
    case 2: return_trace (u.format2.sanitize (c));
297
1.10M
    case 3: return_trace (u.format3.sanitize (c));
298
128M
    default:return_trace (true);
299
138M
    }
300
138M
  }
301
302
  protected:
303
  union {
304
  struct { HBUINT16 v; }  format;   /* Format identifier */
305
  CaretValueFormat1 format1;
306
  CaretValueFormat2 format2;
307
  CaretValueFormat3 format3;
308
  } u;
309
  public:
310
  DEFINE_SIZE_UNION (2, format.v);
311
};
312
313
struct LigGlyph
314
{
315
  unsigned get_lig_carets (hb_font_t            *font,
316
         hb_direction_t        direction,
317
         hb_codepoint_t        glyph_id,
318
         const ItemVariationStore &var_store,
319
         unsigned              start_offset,
320
         unsigned             *caret_count /* IN/OUT */,
321
         hb_position_t        *caret_array /* OUT */) const
322
0
  {
323
0
    if (caret_count)
324
0
    {
325
0
      + carets.as_array ().sub_array (start_offset, caret_count)
326
0
      | hb_map (hb_add (this))
327
0
      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
328
0
      | hb_sink (hb_array (caret_array, *caret_count))
329
0
      ;
330
0
    }
331
332
0
    return carets.len;
333
0
  }
334
335
  bool subset (hb_subset_context_t *c) const
336
28.9k
  {
337
28.9k
    TRACE_SUBSET (this);
338
28.9k
    auto *out = c->serializer->start_embed (*this);
339
28.9k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
340
341
28.9k
    + hb_iter (carets)
342
28.9k
    | hb_apply (subset_offset_array (c, out->carets, this))
343
28.9k
    ;
344
345
28.9k
    return_trace (bool (out->carets));
346
28.9k
  }
347
348
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
349
0
  {
350
0
    for (const Offset16To<CaretValue>& offset : carets.iter ())
351
0
      (this+offset).collect_variation_indices (c);
352
0
  }
353
354
  bool sanitize (hb_sanitize_context_t *c) const
355
45.5k
  {
356
45.5k
    TRACE_SANITIZE (this);
357
45.5k
    return_trace (carets.sanitize (c, this));
358
45.5k
  }
359
360
  protected:
361
  Array16OfOffset16To<CaretValue>
362
    carets;     /* Offset array of CaretValue tables
363
           * --from beginning of LigGlyph table
364
           * --in increasing coordinate order */
365
  public:
366
  DEFINE_SIZE_ARRAY (2, carets);
367
};
368
369
struct LigCaretList
370
{
371
  unsigned int get_lig_carets (hb_font_t *font,
372
             hb_direction_t direction,
373
             hb_codepoint_t glyph_id,
374
             const ItemVariationStore &var_store,
375
             unsigned int start_offset,
376
             unsigned int *caret_count /* IN/OUT */,
377
             hb_position_t *caret_array /* OUT */) const
378
0
  {
379
0
    unsigned int index = (this+coverage).get_coverage (glyph_id);
380
0
    if (index == NOT_COVERED)
381
0
    {
382
0
      if (caret_count)
383
0
  *caret_count = 0;
384
0
      return 0;
385
0
    }
386
0
    const LigGlyph &lig_glyph = this+ligGlyph[index];
387
0
    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
388
0
  }
389
390
  bool subset (hb_subset_context_t *c) const
391
645
  {
392
645
    TRACE_SUBSET (this);
393
645
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
394
645
    const hb_map_t &glyph_map = *c->plan->glyph_map;
395
396
645
    auto *out = c->serializer->start_embed (*this);
397
645
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
398
399
643
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
400
643
    + hb_zip (this+coverage, ligGlyph)
401
643
    | hb_filter (glyphset, hb_first)
402
643
    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
403
643
    | hb_map (hb_first)
404
643
    | hb_map (glyph_map)
405
643
    | hb_sink (new_coverage)
406
643
    ;
407
643
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
408
643
    return_trace (bool (new_coverage));
409
645
  }
410
411
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
412
1.00k
  {
413
1.00k
    + hb_zip (this+coverage, ligGlyph)
414
1.00k
    | hb_filter (c->glyph_set, hb_first)
415
1.00k
    | hb_map (hb_second)
416
1.00k
    | hb_map (hb_add (this))
417
1.00k
    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
418
1.00k
    ;
419
1.00k
  }
420
421
  bool sanitize (hb_sanitize_context_t *c) const
422
724
  {
423
724
    TRACE_SANITIZE (this);
424
724
    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
425
724
  }
426
427
  protected:
428
  Offset16To<Coverage>
429
    coverage;   /* Offset to Coverage table--from
430
           * beginning of LigCaretList table */
431
  Array16OfOffset16To<LigGlyph>
432
    ligGlyph;   /* Array of LigGlyph tables
433
           * in Coverage Index order */
434
  public:
435
  DEFINE_SIZE_ARRAY (4, ligGlyph);
436
};
437
438
439
struct MarkGlyphSetsFormat1
440
{
441
  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
442
0
  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
443
444
  void collect_used_mark_sets (const hb_set_t& glyph_set,
445
                               hb_set_t& used_mark_sets /* OUT */) const
446
728
  {
447
728
    unsigned i = 0;
448
728
    for (const auto &offset : coverage)
449
3.10k
     {
450
3.10k
       const auto &cov = this+offset;
451
3.10k
       if (cov.intersects (&glyph_set))
452
812
         used_mark_sets.add (i);
453
454
3.10k
       i++;
455
3.10k
     }
456
728
  }
457
458
  template <typename set_t>
459
  void collect_coverage (hb_vector_t<set_t> &sets) const
460
0
  {
461
0
     for (const auto &offset : coverage)
462
0
     {
463
0
       const auto &cov = this+offset;
464
0
       cov.collect_coverage (sets.push ());
465
0
     }
466
0
  }
467
468
  bool subset (hb_subset_context_t *c) const
469
703
  {
470
703
    TRACE_SUBSET (this);
471
703
    auto *out = c->serializer->start_embed (*this);
472
703
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
473
697
    out->format = format;
474
475
697
    bool ret = true;
476
697
    for (const Offset32To<Coverage>& offset : coverage.iter ())
477
2.98k
    {
478
2.98k
      auto snap = c->serializer->snapshot ();
479
2.98k
      auto *o = out->coverage.serialize_append (c->serializer);
480
2.98k
      if (unlikely (!o))
481
0
      {
482
0
  ret = false;
483
0
  break;
484
0
      }
485
486
      //skip empty coverage
487
2.98k
      c->serializer->push ();
488
2.98k
      bool res = false;
489
2.98k
      if (offset) res = c->dispatch (this+offset);
490
2.98k
      if (!res)
491
2.20k
      {
492
2.20k
        c->serializer->pop_discard ();
493
2.20k
        c->serializer->revert (snap);
494
2.20k
        (out->coverage.len)--;
495
2.20k
        continue;
496
2.20k
      }
497
776
      c->serializer->add_link (*o, c->serializer->pop_pack ());
498
776
    }
499
500
697
    return_trace (ret && out->coverage.len);
501
703
  }
502
503
  bool sanitize (hb_sanitize_context_t *c) const
504
788
  {
505
788
    TRACE_SANITIZE (this);
506
788
    return_trace (coverage.sanitize (c, this));
507
788
  }
508
509
  protected:
510
  HBUINT16  format;     /* Format identifier--format = 1 */
511
  Array16Of<Offset32To<Coverage>>
512
    coverage;   /* Array of long offsets to mark set
513
           * coverage tables */
514
  public:
515
  DEFINE_SIZE_ARRAY (4, coverage);
516
};
517
518
struct MarkGlyphSets
519
{
520
  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
521
0
  {
522
0
    switch (u.format.v) {
523
0
    case 1: return u.format1.covers (set_index, glyph_id);
524
0
    default:return false;
525
0
    }
526
0
  }
527
528
  template <typename set_t>
529
  void collect_coverage (hb_vector_t<set_t> &sets) const
530
0
  {
531
0
    switch (u.format.v) {
532
0
    case 1: u.format1.collect_coverage (sets); return;
533
0
    default:return;
534
0
    }
535
0
  }
536
537
  void collect_used_mark_sets (const hb_set_t& glyph_set,
538
                               hb_set_t& used_mark_sets /* OUT */) const
539
763
  {
540
763
    switch (u.format.v) {
541
728
    case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
542
35
    default:return;
543
763
    }
544
763
  }
545
546
  bool subset (hb_subset_context_t *c) const
547
735
  {
548
735
    TRACE_SUBSET (this);
549
735
    switch (u.format.v) {
550
703
    case 1: return_trace (u.format1.subset (c));
551
32
    default:return_trace (false);
552
735
    }
553
735
  }
554
555
  bool sanitize (hb_sanitize_context_t *c) const
556
858
  {
557
858
    TRACE_SANITIZE (this);
558
858
    if (!u.format.v.sanitize (c)) return_trace (false);
559
834
    hb_barrier ();
560
834
    switch (u.format.v) {
561
788
    case 1: return_trace (u.format1.sanitize (c));
562
46
    default:return_trace (true);
563
834
    }
564
834
  }
565
566
  protected:
567
  union {
568
  struct { HBUINT16 v; }  format;   /* Format identifier */
569
  MarkGlyphSetsFormat1  format1;
570
  } u;
571
  public:
572
  DEFINE_SIZE_UNION (2, format.v);
573
};
574
575
576
/*
577
 * GDEF -- Glyph Definition
578
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
579
 */
580
581
582
template <typename Types>
583
struct GDEFVersion1_2
584
{
585
  friend struct GDEF;
586
587
  protected:
588
  FixedVersion<>version;    /* Version of the GDEF table--currently
589
           * 0x00010003u */
590
  typename Types::template OffsetTo<ClassDef>
591
    glyphClassDef;    /* Offset to class definition table
592
           * for glyph type--from beginning of
593
           * GDEF header (may be Null) */
594
  typename Types::template OffsetTo<AttachList>
595
    attachList;   /* Offset to list of glyphs with
596
           * attachment points--from beginning
597
           * of GDEF header (may be Null) */
598
  typename Types::template OffsetTo<LigCaretList>
599
    ligCaretList;   /* Offset to list of positioning points
600
           * for ligature carets--from beginning
601
           * of GDEF header (may be Null) */
602
  typename Types::template OffsetTo<ClassDef>
603
    markAttachClassDef; /* Offset to class definition table for
604
           * mark attachment type--from beginning
605
           * of GDEF header (may be Null) */
606
  typename Types::template OffsetTo<MarkGlyphSets>
607
    markGlyphSetsDef; /* Offset to the table of mark set
608
           * definitions--from beginning of GDEF
609
           * header (may be NULL).  Introduced
610
           * in version 0x00010002. */
611
  Offset32To<ItemVariationStore>
612
    varStore;   /* Offset to the table of Item Variation
613
           * Store--from beginning of GDEF
614
           * header (may be NULL).  Introduced
615
           * in version 0x00010003. */
616
  public:
617
  DEFINE_SIZE_MIN (4 + 4 * Types::size);
618
619
  unsigned int get_size () const
620
0
  {
621
0
    return min_size +
622
0
     (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
623
0
     (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
624
0
  }
Unexecuted instantiation: OT::GDEFVersion1_2<OT::Layout::SmallTypes>::get_size() const
Unexecuted instantiation: OT::GDEFVersion1_2<OT::Layout::MediumTypes>::get_size() const
625
626
  bool sanitize (hb_sanitize_context_t *c) const
627
3.81k
  {
628
3.81k
    TRACE_SANITIZE (this);
629
3.81k
    return_trace (version.sanitize (c) &&
630
3.81k
      glyphClassDef.sanitize (c, this) &&
631
3.81k
      attachList.sanitize (c, this) &&
632
3.81k
      ligCaretList.sanitize (c, this) &&
633
3.81k
      markAttachClassDef.sanitize (c, this) &&
634
3.81k
      hb_barrier () &&
635
3.81k
      ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
636
3.81k
      ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
637
3.81k
  }
OT::GDEFVersion1_2<OT::Layout::SmallTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
627
3.63k
  {
628
3.63k
    TRACE_SANITIZE (this);
629
3.63k
    return_trace (version.sanitize (c) &&
630
3.63k
      glyphClassDef.sanitize (c, this) &&
631
3.63k
      attachList.sanitize (c, this) &&
632
3.63k
      ligCaretList.sanitize (c, this) &&
633
3.63k
      markAttachClassDef.sanitize (c, this) &&
634
3.63k
      hb_barrier () &&
635
3.63k
      ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
636
3.63k
      ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
637
3.63k
  }
OT::GDEFVersion1_2<OT::Layout::MediumTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
627
179
  {
628
179
    TRACE_SANITIZE (this);
629
179
    return_trace (version.sanitize (c) &&
630
179
      glyphClassDef.sanitize (c, this) &&
631
179
      attachList.sanitize (c, this) &&
632
179
      ligCaretList.sanitize (c, this) &&
633
179
      markAttachClassDef.sanitize (c, this) &&
634
179
      hb_barrier () &&
635
179
      ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
636
179
      ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
637
179
  }
638
639
  static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
640
                                                hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
641
0
  {
642
    /* varidx_map is empty which means varstore is empty after instantiation,
643
     * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
644
     * varidx_map doesn't have original varidx, indicating delta row is all
645
     * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
646
0
    for (auto _ : layout_variation_idx_delta_map.iter_ref ())
647
0
    {
648
      /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
649
       * varidx is used as key of varidx_map during instantiation */
650
0
      uint32_t varidx = _.second.first;
651
0
      uint32_t *new_varidx;
652
0
      if (varidx_map.has (varidx, &new_varidx))
653
0
        _.second.first = *new_varidx;
654
0
      else
655
0
        _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
656
0
    }
657
0
  }
Unexecuted instantiation: OT::GDEFVersion1_2<OT::Layout::SmallTypes>::remap_varidx_after_instantiation(hb_map_t const&, hb_hashmap_t<unsigned int, hb_pair_t<unsigned int, int>, false>&)
Unexecuted instantiation: OT::GDEFVersion1_2<OT::Layout::MediumTypes>::remap_varidx_after_instantiation(hb_map_t const&, hb_hashmap_t<unsigned int, hb_pair_t<unsigned int, int>, false>&)
658
659
  bool subset (hb_subset_context_t *c) const
660
2.33k
  {
661
2.33k
    TRACE_SUBSET (this);
662
2.33k
    auto *out = c->serializer->start_embed (*this);
663
2.33k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
664
665
    // Push var store first (if it's needed) so that it's last in the
666
    // serialization order. Some font consumers assume that varstore runs to
667
    // the end of the GDEF table.
668
    // See: https://github.com/harfbuzz/harfbuzz/issues/4636
669
2.33k
    auto snapshot_version0 = c->serializer->snapshot ();
670
2.33k
    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
671
0
      return_trace (false);
672
673
2.33k
    bool subset_varstore = false;
674
2.33k
    unsigned varstore_index = (unsigned) -1;
675
2.33k
    auto snapshot_version2 = c->serializer->snapshot ();
676
2.33k
    if (version.to_int () >= 0x00010003u && hb_barrier ())
677
860
    {
678
860
      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
679
860
      if (c->plan->all_axes_pinned)
680
0
        out->varStore = 0;
681
860
      else if (c->plan->normalized_coords)
682
2
      {
683
2
        if (varStore)
684
0
        {
685
0
          item_variations_t item_vars;
686
0
          if (item_vars.instantiate (this+varStore, c->plan, true, true,
687
0
                                     c->plan->gdef_varstore_inner_maps.as_array ())) {
688
0
            subset_varstore = out->varStore.serialize_serialize (c->serializer,
689
0
                                                                 item_vars.has_long_word (),
690
0
                                                                 c->plan->axis_tags,
691
0
                                                                 item_vars.get_region_list (),
692
0
                                                                 item_vars.get_vardata_encodings ());
693
0
            varstore_index = c->serializer->last_added_child_index();
694
0
          }
695
0
          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
696
0
                                            c->plan->layout_variation_idx_delta_map);
697
0
        }
698
2
      }
699
858
      else
700
858
      {
701
858
        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
702
858
        varstore_index = c->serializer->last_added_child_index();
703
858
      }
704
860
    }
705
706
2.33k
    out->version.major = version.major;
707
2.33k
    out->version.minor = version.minor;
708
709
2.33k
    if (!subset_varstore && version.to_int () >= 0x00010002u) {
710
893
      c->serializer->revert (snapshot_version2);
711
893
    }
712
713
2.33k
    bool subset_markglyphsetsdef = false;
714
2.33k
    if (version.to_int () >= 0x00010002u && hb_barrier ())
715
1.09k
    {
716
1.09k
      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
717
1.09k
    }
718
719
2.33k
    if (subset_varstore)
720
202
    {
721
202
      out->version.minor = 3;
722
202
      c->plan->has_gdef_varstore = true;
723
2.13k
    } else if (subset_markglyphsetsdef) {
724
66
      out->version.minor = 2;      
725
2.07k
    } else  {
726
2.07k
      out->version.minor = 0;
727
2.07k
      c->serializer->revert (snapshot_version0);
728
2.07k
    }
729
730
2.33k
    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
731
2.33k
    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
732
2.33k
    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
733
2.33k
    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
734
735
2.33k
    if (subset_varstore && varstore_index != (unsigned) -1) {
736
202
      c->serializer->repack_last(varstore_index);
737
202
    }
738
739
2.33k
    return_trace (subset_glyphclassdef || subset_attachlist ||
740
2.33k
      subset_ligcaretlist || subset_markattachclassdef ||
741
2.33k
      (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
742
2.33k
      (out->version.to_int () >= 0x00010003u && subset_varstore));
743
2.33k
  }
OT::GDEFVersion1_2<OT::Layout::SmallTypes>::subset(hb_subset_context_t*) const
Line
Count
Source
660
2.32k
  {
661
2.32k
    TRACE_SUBSET (this);
662
2.32k
    auto *out = c->serializer->start_embed (*this);
663
2.32k
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
664
665
    // Push var store first (if it's needed) so that it's last in the
666
    // serialization order. Some font consumers assume that varstore runs to
667
    // the end of the GDEF table.
668
    // See: https://github.com/harfbuzz/harfbuzz/issues/4636
669
2.32k
    auto snapshot_version0 = c->serializer->snapshot ();
670
2.32k
    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
671
0
      return_trace (false);
672
673
2.32k
    bool subset_varstore = false;
674
2.32k
    unsigned varstore_index = (unsigned) -1;
675
2.32k
    auto snapshot_version2 = c->serializer->snapshot ();
676
2.32k
    if (version.to_int () >= 0x00010003u && hb_barrier ())
677
843
    {
678
843
      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
679
843
      if (c->plan->all_axes_pinned)
680
0
        out->varStore = 0;
681
843
      else if (c->plan->normalized_coords)
682
1
      {
683
1
        if (varStore)
684
0
        {
685
0
          item_variations_t item_vars;
686
0
          if (item_vars.instantiate (this+varStore, c->plan, true, true,
687
0
                                     c->plan->gdef_varstore_inner_maps.as_array ())) {
688
0
            subset_varstore = out->varStore.serialize_serialize (c->serializer,
689
0
                                                                 item_vars.has_long_word (),
690
0
                                                                 c->plan->axis_tags,
691
0
                                                                 item_vars.get_region_list (),
692
0
                                                                 item_vars.get_vardata_encodings ());
693
0
            varstore_index = c->serializer->last_added_child_index();
694
0
          }
695
0
          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
696
0
                                            c->plan->layout_variation_idx_delta_map);
697
0
        }
698
1
      }
699
842
      else
700
842
      {
701
842
        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
702
842
        varstore_index = c->serializer->last_added_child_index();
703
842
      }
704
843
    }
705
706
2.32k
    out->version.major = version.major;
707
2.32k
    out->version.minor = version.minor;
708
709
2.32k
    if (!subset_varstore && version.to_int () >= 0x00010002u) {
710
876
      c->serializer->revert (snapshot_version2);
711
876
    }
712
713
2.32k
    bool subset_markglyphsetsdef = false;
714
2.32k
    if (version.to_int () >= 0x00010002u && hb_barrier ())
715
1.07k
    {
716
1.07k
      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
717
1.07k
    }
718
719
2.32k
    if (subset_varstore)
720
202
    {
721
202
      out->version.minor = 3;
722
202
      c->plan->has_gdef_varstore = true;
723
2.11k
    } else if (subset_markglyphsetsdef) {
724
66
      out->version.minor = 2;      
725
2.05k
    } else  {
726
2.05k
      out->version.minor = 0;
727
2.05k
      c->serializer->revert (snapshot_version0);
728
2.05k
    }
729
730
2.32k
    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
731
2.32k
    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
732
2.32k
    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
733
2.32k
    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
734
735
2.32k
    if (subset_varstore && varstore_index != (unsigned) -1) {
736
202
      c->serializer->repack_last(varstore_index);
737
202
    }
738
739
2.32k
    return_trace (subset_glyphclassdef || subset_attachlist ||
740
2.32k
      subset_ligcaretlist || subset_markattachclassdef ||
741
2.32k
      (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
742
2.32k
      (out->version.to_int () >= 0x00010003u && subset_varstore));
743
2.32k
  }
OT::GDEFVersion1_2<OT::Layout::MediumTypes>::subset(hb_subset_context_t*) const
Line
Count
Source
660
17
  {
661
17
    TRACE_SUBSET (this);
662
17
    auto *out = c->serializer->start_embed (*this);
663
17
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
664
665
    // Push var store first (if it's needed) so that it's last in the
666
    // serialization order. Some font consumers assume that varstore runs to
667
    // the end of the GDEF table.
668
    // See: https://github.com/harfbuzz/harfbuzz/issues/4636
669
17
    auto snapshot_version0 = c->serializer->snapshot ();
670
17
    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
671
0
      return_trace (false);
672
673
17
    bool subset_varstore = false;
674
17
    unsigned varstore_index = (unsigned) -1;
675
17
    auto snapshot_version2 = c->serializer->snapshot ();
676
17
    if (version.to_int () >= 0x00010003u && hb_barrier ())
677
17
    {
678
17
      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
679
17
      if (c->plan->all_axes_pinned)
680
0
        out->varStore = 0;
681
17
      else if (c->plan->normalized_coords)
682
1
      {
683
1
        if (varStore)
684
0
        {
685
0
          item_variations_t item_vars;
686
0
          if (item_vars.instantiate (this+varStore, c->plan, true, true,
687
0
                                     c->plan->gdef_varstore_inner_maps.as_array ())) {
688
0
            subset_varstore = out->varStore.serialize_serialize (c->serializer,
689
0
                                                                 item_vars.has_long_word (),
690
0
                                                                 c->plan->axis_tags,
691
0
                                                                 item_vars.get_region_list (),
692
0
                                                                 item_vars.get_vardata_encodings ());
693
0
            varstore_index = c->serializer->last_added_child_index();
694
0
          }
695
0
          remap_varidx_after_instantiation (item_vars.get_varidx_map (),
696
0
                                            c->plan->layout_variation_idx_delta_map);
697
0
        }
698
1
      }
699
16
      else
700
16
      {
701
16
        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
702
16
        varstore_index = c->serializer->last_added_child_index();
703
16
      }
704
17
    }
705
706
17
    out->version.major = version.major;
707
17
    out->version.minor = version.minor;
708
709
17
    if (!subset_varstore && version.to_int () >= 0x00010002u) {
710
17
      c->serializer->revert (snapshot_version2);
711
17
    }
712
713
17
    bool subset_markglyphsetsdef = false;
714
17
    if (version.to_int () >= 0x00010002u && hb_barrier ())
715
17
    {
716
17
      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
717
17
    }
718
719
17
    if (subset_varstore)
720
0
    {
721
0
      out->version.minor = 3;
722
0
      c->plan->has_gdef_varstore = true;
723
17
    } else if (subset_markglyphsetsdef) {
724
0
      out->version.minor = 2;      
725
17
    } else  {
726
17
      out->version.minor = 0;
727
17
      c->serializer->revert (snapshot_version0);
728
17
    }
729
730
17
    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
731
17
    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
732
17
    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
733
17
    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
734
735
17
    if (subset_varstore && varstore_index != (unsigned) -1) {
736
0
      c->serializer->repack_last(varstore_index);
737
0
    }
738
739
17
    return_trace (subset_glyphclassdef || subset_attachlist ||
740
17
      subset_ligcaretlist || subset_markattachclassdef ||
741
17
      (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
742
17
      (out->version.to_int () >= 0x00010003u && subset_varstore));
743
17
  }
744
};
745
746
struct GDEF
747
{
748
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
749
750
  enum GlyphClasses {
751
    UnclassifiedGlyph = 0,
752
    BaseGlyph   = 1,
753
    LigatureGlyph = 2,
754
    MarkGlyph   = 3,
755
    ComponentGlyph  = 4
756
  };
757
758
  unsigned int get_size () const
759
0
  {
760
0
    switch (u.version.major) {
761
0
    case 1: return u.version1.get_size ();
762
0
#ifndef HB_NO_BEYOND_64K
763
0
    case 2: return u.version2.get_size ();
764
0
#endif
765
0
    default: return u.version.static_size;
766
0
    }
767
0
  }
768
769
  bool sanitize (hb_sanitize_context_t *c) const
770
7.00k
  {
771
7.00k
    TRACE_SANITIZE (this);
772
7.00k
    if (unlikely (!u.version.sanitize (c))) return_trace (false);
773
7.00k
    hb_barrier ();
774
7.00k
    switch (u.version.major) {
775
3.63k
    case 1: return_trace (u.version1.sanitize (c));
776
0
#ifndef HB_NO_BEYOND_64K
777
179
    case 2: return_trace (u.version2.sanitize (c));
778
0
#endif
779
3.18k
    default: return_trace (true);
780
7.00k
    }
781
7.00k
  }
782
783
  bool subset (hb_subset_context_t *c) const
784
5.32k
  {
785
5.32k
    switch (u.version.major) {
786
2.32k
    case 1: return u.version1.subset (c);
787
0
#ifndef HB_NO_BEYOND_64K
788
17
    case 2: return u.version2.subset (c);
789
0
#endif
790
2.98k
    default: return false;
791
5.32k
    }
792
5.32k
  }
793
794
  bool has_glyph_classes () const
795
0
  {
796
0
    switch (u.version.major) {
797
0
    case 1: return u.version1.glyphClassDef != 0;
798
0
#ifndef HB_NO_BEYOND_64K
799
0
    case 2: return u.version2.glyphClassDef != 0;
800
0
#endif
801
0
    default: return false;
802
0
    }
803
0
  }
804
  const ClassDef &get_glyph_class_def () const
805
0
  {
806
0
    switch (u.version.major) {
807
0
    case 1: return this+u.version1.glyphClassDef;
808
0
#ifndef HB_NO_BEYOND_64K
809
0
    case 2: return this+u.version2.glyphClassDef;
810
0
#endif
811
0
    default: return Null(ClassDef);
812
0
    }
813
0
  }
814
  bool has_attach_list () const
815
0
  {
816
0
    switch (u.version.major) {
817
0
    case 1: return u.version1.attachList != 0;
818
0
#ifndef HB_NO_BEYOND_64K
819
0
    case 2: return u.version2.attachList != 0;
820
0
#endif
821
0
    default: return false;
822
0
    }
823
0
  }
824
  const AttachList &get_attach_list () const
825
0
  {
826
0
    switch (u.version.major) {
827
0
    case 1: return this+u.version1.attachList;
828
0
#ifndef HB_NO_BEYOND_64K
829
0
    case 2: return this+u.version2.attachList;
830
0
#endif
831
0
    default: return Null(AttachList);
832
0
    }
833
0
  }
834
  bool has_lig_carets () const
835
0
  {
836
0
    switch (u.version.major) {
837
0
    case 1: return u.version1.ligCaretList != 0;
838
0
#ifndef HB_NO_BEYOND_64K
839
0
    case 2: return u.version2.ligCaretList != 0;
840
0
#endif
841
0
    default: return false;
842
0
    }
843
0
  }
844
  const LigCaretList &get_lig_caret_list () const
845
1.00k
  {
846
1.00k
    switch (u.version.major) {
847
999
    case 1: return this+u.version1.ligCaretList;
848
0
#ifndef HB_NO_BEYOND_64K
849
3
    case 2: return this+u.version2.ligCaretList;
850
0
#endif
851
0
    default: return Null(LigCaretList);
852
1.00k
    }
853
1.00k
  }
854
  bool has_mark_attachment_types () const
855
0
  {
856
0
    switch (u.version.major) {
857
0
    case 1: return u.version1.markAttachClassDef != 0;
858
0
#ifndef HB_NO_BEYOND_64K
859
0
    case 2: return u.version2.markAttachClassDef != 0;
860
0
#endif
861
0
    default: return false;
862
0
    }
863
0
  }
864
  const ClassDef &get_mark_attach_class_def () const
865
0
  {
866
0
    switch (u.version.major) {
867
0
    case 1: return this+u.version1.markAttachClassDef;
868
0
#ifndef HB_NO_BEYOND_64K
869
0
    case 2: return this+u.version2.markAttachClassDef;
870
0
#endif
871
0
    default: return Null(ClassDef);
872
0
    }
873
0
  }
874
  bool has_mark_glyph_sets () const
875
5.25k
  {
876
5.25k
    switch (u.version.major) {
877
2.31k
    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
878
0
#ifndef HB_NO_BEYOND_64K
879
19
    case 2: return u.version2.markGlyphSetsDef != 0;
880
0
#endif
881
2.92k
    default: return false;
882
5.25k
    }
883
5.25k
  }
884
  const MarkGlyphSets &get_mark_glyph_sets () const
885
763
  {
886
763
    switch (u.version.major) {
887
756
    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
888
0
#ifndef HB_NO_BEYOND_64K
889
7
    case 2: return this+u.version2.markGlyphSetsDef;
890
0
#endif
891
0
    default: return Null(MarkGlyphSets);
892
763
    }
893
763
  }
894
  bool has_var_store () const
895
5.30k
  {
896
5.30k
    switch (u.version.major) {
897
2.34k
    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
898
0
#ifndef HB_NO_BEYOND_64K
899
19
    case 2: return u.version2.varStore != 0;
900
0
#endif
901
2.94k
    default: return false;
902
5.30k
    }
903
5.30k
  }
904
  const ItemVariationStore &get_var_store () const
905
2.00k
  {
906
2.00k
    switch (u.version.major) {
907
1.99k
    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
908
0
#ifndef HB_NO_BEYOND_64K
909
6
    case 2: return this+u.version2.varStore;
910
0
#endif
911
0
    default: return Null(ItemVariationStore);
912
2.00k
    }
913
2.00k
  }
914
915
916
48.6k
  bool has_data () const { return u.version.to_int (); }
917
  unsigned int get_glyph_class (hb_codepoint_t glyph) const
918
0
  { return get_glyph_class_def ().get_class (glyph); }
919
  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
920
0
  { get_glyph_class_def ().collect_class (glyphs, klass); }
921
922
  unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
923
0
  { return get_mark_attach_class_def ().get_class (glyph); }
924
925
  unsigned int get_attach_points (hb_codepoint_t glyph_id,
926
          unsigned int start_offset,
927
          unsigned int *point_count /* IN/OUT */,
928
          unsigned int *point_array /* OUT */) const
929
0
  { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
930
931
  unsigned int get_lig_carets (hb_font_t *font,
932
             hb_direction_t direction,
933
             hb_codepoint_t glyph_id,
934
             unsigned int start_offset,
935
             unsigned int *caret_count /* IN/OUT */,
936
             hb_position_t *caret_array /* OUT */) const
937
0
  { return get_lig_caret_list ().get_lig_carets (font,
938
0
             direction, glyph_id, get_var_store(),
939
0
             start_offset, caret_count, caret_array); }
940
941
  bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
942
0
  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
943
944
  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
945
   * glyph class and other bits, and high 8-bit the mark attachment type (if any).
946
   * Not to be confused with lookup_props which is very similar. */
947
  unsigned int get_glyph_props (hb_codepoint_t glyph) const
948
0
  {
949
0
    unsigned int klass = get_glyph_class (glyph);
950
951
0
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
952
0
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
953
0
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
954
955
0
    switch (klass) {
956
0
    default:      return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
957
0
    case BaseGlyph:   return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
958
0
    case LigatureGlyph:   return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
959
0
    case MarkGlyph:
960
0
    klass = get_mark_attachment_type (glyph);
961
0
    return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
962
0
    }
963
0
  }
964
965
  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
966
           hb_face_t *face) const;
967
968
  struct accelerator_t
969
  {
970
    accelerator_t (hb_face_t *face)
971
0
    {
972
0
      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
973
0
      if (unlikely (table->is_blocklisted (table.get_blob (), face)))
974
0
      {
975
0
  hb_blob_destroy (table.get_blob ());
976
0
  table = hb_blob_get_empty ();
977
0
      }
978
979
0
#ifndef HB_NO_GDEF_CACHE
980
0
      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
981
0
#endif
982
0
    }
983
0
    ~accelerator_t () { table.destroy (); }
984
985
    unsigned int get_glyph_props (hb_codepoint_t glyph) const
986
0
    {
987
0
      unsigned v;
988
989
0
#ifndef HB_NO_GDEF_CACHE
990
0
      if (glyph_props_cache.get (glyph, &v))
991
0
        return v;
992
0
#endif
993
994
0
      v = table->get_glyph_props (glyph);
995
996
0
#ifndef HB_NO_GDEF_CACHE
997
0
      if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
998
0
  glyph_props_cache.set (glyph, v);
999
0
#endif
1000
1001
0
      return v;
1002
1003
0
    }
1004
1005
    HB_ALWAYS_INLINE
1006
    bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
1007
0
    {
1008
0
      return
1009
0
#ifndef HB_NO_GDEF_CACHE
1010
       // We can access arrayZ directly because of sanitize_lookup_props() guarantee.
1011
0
       mark_glyph_sets.arrayZ[set_index].may_have (glyph_id) &&
1012
0
#endif
1013
0
       table->mark_set_covers (set_index, glyph_id)
1014
0
      ;
1015
0
    }
1016
1017
    unsigned sanitize_lookup_props (unsigned lookup_props) const
1018
0
    {
1019
0
#ifndef HB_NO_GDEF_CACHE
1020
0
      if (lookup_props & LookupFlag::UseMarkFilteringSet &&
1021
0
    (lookup_props >> 16) >= mark_glyph_sets.length)
1022
0
      {
1023
        // Invalid mark filtering set index; unset the flag.
1024
0
  lookup_props &= ~LookupFlag::UseMarkFilteringSet;
1025
0
      }
1026
0
#endif
1027
0
      return lookup_props;
1028
0
    }
1029
1030
    hb_blob_ptr_t<GDEF> table;
1031
#ifndef HB_NO_GDEF_CACHE
1032
    hb_vector_t<hb_set_digest_t> mark_glyph_sets;
1033
    mutable hb_cache_t<21, 3> glyph_props_cache;
1034
    static_assert (sizeof (glyph_props_cache) == 512, "");
1035
#endif
1036
  };
1037
1038
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
1039
1.00k
  { get_lig_caret_list ().collect_variation_indices (c); }
1040
1041
  protected:
1042
  union {
1043
  FixedVersion<>    version;  /* Version identifier */
1044
  GDEFVersion1_2<SmallTypes>  version1;
1045
#ifndef HB_NO_BEYOND_64K
1046
  GDEFVersion1_2<MediumTypes> version2;
1047
#endif
1048
  } u;
1049
  public:
1050
  DEFINE_SIZE_MIN (4);
1051
};
1052
1053
struct GDEF_accelerator_t : GDEF::accelerator_t {
1054
0
  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
1055
};
1056
1057
} /* namespace OT */
1058
1059
1060
#endif /* OT_LAYOUT_GDEF_GDEF_HH */