Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-stat-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2018  Ebrahim Byagowi
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 */
24
25
#ifndef HB_OT_STAT_TABLE_HH
26
#define HB_OT_STAT_TABLE_HH
27
28
#include "hb-open-type.hh"
29
#include "hb-ot-layout-common.hh"
30
31
/*
32
 * STAT -- Style Attributes
33
 * https://docs.microsoft.com/en-us/typography/opentype/spec/stat
34
 */
35
#define HB_OT_TAG_STAT HB_TAG('S','T','A','T')
36
37
38
namespace OT {
39
40
enum
41
{
42
  OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001,  /* If set, this axis value table
43
             * provides axis value information
44
             * that is applicable to other fonts
45
             * within the same font family. This
46
             * is used if the other fonts were
47
             * released earlier and did not include
48
             * information about values for some axis.
49
             * If newer versions of the other
50
             * fonts include the information
51
             * themselves and are present,
52
             * then this record is ignored. */
53
  ELIDABLE_AXIS_VALUE_NAME = 0x0002   /* If set, it indicates that the axis
54
             * value represents the “normal” value
55
             * for the axis and may be omitted when
56
             * composing name strings. */
57
  // Reserved = 0xFFFC        /* Reserved for future use — set to zero. */
58
};
59
60
static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_value,
61
                                              const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location)
62
0
{
63
0
  if (!user_axes_location->has (axis_tag))
64
0
    return false;
65
0
66
0
  double axis_value_double = static_cast<double>(axis_value);
67
0
  Triple axis_range = user_axes_location->get (axis_tag);
68
0
  return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum);
