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
38namespace OT {
39
40enum
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
60struct AxisValueFormat1
61{
62 hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
63
64 bool sanitize (hb_sanitize_context_t *c) const
65 {
66 TRACE_SANITIZE (this);
67 return_trace (likely (c->check_struct (this)));
68 }
69
70 protected:
71 HBUINT16 format; /* Format identifier — set to 1. */
72 HBUINT16 axisIndex; /* Zero-base index into the axis record array
73 * identifying the axis of design variation
74 * to which the axis value record applies.
75 * Must be less than designAxisCount. */
76 HBUINT16 flags; /* Flags — see below for details. */
77 NameID valueNameID; /* The name ID for entries in the 'name' table
78 * that provide a display string for this
79 * attribute value. */
80 HBFixed value; /* A numeric value for this attribute value. */
81 public:
82 DEFINE_SIZE_STATIC (12);
83};
84
85struct AxisValueFormat2
86{
87 hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
88
89 bool sanitize (hb_sanitize_context_t *c) const
90 {
91 TRACE_SANITIZE (this);
92 return_trace (likely (c->check_struct (this)));
93 }
94
95 protected:
96 HBUINT16 format; /* Format identifier — set to 2. */
97 HBUINT16 axisIndex; /* Zero-base index into the axis record array
98 * identifying the axis of design variation
99 * to which the axis value record applies.
100 * Must be less than designAxisCount. */
101 HBUINT16 flags; /* Flags — see below for details. */
102 NameID valueNameID; /* The name ID for entries in the 'name' table
103 * that provide a display string for this
104 * attribute value. */
105 HBFixed nominalValue; /* A numeric value for this attribute value. */
106 HBFixed rangeMinValue; /* The minimum value for a range associated
107 * with the specified name ID. */
108 HBFixed rangeMaxValue; /* The maximum value for a range associated
109 * with the specified name ID. */
110 public:
111 DEFINE_SIZE_STATIC (20);
112};
113
114struct AxisValueFormat3
115{
116 hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
117
118 bool sanitize (hb_sanitize_context_t *c) const
119 {
120 TRACE_SANITIZE (this);
121 return_trace (likely (c->check_struct (this)));
122 }
123
124 protected:
125 HBUINT16 format; /* Format identifier — set to 3. */
126 HBUINT16 axisIndex; /* Zero-base index into the axis record array
127 * identifying the axis of design variation
128 * to which the axis value record applies.
129 * Must be less than designAxisCount. */
130 HBUINT16 flags; /* Flags — see below for details. */
131 NameID valueNameID; /* The name ID for entries in the 'name' table
132 * that provide a display string for this
133 * attribute value. */
134 HBFixed value; /* A numeric value for this attribute value. */
135 HBFixed linkedValue; /* The numeric value for a style-linked mapping
136 * from this value. */
137 public:
138 DEFINE_SIZE_STATIC (16);
139};
140
141struct AxisValueRecord
142{
143 bool sanitize (hb_sanitize_context_t *c) const
144 {
145 TRACE_SANITIZE (this);
146 return_trace (likely (c->check_struct (this)));
147 }
148
149 protected:
150 HBUINT16 axisIndex; /* Zero-base index into the axis record array
151 * identifying the axis to which this value
152 * applies. Must be less than designAxisCount. */
153 HBFixed value; /* A numeric value for this attribute value. */
154 public:
155 DEFINE_SIZE_STATIC (6);
156};
157
158struct AxisValueFormat4
159{
160 hb_ot_name_id_t get_value_name_id () const { return valueNameID; }
161
162 bool sanitize (hb_sanitize_context_t *c) const
163 {
164 TRACE_SANITIZE (this);
165 return_trace (likely (c->check_struct (this)));
166 }
167
168 protected:
169 HBUINT16 format; /* Format identifier — set to 4. */
170 HBUINT16 axisCount; /* The total number of axes contributing to
171 * this axis-values combination. */
172 HBUINT16 flags; /* Flags — see below for details. */
173 NameID valueNameID; /* The name ID for entries in the 'name' table
174 * that provide a display string for this
175 * attribute value. */
176 UnsizedArrayOf<AxisValueRecord>
177 axisValues; /* Array of AxisValue records that provide the
178 * combination of axis values, one for each
179 * contributing axis. */
180 public:
181 DEFINE_SIZE_ARRAY (8, axisValues);
182};
183
184struct AxisValue
185{
186 hb_ot_name_id_t get_value_name_id () const
187 {
188 switch (u.format)
189 {
190 case 1: return u.format1.get_value_name_id ();
191 case 2: return u.format2.get_value_name_id ();
192 case 3: return u.format3.get_value_name_id ();
193 case 4: return u.format4.get_value_name_id ();
194 default:return HB_OT_NAME_ID_INVALID;
195 }
196 }
197
198 bool sanitize (hb_sanitize_context_t *c) const
199 {
200 TRACE_SANITIZE (this);
201 if (unlikely (!c->check_struct (this)))
202 return_trace (false);
203
204 switch (u.format)
205 {
206 case 1: return_trace (u.format1.sanitize (c));
207 case 2: return_trace (u.format2.sanitize (c));
208 case 3: return_trace (u.format3.sanitize (c));
209 case 4: return_trace (u.format4.sanitize (c));
210 default:return_trace (true);
211 }
212 }
213
214 protected:
215 union
216 {
217 HBUINT16 format;
218 AxisValueFormat1 format1;
219 AxisValueFormat2 format2;
220 AxisValueFormat3 format3;
221 AxisValueFormat4 format4;
222 } u;
223 public:
224 DEFINE_SIZE_UNION (2, format);
225};
226
227struct StatAxisRecord
228{
229 hb_ot_name_id_t get_name_id () const { return nameID; }
230
231 bool sanitize (hb_sanitize_context_t *c) const
232 {
233 TRACE_SANITIZE (this);
234 return_trace (likely (c->check_struct (this)));
235 }
236
237 protected:
238 Tag tag; /* A tag identifying the axis of design variation. */
239 NameID nameID; /* The name ID for entries in the 'name' table that
240 * provide a display string for this axis. */
241 HBUINT16 ordering; /* A value that applications can use to determine
242 * primary sorting of face names, or for ordering
243 * of descriptors when composing family or face names. */
244 public:
245 DEFINE_SIZE_STATIC (8);
246};
247
248struct STAT
249{
250 static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;
251
252 bool has_data () const { return version.to_int (); }
253
254 unsigned get_design_axis_count () const { return designAxisCount; }
255
256 hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
257 {
258 if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
259 const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
260 return axis_record.get_name_id ();
261 }
262
263 unsigned get_axis_value_count () const { return axisValueCount; }
264
265 hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
266 {
267 if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
268 const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
269 return axis_value.get_value_name_id ();
270 }
271
272 void collect_name_ids (hb_set_t *nameids_to_retain) const
273 {
274 if (!has_data ()) return;
275
276 + get_design_axes ()
277 | hb_map (&StatAxisRecord::get_name_id)
278 | hb_sink (nameids_to_retain)
279 ;
280
281 + get_axis_value_offsets ()
282 | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
283 | hb_map (&AxisValue::get_value_name_id)
284 | hb_sink (nameids_to_retain)
285 ;
286 }
287
288 bool sanitize (hb_sanitize_context_t *c) const
289 {
290 TRACE_SANITIZE (this);
291 return_trace (likely (c->check_struct (this) &&
292 version.major == 1 &&
293 version.minor > 0 &&
294 designAxesOffset.sanitize (c, this, designAxisCount) &&
295 offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
296 }
297
298 protected:
299 hb_array_t<const StatAxisRecord> const get_design_axes () const
300 { return (this+designAxesOffset).as_array (designAxisCount); }
301
302 hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
303 { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }
304
305
306 protected:
307 FixedVersion<>version; /* Version of the stat table
308 * initially set to 0x00010002u */
309 HBUINT16 designAxisSize; /* The size in bytes of each axis record. */
310 HBUINT16 designAxisCount;/* The number of design axis records. In a
311 * font with an 'fvar' table, this value must be
312 * greater than or equal to the axisCount value
313 * in the 'fvar' table. In all fonts, must
314 * be greater than zero if axisValueCount
315 * is greater than zero. */
316 LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
317 designAxesOffset;
318 /* Offset in bytes from the beginning of
319 * the STAT table to the start of the design
320 * axes array. If designAxisCount is zero,
321 * set to zero; if designAxisCount is greater
322 * than zero, must be greater than zero. */
323 HBUINT16 axisValueCount; /* The number of axis value tables. */
324 LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
325 offsetToAxisValueOffsets;
326 /* Offset in bytes from the beginning of
327 * the STAT table to the start of the design
328 * axes value offsets array. If axisValueCount
329 * is zero, set to zero; if axisValueCount is
330 * greater than zero, must be greater than zero. */
331 NameID elidedFallbackNameID;
332 /* Name ID used as fallback when projection of
333 * names into a particular font model produces
334 * a subfamily name containing only elidable
335 * elements. */
336 public:
337 DEFINE_SIZE_STATIC (20);
338};
339
340
341} /* namespace OT */
342
343
344#endif /* HB_OT_STAT_TABLE_HH */
345