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 | 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 | |
85 | struct 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 | |
114 | struct 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 | |
141 | struct 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 | |
158 | struct 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 | |
184 | struct 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 | |
227 | struct 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 | |
248 | struct 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 | |