69
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::axis_value_is_outside_axis_range(unsigned int, float, hb_hashmap_t<unsigned int, Triple, false> const*)
Unexecuted instantiation: hb-ot-font.cc:OT::axis_value_is_outside_axis_range(unsigned int, float, hb_hashmap_t<unsigned int, Triple, false> const*)
Unexecuted instantiation: hb-ot-shape.cc:OT::axis_value_is_outside_axis_range(unsigned int, float, hb_hashmap_t<unsigned int, Triple, false> const*)
70
71
struct StatAxisRecord
72
{
73
0
  int cmp (hb_tag_t key) const { return tag.cmp (key); }
74
75
0
  hb_ot_name_id_t get_name_id () const { return nameID; }
76
77
0
  hb_tag_t get_axis_tag () const { return tag; }
78
79
  bool sanitize (hb_sanitize_context_t *c) const
80
0
  {
81
0
    TRACE_SANITIZE (this);
82
0
    return_trace (likely (c->check_struct (this)));
83
0
  }
84
85
  protected:
86
  Tag   tag;    /* A tag identifying the axis of design variation. */
87
  NameID  nameID;   /* The name ID for entries in the 'name' table that
88
         * provide a display string for this axis. */
89
  HBUINT16  ordering; /* A value that applications can use to determine
90
         * primary sorting of face names, or for ordering
91
         * of descriptors when composing family or face names. */
92
  public:
93
  DEFINE_SIZE_STATIC (8);
94
};
95
96
struct AxisValueFormat1
97
{
98
0
  unsigned int get_axis_index () const { return axisIndex; }
99
0
  float get_value ()             const { return value.to_float (); }
100
101
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
102
103
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
104
0
  {
105
0
    unsigned axis_idx = get_axis_index ();
106
0
    return axis_records[axis_idx].get_axis_tag ();
107
0
  }
108
109
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
110
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
111
0
  {
112
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
113
0
    float axis_value = get_value ();
114
0
115
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
116
0
  }
117
118
  bool subset (hb_subset_context_t *c,
119
               const hb_array_t<const StatAxisRecord> axis_records) const
120
0
  {
121
0
    TRACE_SUBSET (this);
122
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
123
0
124
0
    if (keep_axis_value (axis_records, user_axes_location))
125
0
      return_trace (c->serializer->embed (this));
126
0
127
0
    return_trace (false);
128
0
  }
129
130
  bool sanitize (hb_sanitize_context_t *c) const
131
0
  {
132
0
    TRACE_SANITIZE (this);
133
0
    return_trace (c->check_struct (this));
134
0
  }
135
136
  protected:
137
  HBUINT16  format;   /* Format identifier — set to 1. */
138
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
139
         * identifying the axis of design variation
140
         * to which the axis value record applies.
141
         * Must be less than designAxisCount. */
142
  HBUINT16  flags;    /* Flags — see below for details. */
143
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
144
         * that provide a display string for this
145
         * attribute value. */
146
  F16DOT16  value;    /* A numeric value for this attribute value. */
147
  public:
148
  DEFINE_SIZE_STATIC (12);
149
};
150
151
struct AxisValueFormat2
152
{
153
0
  unsigned int get_axis_index () const { return axisIndex; }
154
0
  float get_value ()             const { return nominalValue.to_float (); }
155
156
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
157
158
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
159
0
  {
160
0
    unsigned axis_idx = get_axis_index ();
161
0
    return axis_records[axis_idx].get_axis_tag ();
162
0
  }
163
164
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
165
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
166
0
  {
167
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
168
0
    float axis_value = get_value ();
169
0
170
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
171
0
  }
172
173
  bool subset (hb_subset_context_t *c,
174
               const hb_array_t<const StatAxisRecord> axis_records) const
175
0
  {
176
0
    TRACE_SUBSET (this);
177
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
178
0
179
0
    if (keep_axis_value (axis_records, user_axes_location))
180
0
      return_trace (c->serializer->embed (this));
181
0
182
0
    return_trace (false);
183
0
  }
184
185
  bool sanitize (hb_sanitize_context_t *c) const
186
0
  {
187
0
    TRACE_SANITIZE (this);
188
0
    return_trace (c->check_struct (this));
189
0
  }
190
191
  protected:
192
  HBUINT16  format;   /* Format identifier — set to 2. */
193
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
194
         * identifying the axis of design variation
195
         * to which the axis value record applies.
196
         * Must be less than designAxisCount. */
197
  HBUINT16  flags;    /* Flags — see below for details. */
198
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
199
         * that provide a display string for this
200
         * attribute value. */
201
  F16DOT16  nominalValue; /* A numeric value for this attribute value. */
202
  F16DOT16  rangeMinValue;  /* The minimum value for a range associated
203
         * with the specified name ID. */
204
  F16DOT16  rangeMaxValue;  /* The maximum value for a range associated
205
         * with the specified name ID. */
206
  public:
207
  DEFINE_SIZE_STATIC (20);
208
};
209
210
struct AxisValueFormat3
211
{
212
0
  unsigned int get_axis_index () const { return axisIndex; }
213
0
  float get_value ()             const { return value.to_float (); }
214
215
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
216
217
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
218
0
  {
219
0
    unsigned axis_idx = get_axis_index ();
220
0
    return axis_records[axis_idx].get_axis_tag ();
221
0
  }
222
223
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
224
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
225
0
  {
226
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
227
0
    float axis_value = get_value ();
228
0
229
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
230
0
  }
231
232
  bool subset (hb_subset_context_t *c,
233
               const hb_array_t<const StatAxisRecord> axis_records) const
234
0
  {
235
0
    TRACE_SUBSET (this);
236
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
237
0
238
0
    if (keep_axis_value (axis_records, user_axes_location))
239
0
      return_trace (c->serializer->embed (this));
240
0
241
0
    return_trace (false);
242
0
  }
243
244
  bool sanitize (hb_sanitize_context_t *c) const
245
0
  {
246
0
    TRACE_SANITIZE (this);
247
0
    return_trace (c->check_struct (this));
248
0
  }
249
250
  protected:
251
  HBUINT16  format;   /* Format identifier — set to 3. */
252
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
253
         * identifying the axis of design variation
254
         * to which the axis value record applies.
255
         * Must be less than designAxisCount. */
256
  HBUINT16  flags;    /* Flags — see below for details. */
257
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
258
         * that provide a display string for this
259
         * attribute value. */
260
  F16DOT16  value;    /* A numeric value for this attribute value. */
261
  F16DOT16  linkedValue;  /* The numeric value for a style-linked mapping
262
         * from this value. */
263
  public:
264
  DEFINE_SIZE_STATIC (16);
265
};
266
267
struct AxisValueRecord
268
{
269
0
  unsigned int get_axis_index () const { return axisIndex; }
270
0
  float get_value ()             const { return value.to_float (); }
271
272
  bool sanitize (hb_sanitize_context_t *c) const
273
0
  {
274
0
    TRACE_SANITIZE (this);
275
0
    return_trace (c->check_struct (this));
276
0
  }
277
278
  protected:
279
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
280
         * identifying the axis to which this value
281
         * applies. Must be less than designAxisCount. */
282
  F16DOT16  value;    /* A numeric value for this attribute value. */
283
  public:
284
  DEFINE_SIZE_STATIC (6);
285
};
286
287
struct AxisValueFormat4
288
{
289
  const AxisValueRecord &get_axis_record (unsigned int axis_index) const
290
0
  { return axisValues.as_array (axisCount)[axis_index]; }
291
292
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
293
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
294
0
  {
295
0
    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
296
0
297
0
    for (const auto& rec : axis_value_records)
298
0
    {
299
0
      unsigned axis_idx = rec.get_axis_index ();
300
0
      float axis_value = rec.get_value ();
301
0
      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
302
0
303
0
      if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
304
0
        return false;
305
0
    }
306
0
307
0
    return true;
308
0
  }
309
310
  bool subset (hb_subset_context_t *c,
311
               const hb_array_t<const StatAxisRecord> axis_records) const
312
0
  {
313
0
    TRACE_SUBSET (this);
314
0
    const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
315
0
    if (!keep_axis_value (axis_records, user_axes_location))
316
0
      return_trace (false);
317
0
318
0
    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
319
0
    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
320
0
    if (unlikely (!out)) return_trace (false);
321
0
    hb_memcpy (out, this, total_size);
322
0
    return_trace (true);
323
0
  }
324
325
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
326
327
  bool sanitize (hb_sanitize_context_t *c) const
328
0
  {
329
0
    TRACE_SANITIZE (this);
330
0
    return_trace (likely (c->check_struct (this) &&
331
0
        hb_barrier () &&
332
0
                          axisValues.sanitize (c, axisCount)));
333
0
  }
334
335
  protected:
336
  HBUINT16  format;   /* Format identifier — set to 4. */
337
  HBUINT16  axisCount;  /* The total number of axes contributing to
338
         * this axis-values combination. */
339
  HBUINT16  flags;    /* Flags — see below for details. */
340
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
341
         * that provide a display string for this
342
         * attribute value. */
343
  UnsizedArrayOf<AxisValueRecord>
344
    axisValues; /* Array of AxisValue records that provide the
345
         * combination of axis values, one for each
346
         * contributing axis. */
347
  public:
348
  DEFINE_SIZE_ARRAY (8, axisValues);
349
};
350
351
struct AxisValue
352
{
353
  float get_value (unsigned int axis_index) const
354
0
  {
355
0
    switch (u.format)
356
0
    {
357
0
    case 1: hb_barrier (); return u.format1.get_value ();
358
0
    case 2: hb_barrier (); return u.format2.get_value ();
359
0
    case 3: hb_barrier (); return u.format3.get_value ();
360
0
    case 4: hb_barrier (); return u.format4.get_axis_record (axis_index).get_value ();
361
0
    default:return 0.f;
362
0
    }
363
0
  }
364
365
  unsigned int get_axis_index () const
366
0
  {
367
0
    switch (u.format)
368
0
    {
369
0
    case 1: hb_barrier (); return u.format1.get_axis_index ();
370
0
    case 2: hb_barrier (); return u.format2.get_axis_index ();
371
0
    case 3: hb_barrier (); return u.format3.get_axis_index ();
372
0
    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
373
0
    default:return -1;
374
0
    }
375
0
  }
376
377
  hb_ot_name_id_t get_value_name_id () const
378
0
  {
379
0
    switch (u.format)
380
0
    {
381
0
    case 1: hb_barrier (); return u.format1.get_value_name_id ();
382
0
    case 2: hb_barrier (); return u.format2.get_value_name_id ();
383
0
    case 3: hb_barrier (); return u.format3.get_value_name_id ();
384
0
    case 4: hb_barrier (); return u.format4.get_value_name_id ();
385
0
    default:return HB_OT_NAME_ID_INVALID;
386
0
    }
387
0
  }
388
389
  template <typename context_t, typename ...Ts>
390
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
391
0
  {
392
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
393
0
    TRACE_DISPATCH (this, u.format);
394
0
    switch (u.format) {
395
0
    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
396
0
    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
397
0
    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
398
0
    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
399
0
    default:return_trace (c->default_return_value ());
400
0
    }
401
0
  }
402
403
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
404
                        hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
405
0
  {
406
0
    switch (u.format)
407
0
    {
408
0
    case 1: hb_barrier (); return u.format1.keep_axis_value (axis_records, user_axes_location);
409
0
    case 2: hb_barrier (); return u.format2.keep_axis_value (axis_records, user_axes_location);
410
0
    case 3: hb_barrier (); return u.format3.keep_axis_value (axis_records, user_axes_location);
411
0
    case 4: hb_barrier (); return u.format4.keep_axis_value (axis_records, user_axes_location);
412
0
    default:return false;
413
0
    }
414
0
  }
415
416
  bool sanitize (hb_sanitize_context_t *c) const
417
0
  {
418
0
    TRACE_SANITIZE (this);
419
0
    if (unlikely (!c->check_struct (this)))
420
0
      return_trace (false);
421
0
    hb_barrier ();
422
423
0
    switch (u.format)
424
0
    {
425
0
    case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
426
0
    case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
427
0
    case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
428
0
    case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
429
0
    default:return_trace (true);
430
0
    }
431
0
  }
432
433
  protected:
434
  union
435
  {
436
  HBUINT16    format;
437
  AxisValueFormat1  format1;
438
  AxisValueFormat2  format2;
439
  AxisValueFormat3  format3;
440
  AxisValueFormat4  format4;
441
  } u;
442
  public:
443
  DEFINE_SIZE_UNION (2, format);
444
};
445
446
struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
447
{
448
  bool subset (hb_subset_context_t *c,
449
               unsigned axisValueCount,
450
               unsigned& count,
451
               const hb_array_t<const StatAxisRecord> axis_records) const
452
0
  {
453
0
    TRACE_SUBSET (this);
454
0
455
0
    auto axisValueOffsets = as_array (axisValueCount);
456
0
    count = 0;
457
0
    for (const auto& offset : axisValueOffsets)
458
0
    {
459
0
      if (!offset) continue;
460
0
      auto o_snap = c->serializer->snapshot ();
461
0
      auto *o = c->serializer->embed (offset);
462
0
      if (!o) return_trace (false);
463
0
      if (!o->serialize_subset (c, offset, this, axis_records))
464
0
      {
465
0
        c->serializer->revert (o_snap);
466
0
        continue;
467
0
      }
468
0
      count++;
469
0
    }
470
0
471
0
    return_trace (count);
472
0
  }
473
};
474
475
struct STAT
476
{
477
  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
478
479
0
  bool has_data () const { return version.to_int (); }
480
481
  bool get_value (hb_tag_t tag, float *value) const
482
0
  {
483
0
    unsigned int axis_index;
484
0
    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
485
0
486
0
    hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
487
0
    for (unsigned int i = 0; i < axis_values.length; i++)
488
0
    {
489
0
      const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
490
0
      if (axis_value.get_axis_index () == axis_index)
491
0
      {
492
0
  if (value)
493
0
    *value = axis_value.get_value (axis_index);
494
0
  return true;
495
0
      }
496
0
    }
497
0
    return false;
498
0
  }
499
500
0
  unsigned get_design_axis_count () const { return designAxisCount; }
501
502
  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
503
0
  {
504
0
    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
505
0
    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
506
0
    return axis_record.get_name_id ();
507
0
  }
508
509
0
  unsigned get_axis_value_count () const { return axisValueCount; }
510
511
  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
512
0
  {
513
0
    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
514
0
    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
515
0
    return axis_value.get_value_name_id ();
516
0
  }
517
518
  void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
519
                         hb_set_t *nameids_to_retain /* OUT */) const
