Coverage Report

Created: 2024-05-20 07:14

/src/skia/third_party/externals/harfbuzz/src/hb-ot-layout-base-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2016  Elie Roux <elie.roux@telecom-bretagne.eu>
3
 * Copyright © 2018  Google, Inc.
4
 * Copyright © 2018-2019  Ebrahim Byagowi
5
 *
6
 *  This is part of HarfBuzz, a text shaping library.
7
 *
8
 * Permission is hereby granted, without written agreement and without
9
 * license or royalty fees, to use, copy, modify, and distribute this
10
 * software and its documentation for any purpose, provided that the
11
 * above copyright notice and the following two paragraphs appear in
12
 * all copies of this software.
13
 *
14
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18
 * DAMAGE.
19
 *
20
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25
 *
26
 * Google Author(s): Behdad Esfahbod
27
 */
28
29
#ifndef HB_OT_LAYOUT_BASE_TABLE_HH
30
#define HB_OT_LAYOUT_BASE_TABLE_HH
31
32
#include "hb-open-type.hh"
33
#include "hb-ot-layout-common.hh"
34
35
namespace OT {
36
37
/*
38
 * BASE -- Baseline
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/base
40
 */
41
42
struct BaseCoordFormat1
43
{
44
  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
45
0
  {
46
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
47
0
  }
48
49
  bool subset (hb_subset_context_t *c) const
50
0
  {
51
0
    TRACE_SUBSET (this);
52
0
    return_trace ((bool) c->serializer->embed (*this));
53
0
  }
Unexecuted instantiation: OT::BaseCoordFormat1::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseCoordFormat1::subset(hb_subset_context_t*) const
54
55
  bool sanitize (hb_sanitize_context_t *c) const
56
0
  {
57
0
    TRACE_SANITIZE (this);
58
0
    return_trace (c->check_struct (this));
59
0
  }
60
61
  protected:
62
  HBUINT16  format;   /* Format identifier--format = 1 */
63
  FWORD   coordinate; /* X or Y value, in design units */
64
  public:
65
  DEFINE_SIZE_STATIC (4);
66
};
67
68
struct BaseCoordFormat2
69
{
70
  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
71
0
  {
72
    /* TODO */
73
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
74
0
  }
75
76
  bool subset (hb_subset_context_t *c) const
77
0
  {
78
0
    TRACE_SUBSET (this);
79
0
    auto *out = c->serializer->embed (*this);
80
0
    if (unlikely (!out)) return_trace (false);
81
82
0
    return_trace (c->serializer->check_assign (out->referenceGlyph,
83
0
                                               c->plan->glyph_map->get (referenceGlyph),
84
0
                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
85
0
  }
Unexecuted instantiation: OT::BaseCoordFormat2::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseCoordFormat2::subset(hb_subset_context_t*) const
86
87
  bool sanitize (hb_sanitize_context_t *c) const
88
0
  {
89
0
    TRACE_SANITIZE (this);
90
0
    return_trace (c->check_struct (this));
91
0
  }
92
93
  protected:
94
  HBUINT16  format;   /* Format identifier--format = 2 */
95
  FWORD   coordinate; /* X or Y value, in design units */
96
  HBGlyphID16 referenceGlyph; /* Glyph ID of control glyph */
97
  HBUINT16  coordPoint; /* Index of contour point on the
98
         * reference glyph */
99
  public:
100
  DEFINE_SIZE_STATIC (8);
101
};
102
103
struct BaseCoordFormat3
104
{
105
  hb_position_t get_coord (hb_font_t *font,
106
         const ItemVariationStore &var_store,
107
         hb_direction_t direction) const
108
0
  {
109
0
    const Device &device = this+deviceTable;
110
111
0
    return HB_DIRECTION_IS_HORIZONTAL (direction)
112
0
   ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
113
0
   : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
114
0
  }
115
116
  void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
117
0
  {
118
0
    unsigned varidx = (this+deviceTable).get_variation_index ();
119
0
    varidx_set.add (varidx);
120
0
  }
121
122
  bool subset (hb_subset_context_t *c) const
123
0
  {
124
0
    TRACE_SUBSET (this);
125
0
    auto *out = c->serializer->embed (*this);
126
0
    if (unlikely (!out)) return_trace (false);
127
128
0
    if (!c->plan->pinned_at_default)
129
0
    {
130
0
      unsigned var_idx = (this+deviceTable).get_variation_index ();
131
0
      if (var_idx != VarIdx::NO_VARIATION)
132
0
      {
133
0
        hb_pair_t<unsigned, int> *v;
134
0
        if (!c->plan->base_variation_idx_map.has (var_idx, &v))
135
0
          return_trace (false);
136
        
137
0
        if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v),
138
0
                                                    HB_SERIALIZE_ERROR_INT_OVERFLOW)))
139
0
          return_trace (false);
140
0
      }
141
0
    }
142
0
    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
143
0
                                                   this, 0,
144
0
                                                   hb_serialize_context_t::Head,
145
0
                                                   &c->plan->base_variation_idx_map));
