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 | { |
62 | unsigned int get_axis_index () const { return axisIndex; } |
63 | float get_value () const { return value.to_float (); } |
64 | |
65 | hb_ot_name_id_t get_value_name_id () const { return valueNameID; } |
66 | |
67 | 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 | { |
90 | unsigned int get_axis_index () const { return axisIndex; } |
91 | float get_value () const { return nominalValue.to_float (); } |
92 | |
93 | hb_ot_name_id_t get_value_name_id () const { return valueNameID; } |
94 | |
95 | 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 | { |
122 | unsigned int get_axis_index () const { return axisIndex; } |
123 | float get_value () const { return value.to_float (); } |
124 | |
125 | hb_ot_name_id_t get_value_name_id () const { return valueNameID; } |
126 | |
127 | 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 | { |
152 | unsigned int get_axis_index () const { return axisIndex; } |
153 | float get_value () const { return value.to_float (); } |
154 | |
155 | 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 | { |
172 | const AxisValueRecord &get_axis_record (unsigned int axis_index) const |
173 | { return axisValues.as_array (axisCount)[axis_index]; } |
174 | |
175 | hb_ot_name_id_t get_value_name_id () const { return valueNameID; } |
176 | |
177 | 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 | { |
201 | 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 | |
213 | 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 | |
225 | 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 | |
237 | 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 | { |
268 | int cmp (hb_tag_t key) const { return tag.cmp (key); } |
269 | |
270 | hb_ot_name_id_t get_name_id () const { return nameID; } |
271 | |
272 | 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 | |
293 | bool has_data () const { return version.to_int (); } |
294 | |
295 | 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 OffsetTo<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 | |
314 | unsigned get_design_axis_count () const { return designAxisCount; } |
315 | |
316 | 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 | |
323 | unsigned get_axis_value_count () const { return axisValueCount; } |
324 | |
325 | 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 | |
332 | 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 | |
348 | 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: |
359 | hb_array_t<const StatAxisRecord> const get_design_axes () const |
360 | { return (this+designAxesOffset).as_array (designAxisCount); } |
361 | |
362 | hb_array_t<const OffsetTo<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 | LNNOffsetTo<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 | LNNOffsetTo<UnsizedArrayOf<OffsetTo<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 | |