520
0
  {
521
0
    if (!has_data ()) return;
522
0
523
0
    + get_design_axes ()
524
0
    | hb_map (&StatAxisRecord::get_name_id)
525
0
    | hb_sink (nameids_to_retain)
526
0
    ;
527
0
528
0
    auto designAxes = get_design_axes ();
529
0
530
0
    + get_axis_value_offsets ()
531
0
    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
532
0
    | hb_filter ([&] (const AxisValue& _)
533
0
                 { return _.keep_axis_value (designAxes, user_axes_location); })
534
0
    | hb_map (&AxisValue::get_value_name_id)
535
0
    | hb_sink (nameids_to_retain)
536
0
    ;
537
0
538
0
    nameids_to_retain->add (elidedFallbackNameID);
539
0
  }
540
541
  bool subset (hb_subset_context_t *c) const
542
0
  {
543
0
    TRACE_SUBSET (this);
544
0
    STAT *out = c->serializer->embed (this);
545
0
    if (unlikely (!out)) return_trace (false);
546
0
547
0
    auto designAxes = get_design_axes ();
548
0
    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
549
0
      if (unlikely (!c->serializer->embed (designAxes[i])))
550
0
          return_trace (false);
551
0
552
0
    if (designAxisCount)
553
0
      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
554
0
                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
555
0
556
0
    unsigned count = 0;
557
0
    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
558
0
                                                    axisValueCount, count, designAxes);