146
0
  }
Unexecuted instantiation: OT::BaseCoordFormat3::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseCoordFormat3::subset(hb_subset_context_t*) const
147
148
  bool sanitize (hb_sanitize_context_t *c) const
149
0
  {
150
0
    TRACE_SANITIZE (this);
151
0
    return_trace (likely (c->check_struct (this) &&
152
0
        deviceTable.sanitize (c, this)));
153
0
  }
154
155
  protected:
156
  HBUINT16  format;   /* Format identifier--format = 3 */
157
  FWORD   coordinate; /* X or Y value, in design units */
158
  Offset16To<Device>
159
    deviceTable;  /* Offset to Device table for X or
160
         * Y value, from beginning of
161
         * BaseCoord table (may be NULL). */
162
  public:
163
  DEFINE_SIZE_STATIC (6);
164
};
165
166
struct BaseCoord
167
{
168
0
  bool has_data () const { return u.format; }
169
170
  hb_position_t get_coord (hb_font_t            *font,
171
         const ItemVariationStore &var_store,
172
         hb_direction_t        direction) const
173
0
  {
174
0
    switch (u.format) {
175
0
    case 1: return u.format1.get_coord (font, direction);
176
0
    case 2: return u.format2.get_coord (font, direction);
177
0
    case 3: return u.format3.get_coord (font, var_store, direction);
178
0
    default:return 0;
179
0
    }
180
0
  }
181
182
  void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
183
0
  {
184
0
    switch (u.format) {
185
0
    case 3: u.format3.collect_variation_indices (varidx_set);
186
0
    default:return;
187
0
    }
188
0
  }
189
190
  template <typename context_t, typename ...Ts>
191
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
192
0
  {
193
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
194
0
    TRACE_DISPATCH (this, u.format);
195
0
    switch (u.format) {
196
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
197
0
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
198
0
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
199
0
    default:return_trace (c->default_return_value ());
200
0
    }
201
0
  }
Unexecuted instantiation: hb_subset_context_t::return_t OT::BaseCoord::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::BaseCoord::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
202
203
  bool sanitize (hb_sanitize_context_t *c) const
204
0
  {
205
0
    TRACE_SANITIZE (this);
206
0
    if (unlikely (!u.format.sanitize (c))) return_trace (false);
207
0
    hb_barrier ();
208
0
    switch (u.format) {
209
0
    case 1: return_trace (u.format1.sanitize (c));
210
0
    case 2: return_trace (u.format2.sanitize (c));
211
0
    case 3: return_trace (u.format3.sanitize (c));
212
0
    default:return_trace (false);
213
0
    }
214
0
  }
215
216
  protected:
217
  union {
218
  HBUINT16    format;
219
  BaseCoordFormat1  format1;
220
  BaseCoordFormat2  format2;
221
  BaseCoordFormat3  format3;
222
  } u;
223
  public:
224
  DEFINE_SIZE_UNION (2, format);
225
};
226
227
struct FeatMinMaxRecord
228
{
229
0
  int cmp (hb_tag_t key) const { return tag.cmp (key); }
230
231
0
  bool has_data () const { return tag; }
232
233
0
  hb_tag_t get_feature_tag () const { return tag; }
234
235
  void get_min_max (const BaseCoord **min, const BaseCoord **max) const
236
0
  {
237
0
    if (likely (min)) *min = &(this+minCoord);
238
0
    if (likely (max)) *max = &(this+maxCoord);
239
0
  }
240
241
  void collect_variation_indices (const hb_subset_plan_t* plan,
242
                                  const void *base,
243
                                  hb_set_t& varidx_set /* OUT */) const
244
0
  {
245
0
    if (!plan->layout_features.has (tag))
246
0
      return;
247
0
248
0
    (base+minCoord).collect_variation_indices (varidx_set);
249
0
    (base+maxCoord).collect_variation_indices (varidx_set);
250
0
  }
251
252
  bool subset (hb_subset_context_t *c,
253
               const void *base) const
254
0
  {
255
0
    TRACE_SUBSET (this);
256
0
    auto *out = c->serializer->embed (*this);
257
0
    if (unlikely (!out)) return_trace (false);
258
0
    if (!(out->minCoord.serialize_subset (c, minCoord, base)))
259
0
      return_trace (false);
260
261
0
    return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
262
0
  }
Unexecuted instantiation: OT::FeatMinMaxRecord::subset(hb_subset_context_t*, void const*) const
Unexecuted instantiation: OT::FeatMinMaxRecord::subset(hb_subset_context_t*, void const*) const
263
264
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
265
0
  {
266
0
    TRACE_SANITIZE (this);
267
0
    return_trace (likely (c->check_struct (this) &&
268
0
        minCoord.sanitize (c, base) &&
269
0
        maxCoord.sanitize (c, base)));
270
0
  }
271
272
  protected:
273
  Tag   tag;    /* 4-byte feature identification tag--must
274
         * match feature tag in FeatureList */
275
  Offset16To<BaseCoord>
276
    minCoord; /* Offset to BaseCoord table that defines
277
         * the minimum extent value, from beginning
278
         * of MinMax table (may be NULL) */
279
  Offset16To<BaseCoord>
280
    maxCoord; /* Offset to BaseCoord table that defines
281
         * the maximum extent value, from beginning
282
         * of MinMax table (may be NULL) */
283
  public:
284
  DEFINE_SIZE_STATIC (8);
285
};
286
287
struct MinMax
288
{
289
  void get_min_max (hb_tag_t          feature_tag,
290
        const BaseCoord **min,
291
        const BaseCoord **max) const
292
0
  {
293
0
    const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
294
0
    if (minMaxCoord.has_data ())
295
0
      minMaxCoord.get_min_max (min, max);
296
0
    else
297
0
    {
298
0
      if (likely (min)) *min = &(this+minCoord);
299
0
      if (likely (max)) *max = &(this+maxCoord);
300
0
    }
301
0
  }
302
303
  void collect_variation_indices (const hb_subset_plan_t* plan,
304
                                  hb_set_t& varidx_set /* OUT */) const
305
0
  {
306
0
    (this+minCoord).collect_variation_indices (varidx_set);
307
0
    (this+maxCoord).collect_variation_indices (varidx_set);
308
0
    for (const FeatMinMaxRecord& record : featMinMaxRecords)
309
0
      record.collect_variation_indices (plan, this, varidx_set);
310
0
  }
311
312
  bool subset (hb_subset_context_t *c) const
313
0
  {
314
0
    TRACE_SUBSET (this);
315
0
    auto *out = c->serializer->start_embed (*this);
316
0
    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
317
318
0
    if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
319
0
        !(out->maxCoord.serialize_subset (c, maxCoord, this)))
320
0
      return_trace (false);
321
322
0
    unsigned len = 0;
323
0
    for (const FeatMinMaxRecord& _ : featMinMaxRecords)
324
0
    {
325
0
      hb_tag_t feature_tag = _.get_feature_tag ();
326
0
      if (!c->plan->layout_features.has (feature_tag))
327
0
        continue;
328
329
0
      if (!_.subset (c, this)) return false;
330
0
      len++;
331
0
    }
332
0
    return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
333
0
                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
334
0
  }
