xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-stat-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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   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 {
cmpOT::StatAxisRecord73   int cmp (hb_tag_t key) const { return tag.cmp (key); }
74 
get_name_idOT::StatAxisRecord75   hb_ot_name_id_t get_name_id () const { return nameID; }
76 
get_axis_tagOT::StatAxisRecord77   hb_tag_t get_axis_tag () const { return tag; }
78 
sanitizeOT::StatAxisRecord79   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 {
get_axis_indexOT::AxisValueFormat198   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat199   float get_value ()             const { return value.to_float (); }
100 
get_value_name_idOT::AxisValueFormat1101   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
102 
get_axis_tagOT::AxisValueFormat1103   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 
keep_axis_valueOT::AxisValueFormat1109   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 
subsetOT::AxisValueFormat1118   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 
sanitizeOT::AxisValueFormat1130   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 {
get_axis_indexOT::AxisValueFormat2153   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat2154   float get_value ()             const { return nominalValue.to_float (); }
155 
get_value_name_idOT::AxisValueFormat2156   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
157 
get_axis_tagOT::AxisValueFormat2158   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 
keep_axis_valueOT::AxisValueFormat2164   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 
subsetOT::AxisValueFormat2173   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 
sanitizeOT::AxisValueFormat2185   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 {
get_axis_indexOT::AxisValueFormat3212   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat3213   float get_value ()             const { return value.to_float (); }
214 
get_value_name_idOT::AxisValueFormat3215   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
216 
get_axis_tagOT::AxisValueFormat3217   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 
keep_axis_valueOT::AxisValueFormat3223   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 
subsetOT::AxisValueFormat3232   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 
sanitizeOT::AxisValueFormat3244   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 {
get_axis_indexOT::AxisValueRecord269   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueRecord270   float get_value ()             const { return value.to_float (); }
271 
sanitizeOT::AxisValueRecord272   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 {
get_axis_recordOT::AxisValueFormat4289   const AxisValueRecord &get_axis_record (unsigned int axis_index) const
290   { return axisValues.as_array (axisCount)[axis_index]; }
291 
keep_axis_valueOT::AxisValueFormat4292   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 
subsetOT::AxisValueFormat4310   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 
get_value_name_idOT::AxisValueFormat4325   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
326 
sanitizeOT::AxisValueFormat4327   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 {
get_valueOT::AxisValue353   float get_value (unsigned int axis_index) const
354   {
355     switch (u.format)
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 
get_axis_indexOT::AxisValue365   unsigned int get_axis_index () const
366   {
367     switch (u.format)
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 
get_value_name_idOT::AxisValue377   hb_ot_name_id_t get_value_name_id () const
378   {
379     switch (u.format)
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>
dispatchOT::AxisValue390   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
391   {
392     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
393     TRACE_DISPATCH (this, u.format);
394     switch (u.format) {
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 
keep_axis_valueOT::AxisValue403   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)
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 
sanitizeOT::AxisValue416   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)
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   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 {
subsetOT::AxisValueOffsetArray448   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 
has_dataOT::STAT479   bool has_data () const { return version.to_int (); }
480 
get_valueOT::STAT481   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 
get_design_axis_countOT::STAT500   unsigned get_design_axis_count () const { return designAxisCount; }
501 
get_axis_record_name_idOT::STAT502   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 
get_axis_value_countOT::STAT509   unsigned get_axis_value_count () const { return axisValueCount; }
510 
get_axis_value_name_idOT::STAT511   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 
collect_name_idsOT::STAT518   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 
subsetOT::STAT541   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 
sanitizeOT::STAT562   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:
get_design_axesOT::STAT574   hb_array_t<const StatAxisRecord> const get_design_axes () const
575   { return (this+designAxesOffset).as_array (designAxisCount); }
576 
get_axis_value_offsetsOT::STAT577   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 */
620