Coverage Report

Created: 2025-12-31 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pango/subprojects/harfbuzz/src/hb-ot-stat-table.hh
Line
Count
Source
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
  Triple axis_range = user_axes_location->get (axis_tag);
67
0
  return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
68
0
}
69
70
struct StatAxisRecord
71
{
72
0
  int cmp (hb_tag_t key) const { return tag.cmp (key); }
73
74
0
  hb_ot_name_id_t get_name_id () const { return nameID; }
75
76
0
  hb_tag_t get_axis_tag () const { return tag; }
77
78
  bool sanitize (hb_sanitize_context_t *c) const
79
0
  {
80
0
    TRACE_SANITIZE (this);
81
0
    return_trace (likely (c->check_struct (this)));
82
0
  }
83
84
  protected:
85
  Tag   tag;    /* A tag identifying the axis of design variation. */
86
  NameID  nameID;   /* The name ID for entries in the 'name' table that
87
         * provide a display string for this axis. */
88
  HBUINT16  ordering; /* A value that applications can use to determine
89
         * primary sorting of face names, or for ordering
90
         * of descriptors when composing family or face names. */
91
  public:
92
  DEFINE_SIZE_STATIC (8);
93
};
94
95
struct AxisValueFormat1
96
{
97
0
  unsigned int get_axis_index () const { return axisIndex; }
98
0
  float get_value ()             const { return value.to_float (); }
99
100
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
101
102
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
103
0
  {
104
0
    unsigned axis_idx = get_axis_index ();
105
0
    return axis_records[axis_idx].get_axis_tag ();
106
0
  }
107
108
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
109
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
110
0
  {
111
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
112
0
    float axis_value = get_value ();
113
0
114
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
115
0
  }
116
117
  bool subset (hb_subset_context_t *c,
118
               const hb_array_t<const StatAxisRecord> axis_records) const
119
0
  {
120
0
    TRACE_SUBSET (this);
121
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
122
0
123
0
    if (keep_axis_value (axis_records, user_axes_location))
124
0
      return_trace (c->serializer->embed (this));
125
0
126
0
    return_trace (false);
127
0
  }
128
129
  bool sanitize (hb_sanitize_context_t *c) const
130
0
  {
131
0
    TRACE_SANITIZE (this);
132
0
    return_trace (c->check_struct (this));
133
0
  }
134
135
  protected:
136
  HBUINT16  format;   /* Format identifier — set to 1. */
137
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
138
         * identifying the axis of design variation
139
         * to which the axis value record applies.
140
         * Must be less than designAxisCount. */
141
  HBUINT16  flags;    /* Flags — see below for details. */
142
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
143
         * that provide a display string for this
144
         * attribute value. */
145
  F16DOT16  value;    /* A numeric value for this attribute value. */
146
  public:
147
  DEFINE_SIZE_STATIC (12);
148
};
149
150
struct AxisValueFormat2
151
{
152
0
  unsigned int get_axis_index () const { return axisIndex; }
153
0
  float get_value ()             const { return nominalValue.to_float (); }
154
155
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
156
157
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
158
0
  {
159
0
    unsigned axis_idx = get_axis_index ();
160
0
    return axis_records[axis_idx].get_axis_tag ();
161
0
  }
162
163
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
164
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
165
0
  {
166
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
167
0
    float axis_value = get_value ();
168
0
169
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
170
0
  }
171
172
  bool subset (hb_subset_context_t *c,
173
               const hb_array_t<const StatAxisRecord> axis_records) const
174
0
  {
175
0
    TRACE_SUBSET (this);
176
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
177
0
178
0
    if (keep_axis_value (axis_records, user_axes_location))
179
0
      return_trace (c->serializer->embed (this));
180
0
181
0
    return_trace (false);
182
0
  }
183
184
  bool sanitize (hb_sanitize_context_t *c) const
185
0
  {
186
0
    TRACE_SANITIZE (this);
187
0
    return_trace (c->check_struct (this));
188
0
  }
189
190
  protected:
191
  HBUINT16  format;   /* Format identifier — set to 2. */
192
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
193
         * identifying the axis of design variation
194
         * to which the axis value record applies.
195
         * Must be less than designAxisCount. */
196
  HBUINT16  flags;    /* Flags — see below for details. */
197
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
198
         * that provide a display string for this
199
         * attribute value. */
200
  F16DOT16  nominalValue; /* A numeric value for this attribute value. */
201
  F16DOT16  rangeMinValue;  /* The minimum value for a range associated
202
         * with the specified name ID. */
203
  F16DOT16  rangeMaxValue;  /* The maximum value for a range associated
204
         * with the specified name ID. */
205
  public:
206
  DEFINE_SIZE_STATIC (20);
207
};
208
209
struct AxisValueFormat3
210
{
211
0
  unsigned int get_axis_index () const { return axisIndex; }
212
0
  float get_value ()             const { return value.to_float (); }
213
214
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
215
216
  hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
217
0
  {
218
0
    unsigned axis_idx = get_axis_index ();
219
0
    return axis_records[axis_idx].get_axis_tag ();
220
0
  }
221
222
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
223
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
224
0
  {
225
0
    hb_tag_t axis_tag = get_axis_tag (axis_records);
226
0
    float axis_value = get_value ();
227
0
228
0
    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
229
0
  }
230
231
  bool subset (hb_subset_context_t *c,
232
               const hb_array_t<const StatAxisRecord> axis_records) const
233
0
  {
234
0
    TRACE_SUBSET (this);
235
0
    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
236
0
237
0
    if (keep_axis_value (axis_records, user_axes_location))
238
0
      return_trace (c->serializer->embed (this));
239
0
240
0
    return_trace (false);
241
0
  }
242
243
  bool sanitize (hb_sanitize_context_t *c) const
244
0
  {
245
0
    TRACE_SANITIZE (this);
246
0
    return_trace (c->check_struct (this));
247
0
  }
248
249
  protected:
250
  HBUINT16  format;   /* Format identifier — set to 3. */
251
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
252
         * identifying the axis of design variation
253
         * to which the axis value record applies.
254
         * Must be less than designAxisCount. */
255
  HBUINT16  flags;    /* Flags — see below for details. */
256
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
257
         * that provide a display string for this
258
         * attribute value. */
259
  F16DOT16  value;    /* A numeric value for this attribute value. */
260
  F16DOT16  linkedValue;  /* The numeric value for a style-linked mapping
261
         * from this value. */
262
  public:
263
  DEFINE_SIZE_STATIC (16);
264
};
265
266
struct AxisValueRecord
267
{
268
0
  unsigned int get_axis_index () const { return axisIndex; }
269
0
  float get_value ()             const { return value.to_float (); }
270
271
  bool sanitize (hb_sanitize_context_t *c) const
272
0
  {
273
0
    TRACE_SANITIZE (this);
274
0
    return_trace (c->check_struct (this));
275
0
  }
276
277
  protected:
278
  HBUINT16  axisIndex;  /* Zero-base index into the axis record array
279
         * identifying the axis to which this value
280
         * applies. Must be less than designAxisCount. */
281
  F16DOT16  value;    /* A numeric value for this attribute value. */
282
  public:
283
  DEFINE_SIZE_STATIC (6);
284
};
285
286
struct AxisValueFormat4
287
{
288
  const AxisValueRecord &get_axis_record (unsigned int axis_index) const
289
0
  { return axisValues.as_array (axisCount)[axis_index]; }
290
291
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
292
                        const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
293
0
  {
294
0
    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
295
0
296
0
    for (const auto& rec : axis_value_records)
297
0
    {
298
0
      unsigned axis_idx = rec.get_axis_index ();
299
0
      float axis_value = rec.get_value ();
300
0
      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
301
0
302
0
      if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
303
0
        return false;
304
0
    }
305
0
306
0
    return true;
307
0
  }
308
309
  bool subset (hb_subset_context_t *c,
310
               const hb_array_t<const StatAxisRecord> axis_records) const
311
0
  {
312
0
    TRACE_SUBSET (this);
313
0
    const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
314
0
    if (!keep_axis_value (axis_records, user_axes_location))
315
0
      return_trace (false);
316
0
317
0
    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
318
0
    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
319
0
    if (unlikely (!out)) return_trace (false);
320
0
    hb_memcpy (out, this, total_size);
321
0
    return_trace (true);
322
0
  }
323
324
0
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
325
326
  bool sanitize (hb_sanitize_context_t *c) const
327
0
  {
328
0
    TRACE_SANITIZE (this);
329
0
    return_trace (likely (c->check_struct (this) &&
330
0
        hb_barrier () &&
331
0
                          axisValues.sanitize (c, axisCount)));
332
0
  }
333
334
  protected:
335
  HBUINT16  format;   /* Format identifier — set to 4. */
336
  HBUINT16  axisCount;  /* The total number of axes contributing to
337
         * this axis-values combination. */
338
  HBUINT16  flags;    /* Flags — see below for details. */
339
  NameID  valueNameID;  /* The name ID for entries in the 'name' table
340
         * that provide a display string for this
341
         * attribute value. */
342
  UnsizedArrayOf<AxisValueRecord>
343
    axisValues; /* Array of AxisValue records that provide the
344
         * combination of axis values, one for each
345
         * contributing axis. */
346
  public:
347
  DEFINE_SIZE_ARRAY (8, axisValues);
348
};
349
350
struct AxisValue
351
{
352
  float get_value (unsigned int axis_index) const
353
0
  {
354
0
    switch (u.format)
355
0
    {
356
0
    case 1: return u.format1.get_value ();
357
0
    case 2: return u.format2.get_value ();
358
0
    case 3: return u.format3.get_value ();
359
0
    case 4: return u.format4.get_axis_record (axis_index).get_value ();
360
0
    default:return 0.f;
361
0
    }
362
0
  }
363
364
  unsigned int get_axis_index () const
365
0
  {
366
0
    switch (u.format)
367
0
    {
368
0
    case 1: return u.format1.get_axis_index ();
369
0
    case 2: return u.format2.get_axis_index ();
370
0
    case 3: return u.format3.get_axis_index ();
371
0
    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
372
0
    default:return -1;
373
0
    }
374
0
  }
375
376
  hb_ot_name_id_t get_value_name_id () const
377
0
  {
378
0
    switch (u.format)
379
0
    {
380
0
    case 1: return u.format1.get_value_name_id ();
381
0
    case 2: return u.format2.get_value_name_id ();
382
0
    case 3: return u.format3.get_value_name_id ();
383
0
    case 4: return u.format4.get_value_name_id ();
384
0
    default:return HB_OT_NAME_ID_INVALID;
385
0
    }
386
0
  }
387
388
  template <typename context_t, typename ...Ts>
389
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
390
0
  {
391
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
392
0
    TRACE_DISPATCH (this, u.format);
393
0
    switch (u.format) {
394
0
    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
395
0
    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
396
0
    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
397
0
    case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
398
0
    default:return_trace (c->default_return_value ());
399
0
    }
400
0
  }
401
402
  bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
403
                        hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
404
0
  {
405
0
    switch (u.format)
406
0
    {
407
0
    case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
408
0
    case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
409
0
    case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
410
0
    case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
411
0
    default:return false;
412
0
    }
413
0
  }
414
415
  bool sanitize (hb_sanitize_context_t *c) const
416
0
  {
417
0
    TRACE_SANITIZE (this);
418
0
    if (unlikely (!c->check_struct (this)))
419
0
      return_trace (false);
420
0
    hb_barrier ();
421
0
422
0
    switch (u.format)
423
0
    {
424
0
    case 1: return_trace (u.format1.sanitize (c));
425
0
    case 2: return_trace (u.format2.sanitize (c));
426
0
    case 3: return_trace (u.format3.sanitize (c));
427
0
    case 4: return_trace (u.format4.sanitize (c));
428
0
    default:return_trace (true);
429
0
    }
430
0
  }
431
432
  protected:
433
  union
434
  {
435
  HBUINT16    format;
436
  AxisValueFormat1  format1;
437
  AxisValueFormat2  format2;
438
  AxisValueFormat3  format3;
439
  AxisValueFormat4  format4;
440
  } u;
441
  public:
442
  DEFINE_SIZE_UNION (2, format);
443
};
444
445
struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
446
{
447
  bool subset (hb_subset_context_t *c,
448
               unsigned axisValueCount,
449
               unsigned& count,
450
               const hb_array_t<const StatAxisRecord> axis_records) const
451
0
  {
452
0
    TRACE_SUBSET (this);
453
0
454
0
    auto axisValueOffsets = as_array (axisValueCount);
455
0
    count = 0;
456
0
    for (const auto& offset : axisValueOffsets)
457
0
    {
458
0
      if (!offset) continue;
459
0
      auto o_snap = c->serializer->snapshot ();
460
0
      auto *o = c->serializer->embed (offset);
461
0
      if (!o) return_trace (false);
462
0
      if (!o->serialize_subset (c, offset, this, axis_records))
463
0
      {
464
0
        c->serializer->revert (o_snap);
465
0
        continue;
466
0
      }
467
0
      count++;
468
0
    }
469
0
470
0
    return_trace (count);
471
0
  }
472
};
473
474
struct STAT
475
{
476
  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
477
478
0
  bool has_data () const { return version.to_int (); }
479
480
  bool get_value (hb_tag_t tag, float *value) const
481
0
  {
482
0
    unsigned int axis_index;
483
0
    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
484
0
485
0
    hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
486
0
    for (unsigned int i = 0; i < axis_values.length; i++)
487
0
    {
488
0
      const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
489
0
      if (axis_value.get_axis_index () == axis_index)
490
0
      {
491
0
  if (value)
492
0
    *value = axis_value.get_value (axis_index);
493
0
  return true;
494
0
      }
495
0
    }
496
0
    return false;
497
0
  }
498
499
0
  unsigned get_design_axis_count () const { return designAxisCount; }
500
501
  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
502
0
  {
503
0
    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
504
0
    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
505
0
    return axis_record.get_name_id ();
506
0
  }
507
508
0
  unsigned get_axis_value_count () const { return axisValueCount; }
509
510
  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
511
0
  {
512
0
    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
513
0
    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
514
0
    return axis_value.get_value_name_id ();
515
0
  }
516
517
  void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
518
                         hb_set_t *nameids_to_retain /* OUT */) const
