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 struct AxisValueFormat1
61 {
get_axis_indexOT::AxisValueFormat162   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat163   float get_value ()             const { return value.to_float (); }
64 
get_value_name_idOT::AxisValueFormat165   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
66 
sanitizeOT::AxisValueFormat167   bool sanitize (hb_sanitize_context_t *c) const
68   {
69     TRACE_SANITIZE (this);
70     return_trace (likely (c->check_struct (this)));
71   }
72 
73   protected:
74   HBUINT16	format;		/* Format identifier — set to 1. */
75   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
76 				 * identifying the axis of design variation
77 				 * to which the axis value record applies.
78 				 * Must be less than designAxisCount. */
79   HBUINT16	flags;		/* Flags — see below for details. */
80   NameID	valueNameID;	/* The name ID for entries in the 'name' table
81 				 * that provide a display string for this
82 				 * attribute value. */
83   HBFixed	value;		/* A numeric value for this attribute value. */
84   public:
85   DEFINE_SIZE_STATIC (12);
86 };
87 
88 struct AxisValueFormat2
89 {
get_axis_indexOT::AxisValueFormat290   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat291   float get_value ()             const { return nominalValue.to_float (); }
92 
get_value_name_idOT::AxisValueFormat293   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
94 
sanitizeOT::AxisValueFormat295   bool sanitize (hb_sanitize_context_t *c) const
96   {
97     TRACE_SANITIZE (this);
98     return_trace (likely (c->check_struct (this)));
99   }
100 
101   protected:
102   HBUINT16	format;		/* Format identifier — set to 2. */
103   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
104 				 * identifying the axis of design variation
105 				 * to which the axis value record applies.
106 				 * Must be less than designAxisCount. */
107   HBUINT16	flags;		/* Flags — see below for details. */
108   NameID	valueNameID;	/* The name ID for entries in the 'name' table
109 				 * that provide a display string for this
110 				 * attribute value. */
111   HBFixed	nominalValue;	/* A numeric value for this attribute value. */
112   HBFixed	rangeMinValue;	/* The minimum value for a range associated
113 				 * with the specified name ID. */
114   HBFixed	rangeMaxValue;	/* The maximum value for a range associated
115 				 * with the specified name ID. */
116   public:
117   DEFINE_SIZE_STATIC (20);
118 };
119 
120 struct AxisValueFormat3
121 {
get_axis_indexOT::AxisValueFormat3122   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueFormat3123   float get_value ()             const { return value.to_float (); }
124 
get_value_name_idOT::AxisValueFormat3125   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
126 
sanitizeOT::AxisValueFormat3127   bool sanitize (hb_sanitize_context_t *c) const
128   {
129     TRACE_SANITIZE (this);
130     return_trace (likely (c->check_struct (this)));
131   }
132 
133   protected:
134   HBUINT16	format;		/* Format identifier — set to 3. */
135   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
136 				 * identifying the axis of design variation
137 				 * to which the axis value record applies.
138 				 * Must be less than designAxisCount. */
139   HBUINT16	flags;		/* Flags — see below for details. */
140   NameID	valueNameID;	/* The name ID for entries in the 'name' table
141 				 * that provide a display string for this
142 				 * attribute value. */
143   HBFixed	value;		/* A numeric value for this attribute value. */
144   HBFixed	linkedValue;	/* The numeric value for a style-linked mapping
145 				 * from this value. */
146   public:
147   DEFINE_SIZE_STATIC (16);
148 };
149 
150 struct AxisValueRecord
151 {
get_axis_indexOT::AxisValueRecord152   unsigned int get_axis_index () const { return axisIndex; }
get_valueOT::AxisValueRecord153   float get_value ()             const { return value.to_float (); }
154 
sanitizeOT::AxisValueRecord155   bool sanitize (hb_sanitize_context_t *c) const
156   {
157     TRACE_SANITIZE (this);
158     return_trace (likely (c->check_struct (this)));
159   }
160 
161   protected:
162   HBUINT16	axisIndex;	/* Zero-base index into the axis record array
163 				 * identifying the axis to which this value
164 				 * applies. Must be less than designAxisCount. */
165   HBFixed	value;		/* A numeric value for this attribute value. */
166   public:
167   DEFINE_SIZE_STATIC (6);
168 };
169 
170 struct AxisValueFormat4
171 {
get_axis_recordOT::AxisValueFormat4172   const AxisValueRecord &get_axis_record (unsigned int axis_index) const
173   { return axisValues.as_array (axisCount)[axis_index]; }
174 
get_value_name_idOT::AxisValueFormat4175   hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
176 
sanitizeOT::AxisValueFormat4177   bool sanitize (hb_sanitize_context_t *c) const
178   {
179     TRACE_SANITIZE (this);
180     return_trace (likely (c->check_struct (this)));
181   }
182 
183   protected:
184   HBUINT16	format;		/* Format identifier — set to 4. */
185   HBUINT16	axisCount;	/* The total number of axes contributing to
186 				 * this axis-values combination. */
187   HBUINT16	flags;		/* Flags — see below for details. */
188   NameID	valueNameID;	/* The name ID for entries in the 'name' table
189 				 * that provide a display string for this
190 				 * attribute value. */
191   UnsizedArrayOf<AxisValueRecord>
192 		axisValues;	/* Array of AxisValue records that provide the
193 				 * combination of axis values, one for each
194 				 * contributing axis. */
195   public:
196   DEFINE_SIZE_ARRAY (8, axisValues);
197 };
198 
199 struct AxisValue
200 {
get_valueOT::AxisValue201   bool get_value (unsigned int axis_index) const
202   {
203     switch (u.format)
204     {
205     case 1: return u.format1.get_value ();
206     case 2: return u.format2.get_value ();
207     case 3: return u.format3.get_value ();
208     case 4: return u.format4.get_axis_record (axis_index).get_value ();
209     default:return 0;
210     }
211   }
212 
get_axis_indexOT::AxisValue213   unsigned int get_axis_index () const
214   {
215     switch (u.format)
216     {
217     case 1: return u.format1.get_axis_index ();
218     case 2: return u.format2.get_axis_index ();
219     case 3: return u.format3.get_axis_index ();
220     /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */
221     default:return -1;
222     }
223   }
224 
get_value_name_idOT::AxisValue225   hb_ot_name_id_t get_value_name_id () const
226   {
227     switch (u.format)
228     {
229     case 1: return u.format1.get_value_name_id ();
230     case 2: return u.format2.get_value_name_id ();
231     case 3: return u.format3.get_value_name_id ();
232     case 4: return u.format4.get_value_name_id ();
233     default:return HB_OT_NAME_ID_INVALID;
234     }
235   }
236 
sanitizeOT::AxisValue237   bool sanitize (hb_sanitize_context_t *c) const
238   {
239     TRACE_SANITIZE (this);
240     if (unlikely (!c->check_struct (this)))
241       return_trace (false);
242 
243     switch (u.format)
244     {
245     case 1: return_trace (u.format1.sanitize (c));
246     case 2: return_trace (u.format2.sanitize (c));
247     case 3: return_trace (u.format3.sanitize (c));
248     case 4: return_trace (u.format4.sanitize (c));
249     default:return_trace (true);
250     }
251   }
252 
253   protected:
254   union
255   {
256   HBUINT16		format;
257   AxisValueFormat1	format1;
258   AxisValueFormat2	format2;
259   AxisValueFormat3	format3;
260   AxisValueFormat4	format4;
261   } u;
262   public:
263   DEFINE_SIZE_UNION (2, format);
264 };
265 
266 struct StatAxisRecord
267 {
cmpOT::StatAxisRecord268   int cmp (hb_tag_t key) const { return tag.cmp (key); }
269 
get_name_idOT::StatAxisRecord270   hb_ot_name_id_t get_name_id () const { return nameID; }
271 
sanitizeOT::StatAxisRecord272   bool sanitize (hb_sanitize_context_t *c) const
273   {
274     TRACE_SANITIZE (this);
275     return_trace (likely (c->check_struct (this)));
276   }
277 
278   protected:
279   Tag		tag;		/* A tag identifying the axis of design variation. */
280   NameID	nameID;		/* The name ID for entries in the 'name' table that
281 				 * provide a display string for this axis. */
282   HBUINT16	ordering;	/* A value that applications can use to determine
283 				 * primary sorting of face names, or for ordering
284 				 * of descriptors when composing family or face names. */
285   public:
286   DEFINE_SIZE_STATIC (8);
287 };
288 
289 struct STAT
290 {
291   static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
292 
has_dataOT::STAT293   bool has_data () const { return version.to_int (); }
294 
get_valueOT::STAT295   bool get_value (hb_tag_t tag, float *value) const
296   {
297     unsigned int axis_index;
298     if (!get_design_axes ().lfind (tag, &axis_index)) return false;
299 
300     hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
301     for (unsigned int i = 0; i < axis_values.length; i++)
302     {
303       const AxisValue& axis_value = this+axis_values[i];
304       if (axis_value.get_axis_index () == axis_index)
305       {
306 	if (value)
307 	  *value = axis_value.get_value (axis_index);
308 	return true;
309       }
310     }
311     return false;
312   }
313 
get_design_axis_countOT::STAT314   unsigned get_design_axis_count () const { return designAxisCount; }
315 
get_axis_record_name_idOT::STAT316   hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
317   {
318     if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
319     const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
320     return axis_record.get_name_id ();
321   }
322 
get_axis_value_countOT::STAT323   unsigned get_axis_value_count () const { return axisValueCount; }
324 
get_axis_value_name_idOT::STAT325   hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
326   {
327     if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
328     const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
329     return axis_value.get_value_name_id ();
330   }
331 
collect_name_idsOT::STAT332   void collect_name_ids (hb_set_t *nameids_to_retain) const
333   {
334     if (!has_data ()) return;
335 
336     + get_design_axes ()
337     | hb_map (&StatAxisRecord::get_name_id)
338     | hb_sink (nameids_to_retain)
339     ;
340 
341     + get_axis_value_offsets ()
342     | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
343     | hb_map (&AxisValue::get_value_name_id)
344     | hb_sink (nameids_to_retain)
345     ;
346   }
347 
sanitizeOT::STAT348   bool sanitize (hb_sanitize_context_t *c) const
349   {
350     TRACE_SANITIZE (this);
351     return_trace (likely (c->check_struct (this) &&
352 			  version.major == 1 &&
353 			  version.minor > 0 &&
354 			  designAxesOffset.sanitize (c, this, designAxisCount) &&
355 			  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
356   }
357 
358   protected:
get_design_axesOT::STAT359   hb_array_t<const StatAxisRecord> const get_design_axes () const
360   { return (this+designAxesOffset).as_array (designAxisCount); }
361 
get_axis_value_offsetsOT::STAT362   hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const
363   { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
364 
365 
366   protected:
367   FixedVersion<>version;	/* Version of the stat table
368 				 * initially set to 0x00010002u */
369   HBUINT16	designAxisSize;	/* The size in bytes of each axis record. */
370   HBUINT16	designAxisCount;/* The number of design axis records. In a
371 				 * font with an 'fvar' table, this value must be
372 				 * greater than or equal to the axisCount value
373 				 * in the 'fvar' table. In all fonts, must
374 				 * be greater than zero if axisValueCount
375 				 * is greater than zero. */
376   NNOffset32To<UnsizedArrayOf<StatAxisRecord>>
377 		designAxesOffset;
378 				/* Offset in bytes from the beginning of
379 				 * the STAT table to the start of the design
380 				 * axes array. If designAxisCount is zero,
381 				 * set to zero; if designAxisCount is greater
382 				 * than zero, must be greater than zero. */
383   HBUINT16	axisValueCount;	/* The number of axis value tables. */
384   NNOffset32To<UnsizedArrayOf<Offset16To<AxisValue>>>
385 		offsetToAxisValueOffsets;
386 				/* Offset in bytes from the beginning of
387 				 * the STAT table to the start of the design
388 				 * axes value offsets array. If axisValueCount
389 				 * is zero, set to zero; if axisValueCount is
390 				 * greater than zero, must be greater than zero. */
391   NameID	elidedFallbackNameID;
392 				/* Name ID used as fallback when projection of
393 				 * names into a particular font model produces
394 				 * a subfamily name containing only elidable
395 				 * elements. */
396   public:
397   DEFINE_SIZE_STATIC (20);
398 };
399 
400 
401 } /* namespace OT */
402 
403 
404 #endif /* HB_OT_STAT_TABLE_HH */
405