tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-ot-stat-table.hh (21222B)


      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 {
     63  if (!user_axes_location->has (axis_tag))
     64    return false;
     65 
     66  double axis_value_double = static_cast<double>(axis_value);
     67  Triple axis_range = user_axes_location->get (axis_tag);
     68  return (axis_value_double < axis_range.minimum || axis_value_double > axis_range.maximum);
     69 }
     70 
     71 struct StatAxisRecord
     72 {
     73  int cmp (hb_tag_t key) const { return tag.cmp (key); }
     74 
     75  hb_ot_name_id_t get_name_id () const { return nameID; }
     76 
     77  hb_tag_t get_axis_tag () const { return tag; }
     78 
     79  bool sanitize (hb_sanitize_context_t *c) const
     80  {
     81    TRACE_SANITIZE (this);
     82    return_trace (likely (c->check_struct (this)));
     83  }
     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  unsigned int get_axis_index () const { return axisIndex; }
     99  float get_value ()             const { return value.to_float (); }
    100 
    101  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  {
    105    unsigned axis_idx = get_axis_index ();
    106    return axis_records[axis_idx].get_axis_tag ();
    107  }
    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  {
    112    hb_tag_t axis_tag = get_axis_tag (axis_records);
    113    float axis_value = get_value ();
    114 
    115    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
    116  }
    117 
    118  bool subset (hb_subset_context_t *c,
    119               const hb_array_t<const StatAxisRecord> axis_records) const
    120  {
    121    TRACE_SUBSET (this);
    122    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
    123 
    124    if (keep_axis_value (axis_records, user_axes_location))
    125      return_trace (c->serializer->embed (this));
    126 
    127    return_trace (false);
    128  }
    129 
    130  bool sanitize (hb_sanitize_context_t *c) const
    131  {
    132    TRACE_SANITIZE (this);
    133    return_trace (c->check_struct (this));
    134  }
    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  unsigned int get_axis_index () const { return axisIndex; }
    154  float get_value ()             const { return nominalValue.to_float (); }
    155 
    156  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  {
    160    unsigned axis_idx = get_axis_index ();
    161    return axis_records[axis_idx].get_axis_tag ();
    162  }
    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  {
    167    hb_tag_t axis_tag = get_axis_tag (axis_records);
    168    float axis_value = get_value ();
    169 
    170    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
    171  }
    172 
    173  bool subset (hb_subset_context_t *c,
    174               const hb_array_t<const StatAxisRecord> axis_records) const
    175  {
    176    TRACE_SUBSET (this);
    177    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
    178 
    179    if (keep_axis_value (axis_records, user_axes_location))
    180      return_trace (c->serializer->embed (this));
    181 
    182    return_trace (false);
    183  }
    184 
    185  bool sanitize (hb_sanitize_context_t *c) const
    186  {
    187    TRACE_SANITIZE (this);
    188    return_trace (c->check_struct (this));
    189  }
    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  unsigned int get_axis_index () const { return axisIndex; }
    213  float get_value ()             const { return value.to_float (); }
    214 
    215  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  {
    219    unsigned axis_idx = get_axis_index ();
    220    return axis_records[axis_idx].get_axis_tag ();
    221  }
    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  {
    226    hb_tag_t axis_tag = get_axis_tag (axis_records);
    227    float axis_value = get_value ();
    228 
    229    return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
    230  }
    231 
    232  bool subset (hb_subset_context_t *c,
    233               const hb_array_t<const StatAxisRecord> axis_records) const
    234  {
    235    TRACE_SUBSET (this);
    236    const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
    237 
    238    if (keep_axis_value (axis_records, user_axes_location))
    239      return_trace (c->serializer->embed (this));
    240 
    241    return_trace (false);
    242  }
    243 
    244  bool sanitize (hb_sanitize_context_t *c) const
    245  {
    246    TRACE_SANITIZE (this);
    247    return_trace (c->check_struct (this));
    248  }
    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  unsigned int get_axis_index () const { return axisIndex; }
    270  float get_value ()             const { return value.to_float (); }
    271 
    272  bool sanitize (hb_sanitize_context_t *c) const
    273  {
    274    TRACE_SANITIZE (this);
    275    return_trace (c->check_struct (this));
    276  }
    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  { 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  {
    295    hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
    296 
    297    for (const auto& rec : axis_value_records)
    298    {
    299      unsigned axis_idx = rec.get_axis_index ();
    300      float axis_value = rec.get_value ();
    301      hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
    302 
    303      if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
    304        return false;
    305    }
    306 
    307    return true;
    308  }
    309 
    310  bool subset (hb_subset_context_t *c,
    311               const hb_array_t<const StatAxisRecord> axis_records) const
    312  {
    313    TRACE_SUBSET (this);
    314    const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
    315    if (!keep_axis_value (axis_records, user_axes_location))
    316      return_trace (false);
    317 
    318    unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
    319    auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
    320    if (unlikely (!out)) return_trace (false);
    321    hb_memcpy (out, this, total_size);
    322    return_trace (true);
    323  }
    324 
    325  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
    326 
    327  bool sanitize (hb_sanitize_context_t *c) const
    328  {
    329    TRACE_SANITIZE (this);
    330    return_trace (likely (c->check_struct (this) &&
    331 		  hb_barrier () &&
    332                          axisValues.sanitize (c, axisCount)));
    333  }
    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  {
    355    switch (u.format.v)
    356    {
    357    case 1: hb_barrier (); return u.format1.get_value ();
    358    case 2: hb_barrier (); return u.format2.get_value ();
    359    case 3: hb_barrier (); return u.format3.get_value ();
    360    case 4: hb_barrier (); return u.format4.get_axis_record (axis_index).get_value ();
    361    default:return 0.f;
    362    }
    363  }
    364 
    365  unsigned int get_axis_index () const
    366  {
    367    switch (u.format.v)
    368    {
    369    case 1: hb_barrier (); return u.format1.get_axis_index ();
    370    case 2: hb_barrier (); return u.format2.get_axis_index ();
    371    case 3: hb_barrier (); return u.format3.get_axis_index ();
    372    /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
    373    default:return -1;
    374    }
    375  }
    376 
    377  hb_ot_name_id_t get_value_name_id () const
    378  {
    379    switch (u.format.v)
    380    {
    381    case 1: hb_barrier (); return u.format1.get_value_name_id ();
    382    case 2: hb_barrier (); return u.format2.get_value_name_id ();
    383    case 3: hb_barrier (); return u.format3.get_value_name_id ();
    384    case 4: hb_barrier (); return u.format4.get_value_name_id ();
    385    default:return HB_OT_NAME_ID_INVALID;
    386    }
    387  }
    388 
    389  template <typename context_t, typename ...Ts>
    390  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
    391  {
    392    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
    393    TRACE_DISPATCH (this, u.format.v);
    394    switch (u.format.v) {
    395    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
    396    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
    397    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
    398    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
    399    default:return_trace (c->default_return_value ());
    400    }
    401  }
    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  {
    406    switch (u.format.v)
    407    {
    408    case 1: hb_barrier (); return u.format1.keep_axis_value (axis_records, user_axes_location);
    409    case 2: hb_barrier (); return u.format2.keep_axis_value (axis_records, user_axes_location);
    410    case 3: hb_barrier (); return u.format3.keep_axis_value (axis_records, user_axes_location);
    411    case 4: hb_barrier (); return u.format4.keep_axis_value (axis_records, user_axes_location);
    412    default:return false;
    413    }
    414  }
    415 
    416  bool sanitize (hb_sanitize_context_t *c) const
    417  {
    418    TRACE_SANITIZE (this);
    419    if (unlikely (!c->check_struct (this)))
    420      return_trace (false);
    421    hb_barrier ();
    422 
    423    switch (u.format.v)
    424    {
    425    case 1: hb_barrier (); return_trace (u.format1.sanitize (c));
    426    case 2: hb_barrier (); return_trace (u.format2.sanitize (c));
    427    case 3: hb_barrier (); return_trace (u.format3.sanitize (c));
    428    case 4: hb_barrier (); return_trace (u.format4.sanitize (c));
    429    default:return_trace (true);
    430    }
    431  }
    432 
    433  protected:
    434  union
    435  {
    436  struct { HBUINT16 v; }	format;
    437  AxisValueFormat1	format1;
    438  AxisValueFormat2	format2;
    439  AxisValueFormat3	format3;
    440  AxisValueFormat4	format4;
    441  } u;
    442  public:
    443  DEFINE_SIZE_UNION (2, format.v);
    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  {
    453    TRACE_SUBSET (this);
    454 
    455    auto axisValueOffsets = as_array (axisValueCount);
    456    count = 0;
    457    for (const auto& offset : axisValueOffsets)
    458    {
    459      if (!offset) continue;
    460      auto o_snap = c->serializer->snapshot ();
    461      auto *o = c->serializer->embed (offset);
    462      if (!o) return_trace (false);
    463      if (!o->serialize_subset (c, offset, this, axis_records))
    464      {
    465        c->serializer->revert (o_snap);
    466        continue;
    467      }
    468      count++;
    469    }
    470 
    471    return_trace (count);
    472  }
    473 };
    474 
    475 struct STAT
    476 {
    477  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
    478 
    479  bool has_data () const { return version.to_int (); }
    480 
    481  bool get_value (hb_tag_t tag, float *value) const
    482  {
    483    unsigned int axis_index;
    484    if (!get_design_axes ().lfind (tag, &axis_index)) return false;
    485 
    486    hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
    487    for (unsigned int i = 0; i < axis_values.length; i++)
    488    {
    489      const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
    490      if (axis_value.get_axis_index () == axis_index)
    491      {
    492 if (value)
    493   *value = axis_value.get_value (axis_index);
    494 return true;
    495      }
    496    }
    497    return false;
    498  }
    499 
    500  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  {
    504    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
    505    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
    506    return axis_record.get_name_id ();
    507  }
    508 
    509  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  {
    513    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
    514    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
    515    return axis_value.get_value_name_id ();
    516  }
    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  {
    521    if (!has_data ()) return;
    522 
    523    + get_design_axes ()
    524    | hb_map (&StatAxisRecord::get_name_id)
    525    | hb_sink (nameids_to_retain)
    526    ;
    527 
    528    auto designAxes = get_design_axes ();
    529 
    530    + get_axis_value_offsets ()
    531    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
    532    | hb_filter ([&] (const AxisValue& _)
    533                 { return _.keep_axis_value (designAxes, user_axes_location); })
    534    | hb_map (&AxisValue::get_value_name_id)
    535    | hb_sink (nameids_to_retain)
    536    ;
    537 
    538    nameids_to_retain->add (elidedFallbackNameID);
    539  }
    540 
    541  bool subset (hb_subset_context_t *c) const
    542  {
    543    TRACE_SUBSET (this);
    544    STAT *out = c->serializer->embed (this);
    545    if (unlikely (!out)) return_trace (false);
    546 
    547    auto designAxes = get_design_axes ();
    548    for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
    549      if (unlikely (!c->serializer->embed (designAxes[i])))
    550          return_trace (false);
    551 
    552    if (designAxisCount)
    553      c->serializer->check_assign (out->designAxesOffset, this->get_size (),
    554                                   HB_SERIALIZE_ERROR_INT_OVERFLOW);
    555 
    556    unsigned count = 0;
    557    out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
    558                                                    axisValueCount, count, designAxes);
    559    return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
    560  }
    561 
    562  bool sanitize (hb_sanitize_context_t *c) const
    563  {
    564    TRACE_SANITIZE (this);
    565    return_trace (likely (c->check_struct (this) &&
    566 		  hb_barrier () &&
    567 		  version.major == 1 &&
    568 		  version.minor > 0 &&
    569 		  designAxesOffset.sanitize (c, this, designAxisCount) &&
    570 		  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
    571  }
    572 
    573  protected:
    574  hb_array_t<const StatAxisRecord> const get_design_axes () const
    575  { return (this+designAxesOffset).as_array (designAxisCount); }
    576 
    577  hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
    578  { 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 */