1 /* 2 * Copyright © 2016 Elie Roux <[email protected]> 3 * Copyright © 2018 Google, Inc. 4 * Copyright © 2018-2019 Ebrahim Byagowi 5 * 6 * This is part of HarfBuzz, a text shaping library. 7 * 8 * Permission is hereby granted, without written agreement and without 9 * license or royalty fees, to use, copy, modify, and distribute this 10 * software and its documentation for any purpose, provided that the 11 * above copyright notice and the following two paragraphs appear in 12 * all copies of this software. 13 * 14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 18 * DAMAGE. 19 * 20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 * 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef HB_OT_LAYOUT_BASE_TABLE_HH 30 #define HB_OT_LAYOUT_BASE_TABLE_HH 31 32 #include "hb-open-type.hh" 33 #include "hb-ot-layout-common.hh" 34 35 namespace OT { 36 37 /* 38 * BASE -- Baseline 39 * https://docs.microsoft.com/en-us/typography/opentype/spec/base 40 */ 41 42 struct BaseCoordFormat1 43 { get_coordOT::BaseCoordFormat144 hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const 45 { 46 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); 47 } 48 subsetOT::BaseCoordFormat149 bool subset (hb_subset_context_t *c) const 50 { 51 TRACE_SUBSET (this); 52 return_trace ((bool) c->serializer->embed (*this)); 53 } 54 sanitizeOT::BaseCoordFormat155 bool sanitize (hb_sanitize_context_t *c) const 56 { 57 TRACE_SANITIZE (this); 58 return_trace (c->check_struct (this)); 59 } 60 61 protected: 62 HBUINT16 format; /* Format identifier--format = 1 */ 63 FWORD coordinate; /* X or Y value, in design units */ 64 public: 65 DEFINE_SIZE_STATIC (4); 66 }; 67 68 struct BaseCoordFormat2 69 { get_coordOT::BaseCoordFormat270 hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const 71 { 72 /* TODO */ 73 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate); 74 } 75 subsetOT::BaseCoordFormat276 bool subset (hb_subset_context_t *c) const 77 { 78 TRACE_SUBSET (this); 79 auto *out = c->serializer->embed (*this); 80 if (unlikely (!out)) return_trace (false); 81 82 return_trace (c->serializer->check_assign (out->referenceGlyph, 83 c->plan->glyph_map->get (referenceGlyph), 84 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 85 } 86 sanitizeOT::BaseCoordFormat287 bool sanitize (hb_sanitize_context_t *c) const 88 { 89 TRACE_SANITIZE (this); 90 return_trace (c->check_struct (this)); 91 } 92 93 protected: 94 HBUINT16 format; /* Format identifier--format = 2 */ 95 FWORD coordinate; /* X or Y value, in design units */ 96 HBGlyphID16 referenceGlyph; /* Glyph ID of control glyph */ 97 HBUINT16 coordPoint; /* Index of contour point on the 98 * reference glyph */ 99 public: 100 DEFINE_SIZE_STATIC (8); 101 }; 102 103 struct BaseCoordFormat3 104 { get_coordOT::BaseCoordFormat3105 hb_position_t get_coord (hb_font_t *font, 106 const ItemVariationStore &var_store, 107 hb_direction_t direction) const 108 { 109 const Device &device = this+deviceTable; 110 111 return HB_DIRECTION_IS_HORIZONTAL (direction) 112 ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store) 113 : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store); 114 } 115 collect_variation_indicesOT::BaseCoordFormat3116 void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const 117 { 118 unsigned varidx = (this+deviceTable).get_variation_index (); 119 varidx_set.add (varidx); 120 } 121 subsetOT::BaseCoordFormat3122 bool subset (hb_subset_context_t *c) const 123 { 124 TRACE_SUBSET (this); 125 auto *out = c->serializer->embed (*this); 126 if (unlikely (!out)) return_trace (false); 127 128 if (!c->plan->pinned_at_default) 129 { 130 unsigned var_idx = (this+deviceTable).get_variation_index (); 131 if (var_idx != VarIdx::NO_VARIATION) 132 { 133 hb_pair_t<unsigned, int> *v; 134 if (!c->plan->base_variation_idx_map.has (var_idx, &v)) 135 return_trace (false); 136 137 if (unlikely (!c->serializer->check_assign (out->coordinate, coordinate + hb_second (*v), 138 HB_SERIALIZE_ERROR_INT_OVERFLOW))) 139 return_trace (false); 140 } 141 } 142 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, 143 this, 0, 144 hb_serialize_context_t::Head, 145 &c->plan->base_variation_idx_map)); 146 } 147 sanitizeOT::BaseCoordFormat3148 bool sanitize (hb_sanitize_context_t *c) const 149 { 150 TRACE_SANITIZE (this); 151 return_trace (likely (c->check_struct (this) && 152 deviceTable.sanitize (c, this))); 153 } 154 155 protected: 156 HBUINT16 format; /* Format identifier--format = 3 */ 157 FWORD coordinate; /* X or Y value, in design units */ 158 Offset16To<Device> 159 deviceTable; /* Offset to Device table for X or 160 * Y value, from beginning of 161 * BaseCoord table (may be NULL). */ 162 public: 163 DEFINE_SIZE_STATIC (6); 164 }; 165 166 struct BaseCoord 167 { has_dataOT::BaseCoord168 bool has_data () const { return u.format; } 169 get_coordOT::BaseCoord170 hb_position_t get_coord (hb_font_t *font, 171 const ItemVariationStore &var_store, 172 hb_direction_t direction) const 173 { 174 switch (u.format) { 175 case 1: hb_barrier (); return u.format1.get_coord (font, direction); 176 case 2: hb_barrier (); return u.format2.get_coord (font, direction); 177 case 3: hb_barrier (); return u.format3.get_coord (font, var_store, direction); 178 default:return 0; 179 } 180 } 181 collect_variation_indicesOT::BaseCoord182 void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const 183 { 184 switch (u.format) { 185 case 3: hb_barrier (); u.format3.collect_variation_indices (varidx_set); 186 default:return; 187 } 188 } 189 190 template <typename context_t, typename ...Ts> dispatchOT::BaseCoord191 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 192 { 193 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); 194 TRACE_DISPATCH (this, u.format); 195 switch (u.format) { 196 case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 197 case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 198 case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...)); 199 default:return_trace (c->default_return_value ()); 200 } 201 } 202 sanitizeOT::BaseCoord203 bool sanitize (hb_sanitize_context_t *c) const 204 { 205 TRACE_SANITIZE (this); 206 if (unlikely (!u.format.sanitize (c))) return_trace (false); 207 hb_barrier (); 208 switch (u.format) { 209 case 1: hb_barrier (); return_trace (u.format1.sanitize (c)); 210 case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); 211 case 3: hb_barrier (); return_trace (u.format3.sanitize (c)); 212 default:return_trace (false); 213 } 214 } 215 216 protected: 217 union { 218 HBUINT16 format; 219 BaseCoordFormat1 format1; 220 BaseCoordFormat2 format2; 221 BaseCoordFormat3 format3; 222 } u; 223 public: 224 DEFINE_SIZE_UNION (2, format); 225 }; 226 227 struct FeatMinMaxRecord 228 { cmpOT::FeatMinMaxRecord229 int cmp (hb_tag_t key) const { return tag.cmp (key); } 230 has_dataOT::FeatMinMaxRecord231 bool has_data () const { return tag; } 232 get_feature_tagOT::FeatMinMaxRecord233 hb_tag_t get_feature_tag () const { return tag; } 234 get_min_maxOT::FeatMinMaxRecord235 void get_min_max (const BaseCoord **min, const BaseCoord **max) const 236 { 237 if (likely (min)) *min = &(this+minCoord); 238 if (likely (max)) *max = &(this+maxCoord); 239 } 240 collect_variation_indicesOT::FeatMinMaxRecord241 void collect_variation_indices (const hb_subset_plan_t* plan, 242 const void *base, 243 hb_set_t& varidx_set /* OUT */) const 244 { 245 if (!plan->layout_features.has (tag)) 246 return; 247 248 (base+minCoord).collect_variation_indices (varidx_set); 249 (base+maxCoord).collect_variation_indices (varidx_set); 250 } 251 subsetOT::FeatMinMaxRecord252 bool subset (hb_subset_context_t *c, 253 const void *base) const 254 { 255 TRACE_SUBSET (this); 256 auto *out = c->serializer->embed (*this); 257 if (unlikely (!out)) return_trace (false); 258 if (!(out->minCoord.serialize_subset (c, minCoord, base))) 259 return_trace (false); 260 261 return_trace (out->maxCoord.serialize_subset (c, maxCoord, base)); 262 } 263 sanitizeOT::FeatMinMaxRecord264 bool sanitize (hb_sanitize_context_t *c, const void *base) const 265 { 266 TRACE_SANITIZE (this); 267 return_trace (likely (c->check_struct (this) && 268 minCoord.sanitize (c, base) && 269 maxCoord.sanitize (c, base))); 270 } 271 272 protected: 273 Tag tag; /* 4-byte feature identification tag--must 274 * match feature tag in FeatureList */ 275 Offset16To<BaseCoord> 276 minCoord; /* Offset to BaseCoord table that defines 277 * the minimum extent value, from beginning 278 * of MinMax table (may be NULL) */ 279 Offset16To<BaseCoord> 280 maxCoord; /* Offset to BaseCoord table that defines 281 * the maximum extent value, from beginning 282 * of MinMax table (may be NULL) */ 283 public: 284 DEFINE_SIZE_STATIC (8); 285 }; 286 287 struct MinMax 288 { get_min_maxOT::MinMax289 void get_min_max (hb_tag_t feature_tag, 290 const BaseCoord **min, 291 const BaseCoord **max) const 292 { 293 const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag); 294 if (minMaxCoord.has_data ()) 295 minMaxCoord.get_min_max (min, max); 296 else 297 { 298 if (likely (min)) *min = &(this+minCoord); 299 if (likely (max)) *max = &(this+maxCoord); 300 } 301 } 302 collect_variation_indicesOT::MinMax303 void collect_variation_indices (const hb_subset_plan_t* plan, 304 hb_set_t& varidx_set /* OUT */) const 305 { 306 (this+minCoord).collect_variation_indices (varidx_set); 307 (this+maxCoord).collect_variation_indices (varidx_set); 308 for (const FeatMinMaxRecord& record : featMinMaxRecords) 309 record.collect_variation_indices (plan, this, varidx_set); 310 } 311 subsetOT::MinMax312 bool subset (hb_subset_context_t *c) const 313 { 314 TRACE_SUBSET (this); 315 auto *out = c->serializer->start_embed (*this); 316 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 317 318 if (!(out->minCoord.serialize_subset (c, minCoord, this)) || 319 !(out->maxCoord.serialize_subset (c, maxCoord, this))) 320 return_trace (false); 321 322 unsigned len = 0; 323 for (const FeatMinMaxRecord& _ : featMinMaxRecords) 324 { 325 hb_tag_t feature_tag = _.get_feature_tag (); 326 if (!c->plan->layout_features.has (feature_tag)) 327 continue; 328 329 if (!_.subset (c, this)) return false; 330 len++; 331 } 332 return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len, 333 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 334 } 335 sanitizeOT::MinMax336 bool sanitize (hb_sanitize_context_t *c) const 337 { 338 TRACE_SANITIZE (this); 339 return_trace (likely (c->check_struct (this) && 340 minCoord.sanitize (c, this) && 341 maxCoord.sanitize (c, this) && 342 featMinMaxRecords.sanitize (c, this))); 343 } 344 345 protected: 346 Offset16To<BaseCoord> 347 minCoord; /* Offset to BaseCoord table that defines 348 * minimum extent value, from the beginning 349 * of MinMax table (may be NULL) */ 350 Offset16To<BaseCoord> 351 maxCoord; /* Offset to BaseCoord table that defines 352 * maximum extent value, from the beginning 353 * of MinMax table (may be NULL) */ 354 SortedArray16Of<FeatMinMaxRecord> 355 featMinMaxRecords; 356 /* Array of FeatMinMaxRecords, in alphabetical 357 * order by featureTableTag */ 358 public: 359 DEFINE_SIZE_ARRAY (6, featMinMaxRecords); 360 }; 361 362 struct BaseValues 363 { get_base_coordOT::BaseValues364 const BaseCoord &get_base_coord (int baseline_tag_index) const 365 { 366 if (baseline_tag_index == -1) baseline_tag_index = defaultIndex; 367 return this+baseCoords[baseline_tag_index]; 368 } 369 collect_variation_indicesOT::BaseValues370 void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const 371 { 372 for (const auto& _ : baseCoords) 373 (this+_).collect_variation_indices (varidx_set); 374 } 375 subsetOT::BaseValues376 bool subset (hb_subset_context_t *c) const 377 { 378 TRACE_SUBSET (this); 379 auto *out = c->serializer->start_embed (*this); 380 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 381 out->defaultIndex = defaultIndex; 382 383 for (const auto& _ : baseCoords) 384 if (!subset_offset_array (c, out->baseCoords, this) (_)) 385 return_trace (false); 386 387 return_trace (bool (out->baseCoords)); 388 } 389 sanitizeOT::BaseValues390 bool sanitize (hb_sanitize_context_t *c) const 391 { 392 TRACE_SANITIZE (this); 393 return_trace (likely (c->check_struct (this) && 394 baseCoords.sanitize (c, this))); 395 } 396 397 protected: 398 Index defaultIndex; /* Index number of default baseline for this 399 * script — equals index position of baseline tag 400 * in baselineTags array of the BaseTagList */ 401 Array16OfOffset16To<BaseCoord> 402 baseCoords; /* Number of BaseCoord tables defined — should equal 403 * baseTagCount in the BaseTagList 404 * 405 * Array of offsets to BaseCoord tables, from beginning of 406 * BaseValues table — order matches baselineTags array in 407 * the BaseTagList */ 408 public: 409 DEFINE_SIZE_ARRAY (4, baseCoords); 410 }; 411 412 struct BaseLangSysRecord 413 { cmpOT::BaseLangSysRecord414 int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); } 415 has_dataOT::BaseLangSysRecord416 bool has_data () const { return baseLangSysTag; } 417 get_min_maxOT::BaseLangSysRecord418 const MinMax &get_min_max (const void* base) const { return base+minMax; } 419 collect_variation_indicesOT::BaseLangSysRecord420 void collect_variation_indices (const void* base, 421 const hb_subset_plan_t* plan, 422 hb_set_t& varidx_set /* OUT */) const 423 { (base+minMax).collect_variation_indices (plan, varidx_set); } 424 subsetOT::BaseLangSysRecord425 bool subset (hb_subset_context_t *c, 426 const void *base) const 427 { 428 TRACE_SUBSET (this); 429 auto *out = c->serializer->embed (*this); 430 if (unlikely (!out)) return_trace (false); 431 432 return_trace (out->minMax.serialize_subset (c, minMax, base)); 433 } 434 sanitizeOT::BaseLangSysRecord435 bool sanitize (hb_sanitize_context_t *c, const void *base) const 436 { 437 TRACE_SANITIZE (this); 438 return_trace (likely (c->check_struct (this) && 439 minMax.sanitize (c, base))); 440 } 441 442 protected: 443 Tag baseLangSysTag; /* 4-byte language system identification tag */ 444 Offset16To<MinMax> 445 minMax; /* Offset to MinMax table, from beginning 446 * of BaseScript table */ 447 public: 448 DEFINE_SIZE_STATIC (6); 449 }; 450 451 struct BaseScript 452 { get_min_maxOT::BaseScript453 const MinMax &get_min_max (hb_tag_t language_tag) const 454 { 455 const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag); 456 return record.has_data () ? record.get_min_max (this) : this+defaultMinMax; 457 } 458 get_base_coordOT::BaseScript459 const BaseCoord &get_base_coord (int baseline_tag_index) const 460 { return (this+baseValues).get_base_coord (baseline_tag_index); } 461 has_valuesOT::BaseScript462 bool has_values () const { return baseValues; } has_min_maxOT::BaseScript463 bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ } 464 collect_variation_indicesOT::BaseScript465 void collect_variation_indices (const hb_subset_plan_t* plan, 466 hb_set_t& varidx_set /* OUT */) const 467 { 468 (this+baseValues).collect_variation_indices (varidx_set); 469 (this+defaultMinMax).collect_variation_indices (plan, varidx_set); 470 471 for (const BaseLangSysRecord& _ : baseLangSysRecords) 472 _.collect_variation_indices (this, plan, varidx_set); 473 } 474 subsetOT::BaseScript475 bool subset (hb_subset_context_t *c) const 476 { 477 TRACE_SUBSET (this); 478 auto *out = c->serializer->start_embed (*this); 479 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 480 481 if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this)) 482 return_trace (false); 483 484 if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this)) 485 return_trace (false); 486 487 for (const auto& _ : baseLangSysRecords) 488 if (!_.subset (c, this)) return_trace (false); 489 490 return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len, 491 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 492 } 493 sanitizeOT::BaseScript494 bool sanitize (hb_sanitize_context_t *c) const 495 { 496 TRACE_SANITIZE (this); 497 return_trace (likely (c->check_struct (this) && 498 baseValues.sanitize (c, this) && 499 defaultMinMax.sanitize (c, this) && 500 baseLangSysRecords.sanitize (c, this))); 501 } 502 503 protected: 504 Offset16To<BaseValues> 505 baseValues; /* Offset to BaseValues table, from beginning 506 * of BaseScript table (may be NULL) */ 507 Offset16To<MinMax> 508 defaultMinMax; /* Offset to MinMax table, from beginning of 509 * BaseScript table (may be NULL) */ 510 SortedArray16Of<BaseLangSysRecord> 511 baseLangSysRecords; 512 /* Number of BaseLangSysRecords 513 * defined — may be zero (0) */ 514 515 public: 516 DEFINE_SIZE_ARRAY (6, baseLangSysRecords); 517 }; 518 519 struct BaseScriptList; 520 struct BaseScriptRecord 521 { cmpOT::BaseScriptRecord522 int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); } 523 has_dataOT::BaseScriptRecord524 bool has_data () const { return baseScriptTag; } 525 get_script_tagOT::BaseScriptRecord526 hb_tag_t get_script_tag () const { return baseScriptTag; } 527 get_base_scriptOT::BaseScriptRecord528 const BaseScript &get_base_script (const BaseScriptList *list) const 529 { return list+baseScript; } 530 collect_variation_indicesOT::BaseScriptRecord531 void collect_variation_indices (const hb_subset_plan_t* plan, 532 const void* list, 533 hb_set_t& varidx_set /* OUT */) const 534 { 535 if (!plan->layout_scripts.has (baseScriptTag)) 536 return; 537 538 (list+baseScript).collect_variation_indices (plan, varidx_set); 539 } 540 subsetOT::BaseScriptRecord541 bool subset (hb_subset_context_t *c, 542 const void *base) const 543 { 544 TRACE_SUBSET (this); 545 auto *out = c->serializer->embed (*this); 546 if (unlikely (!out)) return_trace (false); 547 548 return_trace (out->baseScript.serialize_subset (c, baseScript, base)); 549 } 550 sanitizeOT::BaseScriptRecord551 bool sanitize (hb_sanitize_context_t *c, const void *base) const 552 { 553 TRACE_SANITIZE (this); 554 return_trace (likely (c->check_struct (this) && 555 baseScript.sanitize (c, base))); 556 } 557 558 protected: 559 Tag baseScriptTag; /* 4-byte script identification tag */ 560 Offset16To<BaseScript> 561 baseScript; /* Offset to BaseScript table, from beginning 562 * of BaseScriptList */ 563 564 public: 565 DEFINE_SIZE_STATIC (6); 566 }; 567 568 struct BaseScriptList 569 { get_base_scriptOT::BaseScriptList570 const BaseScript &get_base_script (hb_tag_t script) const 571 { 572 const BaseScriptRecord *record = &baseScriptRecords.bsearch (script); 573 if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T')); 574 return record->has_data () ? record->get_base_script (this) : Null (BaseScript); 575 } 576 collect_variation_indicesOT::BaseScriptList577 void collect_variation_indices (const hb_subset_plan_t* plan, 578 hb_set_t& varidx_set /* OUT */) const 579 { 580 for (const BaseScriptRecord& _ : baseScriptRecords) 581 _.collect_variation_indices (plan, this, varidx_set); 582 } 583 subsetOT::BaseScriptList584 bool subset (hb_subset_context_t *c) const 585 { 586 TRACE_SUBSET (this); 587 auto *out = c->serializer->start_embed (*this); 588 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 589 590 unsigned len = 0; 591 for (const BaseScriptRecord& _ : baseScriptRecords) 592 { 593 hb_tag_t script_tag = _.get_script_tag (); 594 if (!c->plan->layout_scripts.has (script_tag)) 595 continue; 596 597 if (!_.subset (c, this)) return false; 598 len++; 599 } 600 return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len, 601 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 602 } 603 sanitizeOT::BaseScriptList604 bool sanitize (hb_sanitize_context_t *c) const 605 { 606 TRACE_SANITIZE (this); 607 return_trace (c->check_struct (this) && 608 baseScriptRecords.sanitize (c, this)); 609 } 610 611 protected: 612 SortedArray16Of<BaseScriptRecord> 613 baseScriptRecords; 614 615 public: 616 DEFINE_SIZE_ARRAY (2, baseScriptRecords); 617 }; 618 619 struct Axis 620 { get_baselineOT::Axis621 bool get_baseline (hb_tag_t baseline_tag, 622 hb_tag_t script_tag, 623 hb_tag_t language_tag, 624 const BaseCoord **coord) const 625 { 626 const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); 627 if (!base_script.has_values ()) 628 { 629 *coord = nullptr; 630 return false; 631 } 632 633 if (likely (coord)) 634 { 635 unsigned int tag_index = 0; 636 if (!(this+baseTagList).bfind (baseline_tag, &tag_index)) 637 { 638 *coord = nullptr; 639 return false; 640 } 641 *coord = &base_script.get_base_coord (tag_index); 642 } 643 644 return true; 645 } 646 get_min_maxOT::Axis647 bool get_min_max (hb_tag_t script_tag, 648 hb_tag_t language_tag, 649 hb_tag_t feature_tag, 650 const BaseCoord **min_coord, 651 const BaseCoord **max_coord) const 652 { 653 const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); 654 if (!base_script.has_min_max ()) 655 { 656 *min_coord = *max_coord = nullptr; 657 return false; 658 } 659 660 base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord); 661 662 return true; 663 } 664 collect_variation_indicesOT::Axis665 void collect_variation_indices (const hb_subset_plan_t* plan, 666 hb_set_t& varidx_set /* OUT */) const 667 { (this+baseScriptList).collect_variation_indices (plan, varidx_set); } 668 subsetOT::Axis669 bool subset (hb_subset_context_t *c) const 670 { 671 TRACE_SUBSET (this); 672 auto *out = c->serializer->embed (*this); 673 if (unlikely (!out)) return_trace (false); 674 675 out->baseTagList.serialize_copy (c->serializer, baseTagList, this); 676 return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this)); 677 } 678 sanitizeOT::Axis679 bool sanitize (hb_sanitize_context_t *c) const 680 { 681 TRACE_SANITIZE (this); 682 return_trace (likely (c->check_struct (this) && 683 baseTagList.sanitize (c, this) && 684 baseScriptList.sanitize (c, this))); 685 } 686 687 protected: 688 Offset16To<SortedArray16Of<Tag>> 689 baseTagList; /* Offset to BaseTagList table, from beginning 690 * of Axis table (may be NULL) 691 * Array of 4-byte baseline identification tags — must 692 * be in alphabetical order */ 693 Offset16To<BaseScriptList> 694 baseScriptList; /* Offset to BaseScriptList table, from beginning 695 * of Axis table 696 * Array of BaseScriptRecords, in alphabetical order 697 * by baseScriptTag */ 698 699 public: 700 DEFINE_SIZE_STATIC (4); 701 }; 702 703 struct BASE 704 { 705 static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE; 706 get_axisOT::BASE707 const Axis &get_axis (hb_direction_t direction) const 708 { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; } 709 has_var_storeOT::BASE710 bool has_var_store () const 711 { return version.to_int () >= 0x00010001u && varStore != 0; } 712 get_var_storeOT::BASE713 const ItemVariationStore &get_var_store () const 714 { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; } 715 collect_variation_indicesOT::BASE716 void collect_variation_indices (const hb_subset_plan_t* plan, 717 hb_set_t& varidx_set /* OUT */) const 718 { 719 (this+hAxis).collect_variation_indices (plan, varidx_set); 720 (this+vAxis).collect_variation_indices (plan, varidx_set); 721 } 722 subset_varstoreOT::BASE723 bool subset_varstore (hb_subset_context_t *c, 724 BASE *out /* OUT */) const 725 { 726 TRACE_SUBSET (this); 727 if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size)) 728 return_trace (false); 729 if (!c->plan->normalized_coords) 730 return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ())); 731 732 if (c->plan->all_axes_pinned) 733 return_trace (true); 734 735 item_variations_t item_vars; 736 if (!item_vars.instantiate (this+varStore, c->plan, true, true, 737 c->plan->base_varstore_inner_maps.as_array ())) 738 return_trace (false); 739 740 if (!out->varStore.serialize_serialize (c->serializer, 741 item_vars.has_long_word (), 742 c->plan->axis_tags, 743 item_vars.get_region_list (), 744 item_vars.get_vardata_encodings ())) 745 return_trace (false); 746 747 const hb_map_t &varidx_map = item_vars.get_varidx_map (); 748 /* base_variation_idx_map in the plan is old_varidx->(varidx, delta) 749 * mapping, new varidx is generated for subsetting, we need to remap this 750 * after instancing */ 751 for (auto _ : c->plan->base_variation_idx_map.iter_ref ()) 752 { 753 uint32_t varidx = _.second.first; 754 uint32_t *new_varidx; 755 if (varidx_map.has (varidx, &new_varidx)) 756 _.second.first = *new_varidx; 757 else 758 _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; 759 } 760 return_trace (true); 761 } 762 subsetOT::BASE763 bool subset (hb_subset_context_t *c) const 764 { 765 TRACE_SUBSET (this); 766 auto *out = c->serializer->start_embed (*this); 767 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); 768 769 out->version = version; 770 if (has_var_store () && !subset_varstore (c, out)) 771 return_trace (false); 772 773 if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this)) 774 return_trace (false); 775 776 if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this)) 777 return_trace (false); 778 779 return_trace (true); 780 } 781 get_baselineOT::BASE782 bool get_baseline (hb_font_t *font, 783 hb_tag_t baseline_tag, 784 hb_direction_t direction, 785 hb_tag_t script_tag, 786 hb_tag_t language_tag, 787 hb_position_t *base) const 788 { 789 const BaseCoord *base_coord = nullptr; 790 if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) || 791 !base_coord || !base_coord->has_data ())) 792 return false; 793 794 if (likely (base)) 795 *base = base_coord->get_coord (font, get_var_store (), direction); 796 797 return true; 798 } 799 get_min_maxOT::BASE800 bool get_min_max (hb_font_t *font, 801 hb_direction_t direction, 802 hb_tag_t script_tag, 803 hb_tag_t language_tag, 804 hb_tag_t feature_tag, 805 hb_position_t *min, 806 hb_position_t *max) const 807 { 808 const BaseCoord *min_coord, *max_coord; 809 if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag, 810 &min_coord, &max_coord)) 811 return false; 812 813 const ItemVariationStore &var_store = get_var_store (); 814 if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction); 815 if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction); 816 return true; 817 } 818 sanitizeOT::BASE819 bool sanitize (hb_sanitize_context_t *c) const 820 { 821 TRACE_SANITIZE (this); 822 return_trace (likely (c->check_struct (this) && 823 hb_barrier () && 824 likely (version.major == 1) && 825 hAxis.sanitize (c, this) && 826 vAxis.sanitize (c, this) && 827 (version.to_int () < 0x00010001u || varStore.sanitize (c, this)))); 828 } 829 830 protected: 831 FixedVersion<>version; /* Version of the BASE table */ 832 Offset16To<Axis>hAxis; /* Offset to horizontal Axis table, from beginning 833 * of BASE table (may be NULL) */ 834 Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning 835 * of BASE table (may be NULL) */ 836 Offset32To<ItemVariationStore> 837 varStore; /* Offset to the table of Item Variation 838 * Store--from beginning of BASE 839 * header (may be NULL). Introduced 840 * in version 0x00010001. */ 841 public: 842 DEFINE_SIZE_MIN (8); 843 }; 844 845 846 } /* namespace OT */ 847 848 849 #endif /* HB_OT_LAYOUT_BASE_TABLE_HH */ 850