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