Unexecuted instantiation: OT::MinMax::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::MinMax::subset(hb_subset_context_t*) const
335
336
  bool sanitize (hb_sanitize_context_t *c) const
337
0
  {
338
0
    TRACE_SANITIZE (this);
339
0
    return_trace (likely (c->check_struct (this) &&
340
0
        minCoord.sanitize (c, this) &&
341
0
        maxCoord.sanitize (c, this) &&
342
0
        featMinMaxRecords.sanitize (c, this)));
343
0
  }
344
345
  protected:
346
  Offset16To<BaseCoord>
347
    minCoord; /* Offset to BaseCoord table that defines
348
         * minimum extent value, from the beginning
349
         * of MinMax table (may be NULL) */
350
  Offset16To<BaseCoord>
351
    maxCoord; /* Offset to BaseCoord table that defines
352
         * maximum extent value, from the beginning
353
         * of MinMax table (may be NULL) */
354
  SortedArray16Of<FeatMinMaxRecord>
355
    featMinMaxRecords;
356
        /* Array of FeatMinMaxRecords, in alphabetical
357
         * order by featureTableTag */
358
  public:
359
  DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
360
};
361
362
struct BaseValues
363
{
364
  const BaseCoord &get_base_coord (int baseline_tag_index) const
365
0
  {
366
0
    if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
367
0
    return this+baseCoords[baseline_tag_index];
368
0
  }
369
370
  void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
371
0
  {
372
0
    for (const auto& _ : baseCoords)
373
0
      (this+_).collect_variation_indices (varidx_set);
374
0
  }
375
376
  bool subset (hb_subset_context_t *c) const
377
0
  {
378
0
    TRACE_SUBSET (this);
379
0
    auto *out = c->serializer->start_embed (*this);
380
0
    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
381
0
    out->defaultIndex = defaultIndex;
382
383
0
    for (const auto& _ : baseCoords)
384
0
      if (!subset_offset_array (c, out->baseCoords, this) (_))
385
0
        return_trace (false);
386
387
0
    return_trace (bool (out->baseCoords));
388
0
  }
Unexecuted instantiation: OT::BaseValues::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseValues::subset(hb_subset_context_t*) const
389
390
  bool sanitize (hb_sanitize_context_t *c) const
391
0
  {
392
0
    TRACE_SANITIZE (this);
393
0
    return_trace (likely (c->check_struct (this) &&
394
0
        baseCoords.sanitize (c, this)));
395
0
  }
396
397
  protected:
398
  Index   defaultIndex; /* Index number of default baseline for this
399
         * script — equals index position of baseline tag
400
         * in baselineTags array of the BaseTagList */
401
  Array16OfOffset16To<BaseCoord>
402
    baseCoords; /* Number of BaseCoord tables defined — should equal
403
         * baseTagCount in the BaseTagList
404
         *
405
         * Array of offsets to BaseCoord tables, from beginning of
406
         * BaseValues table — order matches baselineTags array in
407
         * the BaseTagList */
408
  public:
409
  DEFINE_SIZE_ARRAY (4, baseCoords);
410
};
411
412
struct BaseLangSysRecord
413
{
414
0
  int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
415
416
0
  bool has_data () const { return baseLangSysTag; }
417
418
0
  const MinMax &get_min_max (const void* base) const { return base+minMax; }
419
420
  void collect_variation_indices (const void* base,
421
                                  const hb_subset_plan_t* plan,
422
                                  hb_set_t& varidx_set /* OUT */) const
423
0
  { (base+minMax).collect_variation_indices (plan, varidx_set); }
424
425
  bool subset (hb_subset_context_t *c,
426
               const void *base) const
427
0
  {
428
0
    TRACE_SUBSET (this);
429
0
    auto *out = c->serializer->embed (*this);
430
0
    if (unlikely (!out)) return_trace (false);
431
432
0
    return_trace (out->minMax.serialize_subset (c, minMax, base));
433
0
  }
Unexecuted instantiation: OT::BaseLangSysRecord::subset(hb_subset_context_t*, void const*) const
Unexecuted instantiation: OT::BaseLangSysRecord::subset(hb_subset_context_t*, void const*) const
434
435
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
436
0
  {
437
0
    TRACE_SANITIZE (this);
438
0
    return_trace (likely (c->check_struct (this) &&
439
0
        minMax.sanitize (c, base)));
440
0
  }
441
442
  protected:
443
  Tag   baseLangSysTag; /* 4-byte language system identification tag */
444
  Offset16To<MinMax>
445
    minMax;   /* Offset to MinMax table, from beginning
446
         * of BaseScript table */
447
  public:
448
  DEFINE_SIZE_STATIC (6);
449
};
450
451
struct BaseScript
452
{
453
  const MinMax &get_min_max (hb_tag_t language_tag) const
454
0
  {
455
0
    const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
456
0
    return record.has_data () ? record.get_min_max (this) : this+defaultMinMax;
457
0
  }
458
459
  const BaseCoord &get_base_coord (int baseline_tag_index) const
460
0
  { return (this+baseValues).get_base_coord (baseline_tag_index); }
461
462
0
  bool has_values () const { return baseValues; }
463
0
  bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
464
465
  void collect_variation_indices (const hb_subset_plan_t* plan,
466
                                  hb_set_t& varidx_set /* OUT */) const
467
0
  {
468
0
    (this+baseValues).collect_variation_indices (varidx_set);
469
0
    (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
470
0
    
471
0
    for (const BaseLangSysRecord& _ : baseLangSysRecords)
472
0
      _.collect_variation_indices (this, plan, varidx_set);
473
0
  }
474
475
  bool subset (hb_subset_context_t *c) const
476
0
  {
477
0
    TRACE_SUBSET (this);
478
0
    auto *out = c->serializer->start_embed (*this);
479
0
    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
480
481
0
    if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
482
0
      return_trace (false);
483
484
0
    if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
485
0
      return_trace (false);
486
487
0
    for (const auto& _ : baseLangSysRecords)
488
0
      if (!_.subset (c, this)) return_trace (false);
489
490
0
    return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
491
0
                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
492
0
  }
Unexecuted instantiation: OT::BaseScript::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseScript::subset(hb_subset_context_t*) const
493
494
  bool sanitize (hb_sanitize_context_t *c) const
495
0
  {
496
0
    TRACE_SANITIZE (this);
497
0
    return_trace (likely (c->check_struct (this) &&
498
0
        baseValues.sanitize (c, this) &&
499
0
        defaultMinMax.sanitize (c, this) &&
500
0
        baseLangSysRecords.sanitize (c, this)));
501
0
  }
502
503
  protected:
504
  Offset16To<BaseValues>
505
    baseValues; /* Offset to BaseValues table, from beginning
506
         * of BaseScript table (may be NULL) */
507
  Offset16To<MinMax>
508
    defaultMinMax;  /* Offset to MinMax table, from beginning of
509
         * BaseScript table (may be NULL) */
510
  SortedArray16Of<BaseLangSysRecord>
511
    baseLangSysRecords;
512
        /* Number of BaseLangSysRecords
513
         * defined — may be zero (0) */
514
515
  public:
516
  DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
517
};
518
519
struct BaseScriptList;
520
struct BaseScriptRecord
521
{
522
0
  int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
523
524
0
  bool has_data () const { return baseScriptTag; }
525
526
0
  hb_tag_t get_script_tag () const { return baseScriptTag; }
527
528
  const BaseScript &get_base_script (const BaseScriptList *list) const
529
0
  { return list+baseScript; }
530
531
  void collect_variation_indices (const hb_subset_plan_t* plan,
532
                                  const void* list,
533
                                  hb_set_t& varidx_set /* OUT */) const
534
0
  {
535
0
    if (!plan->layout_scripts.has (baseScriptTag))
536
0
      return;
537
0
538
0
    (list+baseScript).collect_variation_indices (plan, varidx_set);
539
0
  }
540
541
  bool subset (hb_subset_context_t *c,
542
               const void *base) const
543
0
  {
544
0
    TRACE_SUBSET (this);
545
0
    auto *out = c->serializer->embed (*this);
546
0
    if (unlikely (!out)) return_trace (false);
547
548
0
    return_trace (out->baseScript.serialize_subset (c, baseScript, base));
549
0
  }
Unexecuted instantiation: OT::BaseScriptRecord::subset(hb_subset_context_t*, void const*) const
Unexecuted instantiation: OT::BaseScriptRecord::subset(hb_subset_context_t*, void const*) const
550
551
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
552
0
  {
553
0
    TRACE_SANITIZE (this);
554
0
    return_trace (likely (c->check_struct (this) &&
555
0
        baseScript.sanitize (c, base)));
556
0
  }
557
558
  protected:
559
  Tag   baseScriptTag;  /* 4-byte script identification tag */
560
  Offset16To<BaseScript>
561
    baseScript; /* Offset to BaseScript table, from beginning
562
         * of BaseScriptList */
563
564
  public:
565
  DEFINE_SIZE_STATIC (6);
566
};
567
568
struct BaseScriptList
569
{
570
  const BaseScript &get_base_script (hb_tag_t script) const
571
0
  {
572
0
    const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
573
0
    if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
574
0
    return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
575
0
  }
576
577
  void collect_variation_indices (const hb_subset_plan_t* plan,
578
                                  hb_set_t& varidx_set /* OUT */) const
579
0
  {
580
0
    for (const BaseScriptRecord& _ : baseScriptRecords)
581
0
      _.collect_variation_indices (plan, this, varidx_set);
582
0
  }
583
584
  bool subset (hb_subset_context_t *c) const
585
0
  {
586
0
    TRACE_SUBSET (this);
587
0
    auto *out = c->serializer->start_embed (*this);
588
0
    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
589
590
0
    unsigned len = 0;
591
0
    for (const BaseScriptRecord& _ : baseScriptRecords)
592
0
    {
593
0
      hb_tag_t script_tag = _.get_script_tag ();
594
0
      if (!c->plan->layout_scripts.has (script_tag))
595
0
        continue;
596
597
0
      if (!_.subset (c, this)) return false;
598
0
      len++;
599
0
    }
600
0
    return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
601
0
                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
602
0
  }
Unexecuted instantiation: OT::BaseScriptList::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BaseScriptList::subset(hb_subset_context_t*) const
603
604
  bool sanitize (hb_sanitize_context_t *c) const
605
0
  {
606
0
    TRACE_SANITIZE (this);
607
0
    return_trace (c->check_struct (this) &&
608
0
      baseScriptRecords.sanitize (c, this));
609
0
  }
610
611
  protected:
612
  SortedArray16Of<BaseScriptRecord>
613
      baseScriptRecords;
614
615
  public:
616
  DEFINE_SIZE_ARRAY (2, baseScriptRecords);
617
};
618
619
struct Axis
620
{
621
  bool get_baseline (hb_tag_t          baseline_tag,
622
         hb_tag_t          script_tag,
623
         hb_tag_t          language_tag,
624
         const BaseCoord **coord) const
625
0
  {
626
0
    const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
627
0
    if (!base_script.has_values ())
628
0
    {
629
0
      *coord = nullptr;
630
0
      return false;
631
0
    }
632
633
0
    if (likely (coord))
634
0
    {
635
0
      unsigned int tag_index = 0;
636
0
      if (!(this+baseTagList).bfind (baseline_tag, &tag_index))
637
0
      {
638
0
        *coord = nullptr;
639
0
        return false;
640
0
      }
641
0
      *coord = &base_script.get_base_coord (tag_index);
642
0
    }
643
644
0
    return true;
645
0
  }
646
647
  bool get_min_max (hb_tag_t          script_tag,
648
        hb_tag_t          language_tag,
649
        hb_tag_t          feature_tag,
650
        const BaseCoord **min_coord,
651
        const BaseCoord **max_coord) const
652
0
  {
653
0
    const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
654
0
    if (!base_script.has_min_max ())
655
0
    {
656
0
      *min_coord = *max_coord = nullptr;
657
0
      return false;
658
0
    }
659
660
0
    base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
661
662
0
    return true;
663
0
  }
664
665
  void collect_variation_indices (const hb_subset_plan_t* plan,
666
                                  hb_set_t& varidx_set /* OUT */) const
667
0
  { (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
668
669
  bool subset (hb_subset_context_t *c) const
670
0
  {
671
0
    TRACE_SUBSET (this);
672
0
    auto *out = c->serializer->embed (*this);
673
0
    if (unlikely (!out)) return_trace (false);
674
675
0
    out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
676
0
    return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
677
0
  }
Unexecuted instantiation: OT::Axis::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::Axis::subset(hb_subset_context_t*) const
678
679
  bool sanitize (hb_sanitize_context_t *c) const
680
0
  {
681
0
    TRACE_SANITIZE (this);
682
0
    return_trace (likely (c->check_struct (this) &&
683
0
        baseTagList.sanitize (c, this) &&
684
0
        baseScriptList.sanitize (c, this)));
685
0
  }
686
687
  protected:
688
  Offset16To<SortedArray16Of<Tag>>
689
    baseTagList;  /* Offset to BaseTagList table, from beginning
690
         * of Axis table (may be NULL)
691
         * Array of 4-byte baseline identification tags — must
692
         * be in alphabetical order */
693
  Offset16To<BaseScriptList>
694
    baseScriptList; /* Offset to BaseScriptList table, from beginning
695
         * of Axis table
696
         * Array of BaseScriptRecords, in alphabetical order
697
         * by baseScriptTag */
698
699
  public:
700
  DEFINE_SIZE_STATIC (4);
701
};
702
703
struct BASE
704
{
705
  static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
706
707
  const Axis &get_axis (hb_direction_t direction) const
708
0
  { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
709
710
  bool has_var_store () const
711
0
  { return version.to_int () >= 0x00010001u && varStore != 0; }
712
713
  const ItemVariationStore &get_var_store () const
714
0
  { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
715
716
  void collect_variation_indices (const hb_subset_plan_t* plan,
717
                                  hb_set_t& varidx_set /* OUT */) const
718
0
  {
719
0
    (this+hAxis).collect_variation_indices (plan, varidx_set);
720
0
    (this+vAxis).collect_variation_indices (plan, varidx_set);
721
0
  }
722
723
  bool subset_varstore (hb_subset_context_t *c,
724
                        BASE *out /* OUT */) const
725
0
  {
726
0
    TRACE_SUBSET (this);
727
0
    if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
728
0
        return_trace (false);
729
0
    if (!c->plan->normalized_coords)
730
0
      return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
731
732
0
    if (c->plan->all_axes_pinned)
733
0
      return_trace (true);
734
735
0
    item_variations_t item_vars;
736
0
    if (!item_vars.instantiate (this+varStore, c->plan, true, true,
737
0
                                c->plan->base_varstore_inner_maps.as_array ()))
738
0
      return_trace (false);
739
740
0
    if (!out->varStore.serialize_serialize (c->serializer,
741
0
                                            item_vars.has_long_word (),
742
0
                                            c->plan->axis_tags,
743
0
                                            item_vars.get_region_list (),
744
0
                                            item_vars.get_vardata_encodings ()))
745
0
      return_trace (false);
746
747
0
    const hb_map_t &varidx_map = item_vars.get_varidx_map ();
748
    /* base_variation_idx_map in the plan is old_varidx->(varidx, delta)
749
     * mapping, new varidx is generated for subsetting, we need to remap this
750
     * after instancing */
751
0
    for (auto _ : c->plan->base_variation_idx_map.iter_ref ())
752
0
    {
753
0
      uint32_t varidx = _.second.first;
754
0
      uint32_t *new_varidx;
755
0
      if (varidx_map.has (varidx, &new_varidx))
756
0
        _.second.first = *new_varidx;
757
0
      else
758
0
        _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
759
0
    }
760
0
    return_trace (true);
761
0
  }
Unexecuted instantiation: OT::BASE::subset_varstore(hb_subset_context_t*, OT::BASE*) const
Unexecuted instantiation: OT::BASE::subset_varstore(hb_subset_context_t*, OT::BASE*) const
762
763
  bool subset (hb_subset_context_t *c) const
764
0
  {
765
0
    TRACE_SUBSET (this);
766
0
    auto *out = c->serializer->start_embed (*this);
767
0
    if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
768
769
0
    out->version = version;
770
0
    if (has_var_store () && !subset_varstore (c, out))
771
0
        return_trace (false);
772
773
0
    if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
774
0
      return_trace (false);
775
776
0
    if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
777
0
      return_trace (false);
778
779
0
    return_trace (true);
780
0
  }
Unexecuted instantiation: OT::BASE::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::BASE::subset(hb_subset_context_t*) const
781
782
  bool get_baseline (hb_font_t      *font,
783
         hb_tag_t        baseline_tag,
784
         hb_direction_t  direction,
785
         hb_tag_t        script_tag,
786
         hb_tag_t        language_tag,
787
         hb_position_t  *base) const
788
0
  {
789
0
    const BaseCoord *base_coord = nullptr;
790
0
    if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
791
0
      !base_coord || !base_coord->has_data ()))
792
0
      return false;
793
794
0
    if (likely (base))
795
0
      *base = base_coord->get_coord (font, get_var_store (), direction);
796
797
0
    return true;
798
0
  }
799
800
  bool get_min_max (hb_font_t      *font,
801
        hb_direction_t  direction,
802
        hb_tag_t        script_tag,
803
        hb_tag_t        language_tag,
804
        hb_tag_t        feature_tag,
805
        hb_position_t  *min,
806
        hb_position_t  *max) const
807
0
  {
808
0
    const BaseCoord *min_coord, *max_coord;
809
0
    if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
810
0
             &min_coord, &max_coord))
811
0
      return false;
812
813
0
    const ItemVariationStore &var_store = get_var_store ();
814
0
    if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
815
0
    if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
816
0
    return true;
817
0
  }
818
819
  bool sanitize (hb_sanitize_context_t *c) const
820
0
  {
821
0
    TRACE_SANITIZE (this);
822
0
    return_trace (likely (c->check_struct (this) &&
823
0
        hb_barrier () &&
824
0
        likely (version.major == 1) &&
825
0
        hAxis.sanitize (c, this) &&
826
0
        vAxis.sanitize (c, this) &&
827
0
        (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
828
0
  }
829
830
  protected:
831
  FixedVersion<>version;  /* Version of the BASE table */
832
  Offset16To<Axis>hAxis;    /* Offset to horizontal Axis table, from beginning
833
         * of BASE table (may be NULL) */
834
  Offset16To<Axis>vAxis;    /* Offset to vertical Axis table, from beginning
835
         * of BASE table (may be NULL) */
836
  Offset32To<ItemVariationStore>
837
    varStore; /* Offset to the table of Item Variation
838
         * Store--from beginning of BASE
839
         * header (may be NULL).  Introduced
840
         * in version 0x00010001. */
841
  public:
842
  DEFINE_SIZE_MIN (8);
843
};
844
845
846
} /* namespace OT */
847
848
849
#endif /* HB_OT_LAYOUT_BASE_TABLE_HH */