519
0
  {
520
0
    if (!has_data ()) return;
521
0
522
0
    + get_design_axes ()
523
0
    | hb_map (&StatAxisRecord::get_name_id)
524
0
    | hb_sink (nameids_to_retain)
525
0
    ;
526
0
527
0
    auto designAxes = get_design_axes ();
528
0
529
0
    + get_axis_value_offsets ()
530
0
    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
531
0
    | hb_filter ([&] (const AxisValue& _)
532
0
                 { return _.keep_axis_value (designAxes, user_axes_location); })
533
0
    | hb_map (&AxisValue::get_value_name_id)
534
0
    | hb_sink (nameids_to_retain)
535
0
    ;
536
0
537
0
    nameids_to_retain->add (elidedFallbackNameID);
538
0
  }
539
540
  bool subset (hb_subset_context_t *c) const
541
0
  {
542
0
    TRACE_SUBSET (this);
543
0
    STAT *out = c->serializer->embed (this);
544
0
    if (unlikely (!out)) return_trace (false);
545
0
546
0
    auto designAxes = get_design_axes ();
547
0
    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
548
0
      if (unlikely (!c->serializer->embed (designAxes[i])))
549
0
          return_trace (false);
550
0
551
0
    if (designAxisCount)
552
0
      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
553
0
                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
554
0
555
0
    unsigned count = 0;
556
0
    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
557
0
                                                    axisValueCount, count, designAxes);
