• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
axis_value_is_outside_axis_range(hb_tag_t axis_tag,float axis_value,const hb_hashmap_t<hb_tag_t,Triple> * user_axes_location)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   Triple axis_range = user_axes_location->get (axis_tag);
67   return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
68 }
69 
70 struct StatAxisRecord
71 {
cmpOT::StatAxisRecord72   int cmp (hb_tag_t key) const { return tag.cmp (key); }
73 
get_name_idOT::StatAxisRecord74   hb_ot_name_id_t get_name_id () const { return nameID; }
75 
get_axis_tagOT::StatAxisRecord76   hb_tag_t get_axis_tag () const { return tag; }
77 
sanitizeOT::StatAxisRecord78   bool sanitize (hb_sanitize_context_t *c) const
79   {
80     TRACE_SANITIZE (this);
81     return_trace (likely (c->check_struct (this)));
82   }
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 {
get_axis_indexOT::AxisValueFormat197   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat198   float get_value ()             const { return value.to_float (); }
99 
get_value_name_idOT::AxisValueFormat1100   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
101 
get_axis_tagOT::AxisValueFormat1102   hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
103   {
104     unsigned axis_idx = get_axis_index ();
105     return axis_records[axis_idx].get_axis_tag ();
106   }
107 
keep_axis_valueOT::AxisValueFormat1108   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   {
111     hb_tag_t axis_tag = get_axis_tag (axis_records);
112     float axis_value = get_value ();
113 
114     return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
115   }
116 
subsetOT::AxisValueFormat1117   bool subset (hb_subset_context_t *c,
118                const hb_array_t<const StatAxisRecord> axis_records) const
119   {
120     TRACE_SUBSET (this);
121     const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
122 
123     if (keep_axis_value (axis_records, user_axes_location))
124       return_trace (c->serializer->embed (this));
125 
126     return_trace (false);
127   }
128 
sanitizeOT::AxisValueFormat1129   bool sanitize (hb_sanitize_context_t *c) const
130   {
131     TRACE_SANITIZE (this);
132     return_trace (c->check_struct (this));
133   }
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 {
get_axis_indexOT::AxisValueFormat2152   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat2153   float get_value ()             const { return nominalValue.to_float (); }
154 
get_value_name_idOT::AxisValueFormat2155   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
156 
get_axis_tagOT::AxisValueFormat2157   hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
158   {
159     unsigned axis_idx = get_axis_index ();
160     return axis_records[axis_idx].get_axis_tag ();
161   }
162 
keep_axis_valueOT::AxisValueFormat2163   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   {
166     hb_tag_t axis_tag = get_axis_tag (axis_records);
167     float axis_value = get_value ();
168 
169     return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
170   }
171 
subsetOT::AxisValueFormat2172   bool subset (hb_subset_context_t *c,
173                const hb_array_t<const StatAxisRecord> axis_records) const
174   {
175     TRACE_SUBSET (this);
176     const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
177 
178     if (keep_axis_value (axis_records, user_axes_location))
179       return_trace (c->serializer->embed (this));
180 
181     return_trace (false);
182   }
183 
sanitizeOT::AxisValueFormat2184   bool sanitize (hb_sanitize_context_t *c) const
185   {
186     TRACE_SANITIZE (this);
187     return_trace (c->check_struct (this));
188   }
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 {
get_axis_indexOT::AxisValueFormat3211   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat3212   float get_value ()             const { return value.to_float (); }
213 
get_value_name_idOT::AxisValueFormat3214   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
215 
get_axis_tagOT::AxisValueFormat3216   hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const
217   {
218     unsigned axis_idx = get_axis_index ();
219     return axis_records[axis_idx].get_axis_tag ();
220   }
221 
keep_axis_valueOT::AxisValueFormat3222   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   {
225     hb_tag_t axis_tag = get_axis_tag (axis_records);
226     float axis_value = get_value ();
227 
228     return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
229   }
230 
subsetOT::AxisValueFormat3231   bool subset (hb_subset_context_t *c,
232                const hb_array_t<const StatAxisRecord> axis_records) const
233   {
234     TRACE_SUBSET (this);
235     const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
236 
237     if (keep_axis_value (axis_records, user_axes_location))
238       return_trace (c->serializer->embed (this));
239 
240     return_trace (false);
241   }
242 
sanitizeOT::AxisValueFormat3243   bool sanitize (hb_sanitize_context_t *c) const
244   {
245     TRACE_SANITIZE (this);
246     return_trace (c->check_struct (this));
247   }
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 {
get_axis_indexOT::AxisValueRecord268   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueRecord269   float get_value ()             const { return value.to_float (); }
270 
sanitizeOT::AxisValueRecord271   bool sanitize (hb_sanitize_context_t *c) const
272   {
273     TRACE_SANITIZE (this);
274     return_trace (c->check_struct (this));
275   }
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 {
get_axis_recordOT::AxisValueFormat4288   const AxisValueRecord &get_axis_record (unsigned int axis_index) const
289   { return axisValues.as_array (axisCount)[axis_index]; }
290 
keep_axis_valueOT::AxisValueFormat4291   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   {
294     hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
295 
296     for (const auto& rec : axis_value_records)
297     {
298       unsigned axis_idx = rec.get_axis_index ();
299       float axis_value = rec.get_value ();
300       hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
301 
302       if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
303         return false;
304     }
305 
306     return true;
307   }
308 
subsetOT::AxisValueFormat4309   bool subset (hb_subset_context_t *c,
310                const hb_array_t<const StatAxisRecord> axis_records) const
311   {
312     TRACE_SUBSET (this);
313     const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
314     if (!keep_axis_value (axis_records, user_axes_location))
315       return_trace (false);
316 
317     unsigned total_size = min_size + axisCount * AxisValueRecord::static_size;
318     auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size);
319     if (unlikely (!out)) return_trace (false);
320     hb_memcpy (out, this, total_size);
321     return_trace (true);
322   }
323 
get_value_name_idOT::AxisValueFormat4324   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
325 
sanitizeOT::AxisValueFormat4326   bool sanitize (hb_sanitize_context_t *c) const
327   {
328     TRACE_SANITIZE (this);
329     return_trace (likely (c->check_struct (this) &&
330                           axisValues.sanitize (c, axisCount)));
331   }
332 
333   protected:
334   HBUINT16	format;		/* Format identifier — set to 4. */
335   HBUINT16	axisCount;	/* The total number of axes contributing to
336 				 * this axis-values combination. */
337   HBUINT16	flags;		/* Flags — see below for details. */
338   NameID	valueNameID;	/* The name ID for entries in the 'name' table
339 				 * that provide a display string for this
340 				 * attribute value. */
341   UnsizedArrayOf<AxisValueRecord>
342 		axisValues;	/* Array of AxisValue records that provide the
343 				 * combination of axis values, one for each
344 				 * contributing axis. */
345   public:
346   DEFINE_SIZE_ARRAY (8, axisValues);
347 };
348 
349 struct AxisValue
350 {
get_valueOT::AxisValue351   bool get_value (unsigned int axis_index) const
352   {
353     switch (u.format)
354     {
355     case 1: return u.format1.get_value ();
356     case 2: return u.format2.get_value ();
357     case 3: return u.format3.get_value ();
358     case 4: return u.format4.get_axis_record (axis_index).get_value ();
359     default:return 0;
360     }
361   }
362 
get_axis_indexOT::AxisValue363   unsigned int get_axis_index () const
364   {
365     switch (u.format)
366     {
367     case 1: return u.format1.get_axis_index ();
368     case 2: return u.format2.get_axis_index ();
369     case 3: return u.format3.get_axis_index ();
370     /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
371     default:return -1;
372     }
373   }
374 
get_value_name_idOT::AxisValue375   hb_ot_name_id_t get_value_name_id () const
376   {
377     switch (u.format)
378     {
379     case 1: return u.format1.get_value_name_id ();
380     case 2: return u.format2.get_value_name_id ();
381     case 3: return u.format3.get_value_name_id ();
382     case 4: return u.format4.get_value_name_id ();
383     default:return HB_OT_NAME_ID_INVALID;
384     }
385   }
386 
387   template <typename context_t, typename ...Ts>
dispatchOT::AxisValue388   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
389   {
390     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
391     TRACE_DISPATCH (this, u.format);
392     switch (u.format) {
393     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
394     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
395     case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
396     case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
397     default:return_trace (c->default_return_value ());
398     }
399   }
400 
keep_axis_valueOT::AxisValue401   bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
402                         hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
403   {
404     switch (u.format)
405     {
406     case 1: return u.format1.keep_axis_value (axis_records, user_axes_location);
407     case 2: return u.format2.keep_axis_value (axis_records, user_axes_location);
408     case 3: return u.format3.keep_axis_value (axis_records, user_axes_location);
409     case 4: return u.format4.keep_axis_value (axis_records, user_axes_location);
410     default:return false;
411     }
412   }
413 
sanitizeOT::AxisValue414   bool sanitize (hb_sanitize_context_t *c) const
415   {
416     TRACE_SANITIZE (this);
417     if (unlikely (!c->check_struct (this)))
418       return_trace (false);
419 
420     switch (u.format)
421     {
422     case 1: return_trace (u.format1.sanitize (c));
423     case 2: return_trace (u.format2.sanitize (c));
424     case 3: return_trace (u.format3.sanitize (c));
425     case 4: return_trace (u.format4.sanitize (c));
426     default:return_trace (true);
427     }
428   }
429 
430   protected:
431   union
432   {
433   HBUINT16		format;
434   AxisValueFormat1	format1;
435   AxisValueFormat2	format2;
436   AxisValueFormat3	format3;
437   AxisValueFormat4	format4;
438   } u;
439   public:
440   DEFINE_SIZE_UNION (2, format);
441 };
442 
443 struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
444 {
subsetOT::AxisValueOffsetArray445   bool subset (hb_subset_context_t *c,
446                unsigned axisValueCount,
447                unsigned& count,
448                const hb_array_t<const StatAxisRecord> axis_records) const
449   {
450     TRACE_SUBSET (this);
451 
452     auto axisValueOffsets = as_array (axisValueCount);
453     count = 0;
454     for (const auto& offset : axisValueOffsets)
455     {
456       if (!offset) continue;
457       auto o_snap = c->serializer->snapshot ();
458       auto *o = c->serializer->embed (offset);
459       if (!o) return_trace (false);
460       if (!o->serialize_subset (c, offset, this, axis_records))
461       {
462         c->serializer->revert (o_snap);
463         continue;
464       }
465       count++;
466     }
467 
468     return_trace (count);
469   }
470 };
471 
472 struct STAT
473 {
474   static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
475 
has_dataOT::STAT476   bool has_data () const { return version.to_int (); }
477 
get_valueOT::STAT478   bool get_value (hb_tag_t tag, float *value) const
479   {
480     unsigned int axis_index;
481     if (!get_design_axes ().lfind (tag, &axis_index)) return false;
482 
483     hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
484     for (unsigned int i = 0; i < axis_values.length; i++)
485     {
486       const AxisValue& axis_value = this+axis_values[i];
487       if (axis_value.get_axis_index () == axis_index)
488       {
489 	if (value)
490 	  *value = axis_value.get_value (axis_index);
491 	return true;
492       }
493     }
494     return false;
495   }
496 
get_design_axis_countOT::STAT497   unsigned get_design_axis_count () const { return designAxisCount; }
498 
get_axis_record_name_idOT::STAT499   hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
500   {
501     if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
502     const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
503     return axis_record.get_name_id ();
504   }
505 
get_axis_value_countOT::STAT506   unsigned get_axis_value_count () const { return axisValueCount; }
507 
get_axis_value_name_idOT::STAT508   hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
509   {
510     if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
511     const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
512     return axis_value.get_value_name_id ();
513   }
514 
collect_name_idsOT::STAT515   void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
516                          hb_set_t *nameids_to_retain /* OUT */) const
517   {
518     if (!has_data ()) return;
519 
520     + get_design_axes ()
521     | hb_map (&StatAxisRecord::get_name_id)
522     | hb_sink (nameids_to_retain)
523     ;
524 
525     auto designAxes = get_design_axes ();
526 
527     + get_axis_value_offsets ()
528     | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
529     | hb_filter ([&] (const AxisValue& _)
530                  { return _.keep_axis_value (designAxes, user_axes_location); })
531     | hb_map (&AxisValue::get_value_name_id)
532     | hb_sink (nameids_to_retain)
533     ;
534 
535     nameids_to_retain->add (elidedFallbackNameID);
536   }
537 
subsetOT::STAT538   bool subset (hb_subset_context_t *c) const
539   {
540     TRACE_SUBSET (this);
541     STAT *out = c->serializer->embed (this);
542     if (unlikely (!out)) return_trace (false);
543 
544     auto designAxes = get_design_axes ();
545     for (unsigned i = 0; i < (unsigned)designAxisCount; i++)
546       if (unlikely (!c->serializer->embed (designAxes[i])))
547           return_trace (false);
548 
549     if (designAxisCount)
550       c->serializer->check_assign (out->designAxesOffset, this->get_size (),
551                                    HB_SERIALIZE_ERROR_INT_OVERFLOW);
552 
553     unsigned count = 0;
554     out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this,
555                                                     axisValueCount, count, designAxes);
556     return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
557   }
558 
sanitizeOT::STAT559   bool sanitize (hb_sanitize_context_t *c) const
560   {
561     TRACE_SANITIZE (this);
562     return_trace (likely (c->check_struct (this) &&
563 			  version.major == 1 &&
564 			  version.minor > 0 &&
565 			  designAxesOffset.sanitize (c, this, designAxisCount) &&
566 			  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
567   }
568 
569   protected:
get_design_axesOT::STAT570   hb_array_t<const StatAxisRecord> const get_design_axes () const
571   { return (this+designAxesOffset).as_array (designAxisCount); }
572 
get_axis_value_offsetsOT::STAT573   hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
574   { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
575 
576 
577   protected:
578   FixedVersion<>version;	/* Version of the stat table
579 				 * initially set to 0x00010002u */
580   HBUINT16	designAxisSize;	/* The size in bytes of each axis record. */
581   HBUINT16	designAxisCount;/* The number of design axis records. In a
582 				 * font with an 'fvar' table, this value must be
583 				 * greater than or equal to the axisCount value
584 				 * in the 'fvar' table. In all fonts, must
585 				 * be greater than zero if axisValueCount
586 				 * is greater than zero. */
587   NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
588 		designAxesOffset;
589 				/* Offset in bytes from the beginning of
590 				 * the STAT table to the start of the design
591 				 * axes array. If designAxisCount is zero,
592 				 * set to zero; if designAxisCount is greater
593 				 * than zero, must be greater than zero. */
594   HBUINT16	axisValueCount;	/* The number of axis value tables. */
595   NNOffset32To<AxisValueOffsetArray>
596 		offsetToAxisValueOffsets;
597 				/* Offset in bytes from the beginning of
598 				 * the STAT table to the start of the design
599 				 * axes value offsets array. If axisValueCount
600 				 * is zero, set to zero; if axisValueCount is
601 				 * greater than zero, must be greater than zero. */
602   NameID	elidedFallbackNameID;
603 				/* Name ID used as fallback when projection of
604 				 * names into a particular font model produces
605 				 * a subfamily name containing only elidable
606 				 * elements. */
607   public:
608   DEFINE_SIZE_STATIC (20);
609 };
610 
611 
612 } /* namespace OT */
613 
614 
615 #endif /* HB_OT_STAT_TABLE_HH */
616