Coverage Report

Created: 2025-08-29 06:20

/src/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
Line
Count
Source (jump to first uncovered line)
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
0
  {
50
0
    TRACE_SUBSET (this);
51
0
    auto *out = c->serializer->start_embed (*this);
52
0
    return_trace (out->serialize (c->serializer, + iter ()));
53
0
  }
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
0
  {
85
0
    TRACE_SUBSET (this);
86
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
87
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
88
0
89
0
    auto *out = c->serializer->start_embed (*this);
90
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
91
0
92
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
93
0
    + hb_zip (this+coverage, attachPoint)
94
0
    | hb_filter (glyphset, hb_first)
95
0
    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
96
0
    | hb_map (hb_first)
97
0
    | hb_map (glyph_map)
98
0
    | hb_sink (new_coverage)
99
0
    ;
100
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
101
0
    return_trace (bool (new_coverage));
102
0
  }
103
104
  bool sanitize (hb_sanitize_context_t *c) const
105
0
  {
106
0
    TRACE_SANITIZE (this);
107
0
    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
108
0
  }
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
0
  {
130
0
    TRACE_SUBSET (this);
131
0
    auto *out = c->serializer->embed (this);
132
0
    if (unlikely (!out)) return_trace (false);
133
0
    return_trace (true);
134
0
  }
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
0
  {
144
0
    TRACE_SANITIZE (this);
145
0
    return_trace (c->check_struct (this));
146
0
  }
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
0
  {
160
0
    TRACE_SUBSET (this);
161
0
    auto *out = c->serializer->embed (this);
162
0
    if (unlikely (!out)) return_trace (false);
163
0
    return_trace (true);
164
0
  }
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
0
  {
176
0
    TRACE_SANITIZE (this);
177
0
    return_trace (c->check_struct (this));
178
0
  }
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
0
  {
201
0
    TRACE_SUBSET (this);
202
0
    auto *out = c->serializer->start_embed (*this);
203
0
    if (!c->serializer->embed (caretValueFormat)) return_trace (false);
204
0
    if (!c->serializer->embed (coordinate)) return_trace (false);
205
0
206
0
    unsigned varidx = (this+deviceTable).get_variation_index ();
207
0
    hb_pair_t<unsigned, int> *new_varidx_delta;
208
0
    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
0
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
0
221
0
    if (!c->serializer->embed (deviceTable))
222
0
      return_trace (false);
223
0
224
0
    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
225
0
               hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
226
0
  }
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
0
  {
233
0
    TRACE_SANITIZE (this);
234
0
    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
235
0
  }
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) {
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
0
  {
266
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
267
0
    TRACE_DISPATCH (this, u.format);
268
0
    switch (u.format) {
269
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
270
0
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
271
0
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
272
0
    default:return_trace (c->default_return_value ());
273
0
    }
274
0
  }
275
276
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
277
0
  {
278
0
    switch (u.format) {
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
0
  {
291
0
    TRACE_SANITIZE (this);
292
0
    if (!u.format.sanitize (c)) return_trace (false);
293
0
    hb_barrier ();
294
0
    switch (u.format) {
295
0
    case 1: return_trace (u.format1.sanitize (c));
296
0
    case 2: return_trace (u.format2.sanitize (c));
297
0
    case 3: return_trace (u.format3.sanitize (c));
298
0
    default:return_trace (true);
299
0
    }
300
0
  }
301
302
  protected:
303
  union {
304
  HBUINT16    format;   /* Format identifier */
305
  CaretValueFormat1 format1;
306
  CaretValueFormat2 format2;
307
  CaretValueFormat3 format3;
308
  } u;
309
  public:
310
  DEFINE_SIZE_UNION (2, format);
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
0
  {
337
0
    TRACE_SUBSET (this);
338
0
    auto *out = c->serializer->start_embed (*this);
339
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
340
0
341
0
    + hb_iter (carets)
342
0
    | hb_apply (subset_offset_array (c, out->carets, this))
343
0
    ;
344
0
345
0
    return_trace (bool (out->carets));
346
0
  }
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
0
  {
356
0
    TRACE_SANITIZE (this);
357
0
    return_trace (carets.sanitize (c, this));
358
0
  }
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
0
  {
392
0
    TRACE_SUBSET (this);
393
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
394
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
395
0
396
0
    auto *out = c->serializer->start_embed (*this);
397
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
398
0
399
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
400
0
    + hb_zip (this+coverage, ligGlyph)
401
0
    | hb_filter (glyphset, hb_first)
402
0
    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
403
0
    | hb_map (hb_first)
404
0
    | hb_map (glyph_map)
405
0
    | hb_sink (new_coverage)
406
0
    ;
407
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
408
0
    return_trace (bool (new_coverage));
409
0
  }
410
411
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
412
0
  {
413
0
    + hb_zip (this+coverage, ligGlyph)
414
0
    | hb_filter (c->glyph_set, hb_first)
415
0
    | hb_map (hb_second)
416
0
    | hb_map (hb_add (this))
417
0
    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
418
0
    ;
419
0
  }
420
421
  bool sanitize (hb_sanitize_context_t *c) const
422
20
  {
423
20
    TRACE_SANITIZE (this);
424
20
    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
425
20
  }
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
0
  {
447
0
    unsigned i = 0;
448
0
    for (const auto &offset : coverage)
449
0
     {
450
0
       const auto &cov = this+offset;
451
0
       if (cov.intersects (&glyph_set))
452
0
         used_mark_sets.add (i);
453
0
454
0
       i++;
455
0
     }
456
0
  }
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
0
  {
470
0
    TRACE_SUBSET (this);
471
0
    auto *out = c->serializer->start_embed (*this);
472
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
473
0
    out->format = format;
474
0
475
0
    bool ret = true;
476
0
    for (const Offset32To<Coverage>& offset : coverage.iter ())
477
0
    {
478
0
      auto snap = c->serializer->snapshot ();
479
0
      auto *o = out->coverage.serialize_append (c->serializer);
480
0
      if (unlikely (!o))
481
0
      {
482
0
  ret = false;
483
0
  break;
484
0
      }
485
0
486
0
      //skip empty coverage
487
0
      c->serializer->push ();
488
0
      bool res = false;
489
0
      if (offset) res = c->dispatch (this+offset);
490
0
      if (!res)
491
0
      {
492
0
        c->serializer->pop_discard ();
493
0
        c->serializer->revert (snap);
494
0
        (out->coverage.len)--;
495
0
        continue;
496
0
      }
497
0
      c->serializer->add_link (*o, c->serializer->pop_pack ());
498
0
    }
499
0
500
0
    return_trace (ret && out->coverage.len);
501
0
  }
502
503
  bool sanitize (hb_sanitize_context_t *c) const
504
0
  {
505
0
    TRACE_SANITIZE (this);
506
0
    return_trace (coverage.sanitize (c, this));
507
0
  }
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) {
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
1.88k
  {
531
1.88k
    switch (u.format) {
532
0
    case 1: u.format1.collect_coverage (sets); return;
533
1.88k
    default:return;
534
1.88k
    }
535
1.88k
  }
536
537
  void collect_used_mark_sets (const hb_set_t& glyph_set,
538
                               hb_set_t& used_mark_sets /* OUT */) const
539
0
  {
540
0
    switch (u.format) {
541
0
    case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
542
0
    default:return;
543
0
    }
544
0
  }
545
546
  bool subset (hb_subset_context_t *c) const
547
0
  {
548
0
    TRACE_SUBSET (this);
549
0
    switch (u.format) {
550
0
    case 1: return_trace (u.format1.subset (c));
551
0
    default:return_trace (false);
552
0
    }
553
0
  }
554
555
  bool sanitize (hb_sanitize_context_t *c) const
556
0
  {
557
0
    TRACE_SANITIZE (this);
558
0
    if (!u.format.sanitize (c)) return_trace (false);
559
0
    hb_barrier ();
560
0
    switch (u.format) {
561
0
    case 1: return_trace (u.format1.sanitize (c));
562
0
    default:return_trace (true);
563
0
    }
564
0
  }
565
566
  protected:
567
  union {
568
  HBUINT16    format;   /* Format identifier */
569
  MarkGlyphSetsFormat1  format1;
570
  } u;
571
  public:
572
  DEFINE_SIZE_UNION (2, format);
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
  }
625
626
  bool sanitize (hb_sanitize_context_t *c) const
627
20
  {
628
20
    TRACE_SANITIZE (this);
629
20
    return_trace (version.sanitize (c) &&
630
20
      glyphClassDef.sanitize (c, this) &&
631
20
      attachList.sanitize (c, this) &&
632
20
      ligCaretList.sanitize (c, this) &&
633
20
      markAttachClassDef.sanitize (c, this) &&
634
20
      hb_barrier () &&
635
20
      ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
636
20
      ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
637
20
  }
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
0
    /* varidx_map is empty which means varstore is empty after instantiation,
643
0
     * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
644
0
     * varidx_map doesn't have original varidx, indicating delta row is all
645
0
     * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
646
0
    for (auto _ : layout_variation_idx_delta_map.iter_ref ())
647
0
    {
648
0
      /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
649
0
       * 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
  }
658
659
  bool subset (hb_subset_context_t *c) const
660
0
  {
661
0
    TRACE_SUBSET (this);
662
0
    auto *out = c->serializer->start_embed (*this);
663
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
664
0
665
0
    // Push var store first (if it's needed) so that it's last in the
666
0
    // serialization order. Some font consumers assume that varstore runs to
667
0
    // the end of the GDEF table.
668
0
    // See: https://github.com/harfbuzz/harfbuzz/issues/4636
669
0
    auto snapshot_version0 = c->serializer->snapshot ();
670
0
    if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
671
0
      return_trace (false);
672
0
673
0
    bool subset_varstore = false;
674
0
    unsigned varstore_index = (unsigned) -1;
675
0
    auto snapshot_version2 = c->serializer->snapshot ();
676
0
    if (version.to_int () >= 0x00010003u && hb_barrier ())
677
0
    {
678
0
      if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
679
0
      if (c->plan->all_axes_pinned)
680
0
        out->varStore = 0;
681
0
      else if (c->plan->normalized_coords)
682
0
      {
683
0
        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
0
      }
699
0
      else
700
0
      {
701
0
        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
702
0
        varstore_index = c->serializer->last_added_child_index();
703
0
      }
704
0
    }
705
0
706
0
    out->version.major = version.major;
707
0
    out->version.minor = version.minor;
708
0
709
0
    if (!subset_varstore && version.to_int () >= 0x00010002u) {
710
0
      c->serializer->revert (snapshot_version2);
711
0
    }
712
0
713
0
    bool subset_markglyphsetsdef = false;
714
0
    if (version.to_int () >= 0x00010002u && hb_barrier ())
715
0
    {
716
0
      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
717
0
    }
718
0
719
0
    if (subset_varstore)
720
0
    {
721
0
      out->version.minor = 3;
722
0
      c->plan->has_gdef_varstore = true;
723
0
    } else if (subset_markglyphsetsdef) {
724
0
      out->version.minor = 2;      
725
0
    } else  {
726
0
      out->version.minor = 0;
727
0
      c->serializer->revert (snapshot_version0);
728
0
    }
729
0
730
0
    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
731
0
    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
732
0
    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
733
0
    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
734
0
735
0
    if (subset_varstore && varstore_index != (unsigned) -1) {
736
0
      c->serializer->repack_last(varstore_index);
737
0
    }
738
0
739
0
    return_trace (subset_glyphclassdef || subset_attachlist ||
740
0
      subset_ligcaretlist || subset_markattachclassdef ||
741
0
      (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
742
0
      (out->version.to_int () >= 0x00010003u && subset_varstore));
743
0
  }
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
20
  {
771
20
    TRACE_SANITIZE (this);
772
20
    if (unlikely (!u.version.sanitize (c))) return_trace (false);
773
20
    hb_barrier ();
774
20
    switch (u.version.major) {
775
20
    case 1: return_trace (u.version1.sanitize (c));
776
#ifndef HB_NO_BEYOND_64K
777
    case 2: return_trace (u.version2.sanitize (c));
778
#endif
779
0
    default: return_trace (true);
780
20
    }
781
20
  }
782
783
  bool subset (hb_subset_context_t *c) const
784
0
  {
785
0
    switch (u.version.major) {
786
0
    case 1: return u.version1.subset (c);
787
0
#ifndef HB_NO_BEYOND_64K
788
0
    case 2: return u.version2.subset (c);
789
0
#endif
790
0
    default: return false;
791
0
    }
792
0
  }
793
794
  bool has_glyph_classes () const
795
249k
  {
796
249k
    switch (u.version.major) {
797
2.73k
    case 1: return u.version1.glyphClassDef != 0;
798
#ifndef HB_NO_BEYOND_64K
799
    case 2: return u.version2.glyphClassDef != 0;
800
#endif
801
247k
    default: return false;
802
249k
    }
803
249k
  }
804
  const ClassDef &get_glyph_class_def () const
805
9.82k
  {
806
9.82k
    switch (u.version.major) {
807
21
    case 1: return this+u.version1.glyphClassDef;
808
#ifndef HB_NO_BEYOND_64K
809
    case 2: return this+u.version2.glyphClassDef;
810
#endif
811
9.80k
    default: return Null(ClassDef);
812
9.82k
    }
813
9.82k
  }
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
#ifndef HB_NO_BEYOND_64K
829
    case 2: return this+u.version2.attachList;
830
#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
0
  {
846
0
    switch (u.version.major) {
847
0
    case 1: return this+u.version1.ligCaretList;
848
#ifndef HB_NO_BEYOND_64K
849
    case 2: return this+u.version2.ligCaretList;
850
#endif
851
0
    default: return Null(LigCaretList);
852
0
    }
853
0
  }
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
#ifndef HB_NO_BEYOND_64K
869
    case 2: return this+u.version2.markAttachClassDef;
870
#endif
871
0
    default: return Null(ClassDef);
872
0
    }
873
0
  }
874
  bool has_mark_glyph_sets () const
875
0
  {
876
0
    switch (u.version.major) {
877
0
    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
878
0
#ifndef HB_NO_BEYOND_64K
879
0
    case 2: return u.version2.markGlyphSetsDef != 0;
880
0
#endif
881
0
    default: return false;
882
0
    }
883
0
  }
884
  const MarkGlyphSets &get_mark_glyph_sets () const
885
1.88k
  {
886
1.88k
    switch (u.version.major) {
887
20
    case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
888
#ifndef HB_NO_BEYOND_64K
889
    case 2: return this+u.version2.markGlyphSetsDef;
890
#endif
891
1.86k
    default: return Null(MarkGlyphSets);
892
1.88k
    }
893
1.88k
  }
894
  bool has_var_store () const
895
0
  {
896
0
    switch (u.version.major) {
897
0
    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
898
0
#ifndef HB_NO_BEYOND_64K
899
0
    case 2: return u.version2.varStore != 0;
900
0
#endif
901
0
    default: return false;
902
0
    }
903
0
  }
904
  const ItemVariationStore &get_var_store () const
905
621k
  {
906
621k
    switch (u.version.major) {
907
4.57k
    case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
908
#ifndef HB_NO_BEYOND_64K
909
    case 2: return this+u.version2.varStore;
910
#endif
911
616k
    default: return Null(ItemVariationStore);
912
621k
    }
913
621k
  }
914
915
916
0
  bool has_data () const { return u.version.to_int (); }
917
  unsigned int get_glyph_class (hb_codepoint_t glyph) const
918
9.82k
  { 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
9.82k
  {
949
9.82k
    unsigned int klass = get_glyph_class (glyph);
950
951
9.82k
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
952
9.82k
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
953
9.82k
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
954
955
9.82k
    switch (klass) {
956
9.80k
    default:      return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
957
21
    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
9.82k
    }
963
9.82k
  }
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
1.88k
    {
972
1.88k
      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
973
1.88k
      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
1.88k
#ifndef HB_NO_GDEF_CACHE
980
1.88k
      table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
981
1.88k
#endif
982
1.88k
    }
983
1.88k
    ~accelerator_t () { table.destroy (); }
984
985
    unsigned int get_glyph_props (hb_codepoint_t glyph) const
986
947k
    {
987
947k
      unsigned v;
988
989
947k
#ifndef HB_NO_GDEF_CACHE
990
947k
      if (glyph_props_cache.get (glyph, &v))
991
937k
        return v;
992
9.82k
#endif
993
994
9.82k
      v = table->get_glyph_props (glyph);
995
996
9.82k
#ifndef HB_NO_GDEF_CACHE
997
9.82k
      if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
998
9.82k
  glyph_props_cache.set (glyph, v);
999
9.82k
#endif
1000
1001
9.82k
      return v;
1002
1003
947k
    }
1004
1005
    bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
1006
0
    {
1007
0
      return
1008
0
#ifndef HB_NO_GDEF_CACHE
1009
0
       mark_glyph_sets[set_index].may_have (glyph_id)
1010
#else
1011
       table->mark_set_covers (set_index, glyph_id)
1012
#endif
1013
0
      ;
1014
0
    }
1015
1016
    hb_blob_ptr_t<GDEF> table;
1017
#ifndef HB_NO_GDEF_CACHE
1018
    hb_vector_t<hb_bit_set_t> mark_glyph_sets;
1019
    mutable hb_cache_t<21, 3> glyph_props_cache;
1020
    static_assert (sizeof (glyph_props_cache) == 512, "");
1021
#endif
1022
  };
1023
1024
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
1025
0
  { get_lig_caret_list ().collect_variation_indices (c); }
1026
1027
  protected:
1028
  union {
1029
  FixedVersion<>    version;  /* Version identifier */
1030
  GDEFVersion1_2<SmallTypes>  version1;
1031
#ifndef HB_NO_BEYOND_64K
1032
  GDEFVersion1_2<MediumTypes> version2;
1033
#endif
1034
  } u;
1035
  public:
1036
  DEFINE_SIZE_MIN (4);
1037
};
1038
1039
struct GDEF_accelerator_t : GDEF::accelerator_t {
1040
1.88k
  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
1041
};
1042
1043
} /* namespace OT */
1044
1045
1046
#endif /* OT_LAYOUT_GDEF_GDEF_HH */