558
0
    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
559
0
  }
560
561
  bool sanitize (hb_sanitize_context_t *c) const
562
0
  {
563
0
    TRACE_SANITIZE (this);
564
0
    return_trace (likely (c->check_struct (this) &&
565
0
        hb_barrier () &&
566
0
        version.major == 1 &&
567
0
        version.minor > 0 &&
568
0
        designAxesOffset.sanitize (c, this, designAxisCount) &&
569
0
        offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
570
0
  }
571
572
  protected:
573
  hb_array_t<const StatAxisRecord> const get_design_axes () const
574
0
  { return (this+designAxesOffset).as_array (designAxisCount); }
575
576
  hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
577
0
  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
578
579
580
  protected:
581
  FixedVersion<>version;  /* Version of the stat table
582
         * initially set to 0x00010002u */
583
  HBUINT16  designAxisSize; /* The size in bytes of each axis record. */
584
  HBUINT16  designAxisCount;/* The number of design axis records. In a
585
         * font with an 'fvar' table, this value must be
586
         * greater than or equal to the axisCount value
587
         * in the 'fvar' table. In all fonts, must
588
         * be greater than zero if axisValueCount
589
         * is greater than zero. */
590
  NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
591
    designAxesOffset;
592
        /* Offset in bytes from the beginning of
593
         * the STAT table to the start of the design
594
         * axes array. If designAxisCount is zero,
595
         * set to zero; if designAxisCount is greater
596
         * than zero, must be greater than zero. */
597
  HBUINT16  axisValueCount; /* The number of axis value tables. */
598
  NNOffset32To<AxisValueOffsetArray>
599
    offsetToAxisValueOffsets;
600
        /* Offset in bytes from the beginning of
601
         * the STAT table to the start of the design
602
         * axes value offsets array. If axisValueCount
603
         * is zero, set to zero; if axisValueCount is
604
         * greater than zero, must be greater than zero. */
605
  NameID  elidedFallbackNameID;
606
        /* Name ID used as fallback when projection of
607
         * names into a particular font model produces
608
         * a subfamily name containing only elidable
609
         * elements. */
610
  public:
611
  DEFINE_SIZE_STATIC (20);
612
};
613
614
615
} /* namespace OT */
616
617
618
#endif /* HB_OT_STAT_TABLE_HH */