559
0
    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
560
0
  }
561
562
  bool sanitize (hb_sanitize_context_t *c) const
563
0
  {
564
0
    TRACE_SANITIZE (this);
565
0
    return_trace (likely (c->check_struct (this) &&
566
0
        hb_barrier () &&
567
0
        version.major == 1 &&
568
0
        version.minor > 0 &&
569
0
        designAxesOffset.sanitize (c, this, designAxisCount) &&
570
0
        offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
571
0
  }
572
573
  protected:
574
  hb_array_t<const StatAxisRecord> const get_design_axes () const
575
0
  { return (this+designAxesOffset).as_array (designAxisCount); }
576
577
  hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
578
0
  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
579
580
581
  protected:
582
  FixedVersion<>version;  /* Version of the stat table
583
         * initially set to 0x00010002u */
584
  HBUINT16  designAxisSize; /* The size in bytes of each axis record. */
585
  HBUINT16  designAxisCount;/* The number of design axis records. In a
586
         * font with an 'fvar' table, this value must be
587
         * greater than or equal to the axisCount value
588
         * in the 'fvar' table. In all fonts, must
589
         * be greater than zero if axisValueCount
590
         * is greater than zero. */
591
  NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
592
    designAxesOffset;
593
        /* Offset in bytes from the beginning of
594
         * the STAT table to the start of the design
595
         * axes array. If designAxisCount is zero,
596
         * set to zero; if designAxisCount is greater
597
         * than zero, must be greater than zero. */
598
  HBUINT16  axisValueCount; /* The number of axis value tables. */
599
  NNOffset32To<AxisValueOffsetArray>
600
    offsetToAxisValueOffsets;
601
        /* Offset in bytes from the beginning of
602
         * the STAT table to the start of the design
603
         * axes value offsets array. If axisValueCount
604
         * is zero, set to zero; if axisValueCount is
605
         * greater than zero, must be greater than zero. */
606
  NameID  elidedFallbackNameID;
607
        /* Name ID used as fallback when projection of
608
         * names into a particular font model produces
609
         * a subfamily name containing only elidable
610
         * elements. */
611
  public:
612
  DEFINE_SIZE_STATIC (20);
613
};
614
615
616
} /* namespace OT */
617
618
619
#endif /* HB_OT_STAT_TABLE_HH */