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 StatAxisRecord 61 { cmpOT::StatAxisRecord62 int cmp (hb_tag_t key) const { return tag.cmp (key); } 63 get_name_idOT::StatAxisRecord64 hb_ot_name_id_t get_name_id () const { return nameID; } 65 get_axis_tagOT::StatAxisRecord66 hb_tag_t get_axis_tag () const { return tag; } 67 sanitizeOT::StatAxisRecord68 bool sanitize (hb_sanitize_context_t *c) const 69 { 70 TRACE_SANITIZE (this); 71 return_trace (likely (c->check_struct (this))); 72 } 73 74 protected: 75 Tag tag; /* A tag identifying the axis of design variation. */ 76 NameID nameID; /* The name ID for entries in the 'name' table that 77 * provide a display string for this axis. */ 78 HBUINT16 ordering; /* A value that applications can use to determine 79 * primary sorting of face names, or for ordering 80 * of descriptors when composing family or face names. */ 81 public: 82 DEFINE_SIZE_STATIC (8); 83 }; 84 85 struct AxisValueFormat1 86 { get_axis_indexOT::AxisValueFormat187 unsigned int get_axis_index () const { return axisIndex; } get_valueOT::AxisValueFormat188 float get_value () const { return value.to_float (); } 89 get_value_name_idOT::AxisValueFormat190 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } 91 get_axis_tagOT::AxisValueFormat192 hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const 93 { 94 unsigned axis_idx = get_axis_index (); 95 return axis_records[axis_idx].get_axis_tag (); 96 } 97 keep_axis_valueOT::AxisValueFormat198 bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, 99 const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const 100 { 101 hb_tag_t axis_tag = get_axis_tag (axis_records); 102 float axis_value = get_value (); 103 104 if (!user_axes_location->has (axis_tag) || 105 fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) 106 return true; 107 108 return false; 109 } 110 subsetOT::AxisValueFormat1111 bool subset (hb_subset_context_t *c, 112 const hb_array_t<const StatAxisRecord> axis_records) const 113 { 114 TRACE_SUBSET (this); 115 const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location; 116 117 if (keep_axis_value (axis_records, user_axes_location)) 118 return_trace (c->serializer->embed (this)); 119 120 return_trace (false); 121 } 122 sanitizeOT::AxisValueFormat1123 bool sanitize (hb_sanitize_context_t *c) const 124 { 125 TRACE_SANITIZE (this); 126 return_trace (c->check_struct (this)); 127 } 128 129 protected: 130 HBUINT16 format; /* Format identifier — set to 1. */ 131 HBUINT16 axisIndex; /* Zero-base index into the axis record array 132 * identifying the axis of design variation 133 * to which the axis value record applies. 134 * Must be less than designAxisCount. */ 135 HBUINT16 flags; /* Flags — see below for details. */ 136 NameID valueNameID; /* The name ID for entries in the 'name' table 137 * that provide a display string for this 138 * attribute value. */ 139 F16DOT16 value; /* A numeric value for this attribute value. */ 140 public: 141 DEFINE_SIZE_STATIC (12); 142 }; 143 144 struct AxisValueFormat2 145 { get_axis_indexOT::AxisValueFormat2146 unsigned int get_axis_index () const { return axisIndex; } get_valueOT::AxisValueFormat2147 float get_value () const { return nominalValue.to_float (); } 148 get_value_name_idOT::AxisValueFormat2149 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } 150 get_axis_tagOT::AxisValueFormat2151 hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const 152 { 153 unsigned axis_idx = get_axis_index (); 154 return axis_records[axis_idx].get_axis_tag (); 155 } 156 keep_axis_valueOT::AxisValueFormat2157 bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, 158 const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const 159 { 160 hb_tag_t axis_tag = get_axis_tag (axis_records); 161 float axis_value = get_value (); 162 163 if (!user_axes_location->has (axis_tag) || 164 fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) 165 return true; 166 167 return false; 168 } 169 subsetOT::AxisValueFormat2170 bool subset (hb_subset_context_t *c, 171 const hb_array_t<const StatAxisRecord> axis_records) const 172 { 173 TRACE_SUBSET (this); 174 const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location; 175 176 if (keep_axis_value (axis_records, user_axes_location)) 177 return_trace (c->serializer->embed (this)); 178 179 return_trace (false); 180 } 181 sanitizeOT::AxisValueFormat2182 bool sanitize (hb_sanitize_context_t *c) const 183 { 184 TRACE_SANITIZE (this); 185 return_trace (c->check_struct (this)); 186 } 187 188 protected: 189 HBUINT16 format; /* Format identifier — set to 2. */ 190 HBUINT16 axisIndex; /* Zero-base index into the axis record array 191 * identifying the axis of design variation 192 * to which the axis value record applies. 193 * Must be less than designAxisCount. */ 194 HBUINT16 flags; /* Flags — see below for details. */ 195 NameID valueNameID; /* The name ID for entries in the 'name' table 196 * that provide a display string for this 197 * attribute value. */ 198 F16DOT16 nominalValue; /* A numeric value for this attribute value. */ 199 F16DOT16 rangeMinValue; /* The minimum value for a range associated 200 * with the specified name ID. */ 201 F16DOT16 rangeMaxValue; /* The maximum value for a range associated 202 * with the specified name ID. */ 203 public: 204 DEFINE_SIZE_STATIC (20); 205 }; 206 207 struct AxisValueFormat3 208 { get_axis_indexOT::AxisValueFormat3209 unsigned int get_axis_index () const { return axisIndex; } get_valueOT::AxisValueFormat3210 float get_value () const { return value.to_float (); } 211 get_value_name_idOT::AxisValueFormat3212 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } 213 get_axis_tagOT::AxisValueFormat3214 hb_tag_t get_axis_tag (const hb_array_t<const StatAxisRecord> axis_records) const 215 { 216 unsigned axis_idx = get_axis_index (); 217 return axis_records[axis_idx].get_axis_tag (); 218 } 219 keep_axis_valueOT::AxisValueFormat3220 bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, 221 const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const 222 { 223 hb_tag_t axis_tag = get_axis_tag (axis_records); 224 float axis_value = get_value (); 225 226 if (!user_axes_location->has (axis_tag) || 227 fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f) 228 return true; 229 230 return false; 231 } 232 subsetOT::AxisValueFormat3233 bool subset (hb_subset_context_t *c, 234 const hb_array_t<const StatAxisRecord> axis_records) const 235 { 236 TRACE_SUBSET (this); 237 const hb_hashmap_t<hb_tag_t, float>* user_axes_location = c->plan->user_axes_location; 238 239 if (keep_axis_value (axis_records, user_axes_location)) 240 return_trace (c->serializer->embed (this)); 241 242 return_trace (false); 243 } 244 sanitizeOT::AxisValueFormat3245 bool sanitize (hb_sanitize_context_t *c) const 246 { 247 TRACE_SANITIZE (this); 248 return_trace (c->check_struct (this)); 249 } 250 251 protected: 252 HBUINT16 format; /* Format identifier — set to 3. */ 253 HBUINT16 axisIndex; /* Zero-base index into the axis record array 254 * identifying the axis of design variation 255 * to which the axis value record applies. 256 * Must be less than designAxisCount. */ 257 HBUINT16 flags; /* Flags — see below for details. */ 258 NameID valueNameID; /* The name ID for entries in the 'name' table 259 * that provide a display string for this 260 * attribute value. */ 261 F16DOT16 value; /* A numeric value for this attribute value. */ 262 F16DOT16 linkedValue; /* The numeric value for a style-linked mapping 263 * from this value. */ 264 public: 265 DEFINE_SIZE_STATIC (16); 266 }; 267 268 struct AxisValueRecord 269 { get_axis_indexOT::AxisValueRecord270 unsigned int get_axis_index () const { return axisIndex; } get_valueOT::AxisValueRecord271 float get_value () const { return value.to_float (); } 272 sanitizeOT::AxisValueRecord273 bool sanitize (hb_sanitize_context_t *c) const 274 { 275 TRACE_SANITIZE (this); 276 return_trace (c->check_struct (this)); 277 } 278 279 protected: 280 HBUINT16 axisIndex; /* Zero-base index into the axis record array 281 * identifying the axis to which this value 282 * applies. Must be less than designAxisCount. */ 283 F16DOT16 value; /* A numeric value for this attribute value. */ 284 public: 285 DEFINE_SIZE_STATIC (6); 286 }; 287 288 struct AxisValueFormat4 289 { get_axis_recordOT::AxisValueFormat4290 const AxisValueRecord &get_axis_record (unsigned int axis_index) const 291 { return axisValues.as_array (axisCount)[axis_index]; } 292 keep_axis_valueOT::AxisValueFormat4293 bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, 294 const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const 295 { 296 hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount); 297 298 for (const auto& rec : axis_value_records) 299 { 300 unsigned axis_idx = rec.get_axis_index (); 301 float axis_value = rec.get_value (); 302 hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag (); 303 304 if (user_axes_location->has (axis_tag) && 305 fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f) 306 return false; 307 } 308 309 return true; 310 } 311 subsetOT::AxisValueFormat4312 bool subset (hb_subset_context_t *c, 313 const hb_array_t<const StatAxisRecord> axis_records) const 314 { 315 TRACE_SUBSET (this); 316 const hb_hashmap_t<hb_tag_t, float> *user_axes_location = c->plan->user_axes_location; 317 if (!keep_axis_value (axis_records, user_axes_location)) 318 return_trace (false); 319 320 unsigned total_size = min_size + axisCount * AxisValueRecord::static_size; 321 auto *out = c->serializer->allocate_size<AxisValueFormat4> (total_size); 322 if (unlikely (!out)) return_trace (false); 323 hb_memcpy (out, this, total_size); 324 return_trace (true); 325 } 326 get_value_name_idOT::AxisValueFormat4327 hb_ot_name_id_t get_value_name_id () const { return valueNameID; } 328 sanitizeOT::AxisValueFormat4329 bool sanitize (hb_sanitize_context_t *c) const 330 { 331 TRACE_SANITIZE (this); 332 return_trace (likely (c->check_struct (this) && 333 axisValues.sanitize (c, axisCount))); 334 } 335 336 protected: 337 HBUINT16 format; /* Format identifier — set to 4. */ 338 HBUINT16 axisCount; /* The total number of axes contributing to 339 * this axis-values combination. */ 340 HBUINT16 flags; /* Flags — see below for details. */ 341 NameID valueNameID; /* The name ID for entries in the 'name' table 342 * that provide a display string for this 343 * attribute value. */ 344 UnsizedArrayOf<AxisValueRecord> 345 axisValues; /* Array of AxisValue records that provide the 346 * combination of axis values, one for each 347 * contributing axis. */ 348 public: 349 DEFINE_SIZE_ARRAY (8, axisValues); 350 }; 351 352 struct AxisValue 353 { get_valueOT::AxisValue354 bool get_value (unsigned int axis_index) const 355 { 356 switch (u.format) 357 { 358 case 1: return u.format1.get_value (); 359 case 2: return u.format2.get_value (); 360 case 3: return u.format3.get_value (); 361 case 4: return u.format4.get_axis_record (axis_index).get_value (); 362 default:return 0; 363 } 364 } 365 get_axis_indexOT::AxisValue366 unsigned int get_axis_index () const 367 { 368 switch (u.format) 369 { 370 case 1: return u.format1.get_axis_index (); 371 case 2: return u.format2.get_axis_index (); 372 case 3: return u.format3.get_axis_index (); 373 /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */ 374 default:return -1; 375 } 376 } 377 get_value_name_idOT::AxisValue378 hb_ot_name_id_t get_value_name_id () const 379 { 380 switch (u.format) 381 { 382 case 1: return u.format1.get_value_name_id (); 383 case 2: return u.format2.get_value_name_id (); 384 case 3: return u.format3.get_value_name_id (); 385 case 4: return u.format4.get_value_name_id (); 386 default:return HB_OT_NAME_ID_INVALID; 387 } 388 } 389 390 template <typename context_t, typename ...Ts> dispatchOT::AxisValue391 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 392 { 393 TRACE_DISPATCH (this, u.format); 394 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 395 switch (u.format) { 396 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 397 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 398 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...)); 399 case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...)); 400 default:return_trace (c->default_return_value ()); 401 } 402 } 403 keep_axis_valueOT::AxisValue404 bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records, 405 hb_hashmap_t<hb_tag_t, float> *user_axes_location) const 406 { 407 switch (u.format) 408 { 409 case 1: return u.format1.keep_axis_value (axis_records, user_axes_location); 410 case 2: return u.format2.keep_axis_value (axis_records, user_axes_location); 411 case 3: return u.format3.keep_axis_value (axis_records, user_axes_location); 412 case 4: return u.format4.keep_axis_value (axis_records, user_axes_location); 413 default:return false; 414 } 415 } 416 sanitizeOT::AxisValue417 bool sanitize (hb_sanitize_context_t *c) const 418 { 419 TRACE_SANITIZE (this); 420 if (unlikely (!c->check_struct (this))) 421 return_trace (false); 422 423 switch (u.format) 424 { 425 case 1: return_trace (u.format1.sanitize (c)); 426 case 2: return_trace (u.format2.sanitize (c)); 427 case 3: return_trace (u.format3.sanitize (c)); 428 case 4: return_trace (u.format4.sanitize (c)); 429 default:return_trace (true); 430 } 431 } 432 433 protected: 434 union 435 { 436 HBUINT16 format; 437 AxisValueFormat1 format1; 438 AxisValueFormat2 format2; 439 AxisValueFormat3 format3; 440 AxisValueFormat4 format4; 441 } u; 442 public: 443 DEFINE_SIZE_UNION (2, format); 444 }; 445 446 struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>> 447 { subsetOT::AxisValueOffsetArray448 bool subset (hb_subset_context_t *c, 449 unsigned axisValueCount, 450 unsigned& count, 451 const hb_array_t<const StatAxisRecord> axis_records) const 452 { 453 TRACE_SUBSET (this); 454 auto *out = c->serializer->start_embed (this); 455 if (unlikely (!out)) return_trace (false); 456 457 auto axisValueOffsets = as_array (axisValueCount); 458 count = 0; 459 for (const auto& offset : axisValueOffsets) 460 { 461 if (!offset) continue; 462 auto o_snap = c->serializer->snapshot (); 463 auto *o = c->serializer->embed (offset); 464 if (!o) return_trace (false); 465 if (!o->serialize_subset (c, offset, this, axis_records)) 466 { 467 c->serializer->revert (o_snap); 468 continue; 469 } 470 count++; 471 } 472 473 return_trace (count); 474 } 475 }; 476 477 struct STAT 478 { 479 static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT; 480 has_dataOT::STAT481 bool has_data () const { return version.to_int (); } 482 get_valueOT::STAT483 bool get_value (hb_tag_t tag, float *value) const 484 { 485 unsigned int axis_index; 486 if (!get_design_axes ().lfind (tag, &axis_index)) return false; 487 488 hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets (); 489 for (unsigned int i = 0; i < axis_values.length; i++) 490 { 491 const AxisValue& axis_value = this+axis_values[i]; 492 if (axis_value.get_axis_index () == axis_index) 493 { 494 if (value) 495 *value = axis_value.get_value (axis_index); 496 return true; 497 } 498 } 499 return false; 500 } 501 get_design_axis_countOT::STAT502 unsigned get_design_axis_count () const { return designAxisCount; } 503 get_axis_record_name_idOT::STAT504 hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const 505 { 506 if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID; 507 const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index]; 508 return axis_record.get_name_id (); 509 } 510 get_axis_value_countOT::STAT511 unsigned get_axis_value_count () const { return axisValueCount; } 512 get_axis_value_name_idOT::STAT513 hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const 514 { 515 if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID; 516 const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]); 517 return axis_value.get_value_name_id (); 518 } 519 collect_name_idsOT::STAT520 void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location, 521 hb_set_t *nameids_to_retain /* OUT */) const 522 { 523 if (!has_data ()) return; 524 525 + get_design_axes () 526 | hb_map (&StatAxisRecord::get_name_id) 527 | hb_sink (nameids_to_retain) 528 ; 529 530 auto designAxes = get_design_axes (); 531 532 + get_axis_value_offsets () 533 | hb_map (hb_add (&(this + offsetToAxisValueOffsets))) 534 | hb_filter ([&] (const AxisValue& _) 535 { return _.keep_axis_value (designAxes, user_axes_location); }) 536 | hb_map (&AxisValue::get_value_name_id) 537 | hb_sink (nameids_to_retain) 538 ; 539 } 540 subsetOT::STAT541 bool subset (hb_subset_context_t *c) const 542 { 543 TRACE_SUBSET (this); 544 STAT *out = c->serializer->embed (this); 545 if (unlikely (!out)) return_trace (false); 546 547 auto designAxes = get_design_axes (); 548 for (unsigned i = 0; i < (unsigned)designAxisCount; i++) 549 if (unlikely (!c->serializer->embed (designAxes[i]))) 550 return_trace (false); 551 552 if (designAxisCount) 553 c->serializer->check_assign (out->designAxesOffset, this->get_size (), 554 HB_SERIALIZE_ERROR_INT_OVERFLOW); 555 556 unsigned count = 0; 557 out->offsetToAxisValueOffsets.serialize_subset (c, offsetToAxisValueOffsets, this, 558 axisValueCount, count, designAxes); 559 return_trace (c->serializer->check_assign (out->axisValueCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 560 } 561 sanitizeOT::STAT562 bool sanitize (hb_sanitize_context_t *c) const 563 { 564 TRACE_SANITIZE (this); 565 return_trace (likely (c->check_struct (this) && 566 version.major == 1 && 567 version.minor > 0 && 568 designAxesOffset.sanitize (c, this, designAxisCount) && 569 offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets)))); 570 } 571 572 protected: get_design_axesOT::STAT573 hb_array_t<const StatAxisRecord> const get_design_axes () const 574 { return (this+designAxesOffset).as_array (designAxisCount); } 575 get_axis_value_offsetsOT::STAT576 hb_array_t<const Offset16To<AxisValue>> const get_axis_value_offsets () const 577 { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); } 578 579 580 protected: 581 FixedVersion<>version; /* Version of the stat table 582 * initially set to 0x00010002u */ 583 HBUINT16 designAxisSize; /* The size in bytes of each axis record. */ 584 HBUINT16 designAxisCount;/* The number of design axis records. In a 585 * font with an 'fvar' table, this value must be 586 * greater than or equal to the axisCount value 587 * in the 'fvar' table. In all fonts, must 588 * be greater than zero if axisValueCount 589 * is greater than zero. */ 590 NNOffset32To<UnsizedArrayOf<StatAxisRecord>> 591 designAxesOffset; 592 /* Offset in bytes from the beginning of 593 * the STAT table to the start of the design 594 * axes array. If designAxisCount is zero, 595 * set to zero; if designAxisCount is greater 596 * than zero, must be greater than zero. */ 597 HBUINT16 axisValueCount; /* The number of axis value tables. */ 598 NNOffset32To<AxisValueOffsetArray> 599 offsetToAxisValueOffsets; 600 /* Offset in bytes from the beginning of 601 * the STAT table to the start of the design 602 * axes value offsets array. If axisValueCount 603 * is zero, set to zero; if axisValueCount is 604 * greater than zero, must be greater than zero. */ 605 NameID elidedFallbackNameID; 606 /* Name ID used as fallback when projection of 607 * names into a particular font model produces 608 * a subfamily name containing only elidable 609 * elements. */ 610 public: 611 DEFINE_SIZE_STATIC (20); 612 }; 613 614 615 } /* namespace OT */ 616 617 618 #endif /* HB_OT_STAT_TABLE_HH */ 619