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 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_OT_CMAP_TABLE_HH 28 #define HB_OT_CMAP_TABLE_HH 29 30 #include "hb-open-type-private.hh" 31 #include "hb-set-private.hh" 32 #include "hb-subset-plan.hh" 33 34 /* 35 * cmap -- Character to Glyph Index Mapping 36 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap 37 */ 38 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') 39 40 41 namespace OT { 42 43 44 struct CmapSubtableFormat0 45 { 46 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 47 { 48 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; 49 if (!gid) 50 return false; 51 *glyph = gid; 52 return true; 53 } 54 55 inline 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 number is set to 0. */ 63 HBUINT16 length; /* Byte length of this subtable. */ 64 HBUINT16 language; /* Ignore. */ 65 HBUINT8 glyphIdArray[256];/* An array that maps character 66 * code to glyph index values. */ 67 public: 68 DEFINE_SIZE_STATIC (6 + 256); 69 }; 70 71 struct CmapSubtableFormat4 72 { 73 struct segment_plan 74 { 75 HBUINT16 start_code; 76 HBUINT16 end_code; 77 bool use_delta; 78 }; 79 80 bool serialize (hb_serialize_context_t *c, 81 const hb_subset_plan_t *plan, 82 const hb_vector_t<segment_plan> &segments) 83 { 84 TRACE_SERIALIZE (this); 85 86 if (unlikely (!c->extend_min (*this))) return_trace (false); 87 88 this->format.set (4); 89 this->length.set (get_sub_table_size (segments)); 90 91 this->segCountX2.set (segments.len * 2); 92 this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1); 93 this->searchRange.set (2 * (1u << this->entrySelector)); 94 this->rangeShift.set (segments.len * 2 > this->searchRange 95 ? 2 * segments.len - this->searchRange 96 : 0); 97 98 HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); 99 c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding. 100 HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); 101 HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len); 102 HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len); 103 104 if (id_range_offset == nullptr) 105 return_trace (false); 106 107 for (unsigned int i = 0; i < segments.len; i++) 108 { 109 end_count[i].set (segments[i].end_code); 110 start_count[i].set (segments[i].start_code); 111 if (segments[i].use_delta) 112 { 113 hb_codepoint_t cp = segments[i].start_code; 114 hb_codepoint_t start_gid = 0; 115 if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) 116 return_trace (false); 117 id_delta[i].set (start_gid - segments[i].start_code); 118 } else { 119 id_delta[i].set (0); 120 unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; 121 HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints); 122 if (glyph_id_array == nullptr) 123 return_trace (false); 124 // From the cmap spec: 125 // 126 // id_range_offset[i]/2 127 // + (cp - segments[i].start_code) 133 // 134 // id_range_offset[i] 135 // = 136 // 2 * (glyph_id_array - id_range_offset - i) 137 id_range_offset[i].set (2 * ( 138 glyph_id_array - id_range_offset - i)); 139 for (unsigned int j = 0; j < num_codepoints; j++) 140 { 141 hb_codepoint_t cp = segments[i].start_code + j; 142 hb_codepoint_t new_gid; 143 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 144 return_trace (false); 145 glyph_id_array[j].set (new_gid); 146 } 147 } 148 } 149 150 return_trace (true); 151 } 152 153 static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments) 154 { 155 size_t segment_size = 0; 156 for (unsigned int i = 0; i < segments.len; i++) 157 { 158 // Parallel array entries 159 segment_size += 160 2 // end count 161 + 2 // start count 162 + 2 // delta 163 + 2; // range offset 164 165 if (!segments[i].use_delta) 166 // Add bytes for the glyph index array entries for this segment. 167 segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; 168 } 169 170 return min_size 171 + 2 // Padding 172 + segment_size; 173 } 174 175 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan, 176 hb_vector_t<segment_plan> *segments) 177 { 178 segment_plan *segment = nullptr; 179 hb_codepoint_t last_gid = 0; 180 181 hb_codepoint_t cp = HB_SET_VALUE_INVALID; 182 while (plan->unicodes->next (&cp)) { 183 hb_codepoint_t new_gid; 184 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 185 { 186 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); 187 return false; 188 } 189 190 if (cp > 0xFFFF) { 191 // We are now outside of unicode BMP, stop adding to this cmap. 192 break; 193 } 194 195 if (!segment 196 || cp != segment->end_code + 1u) 197 { 198 segment = segments->push (); 199 segment->start_code.set (cp); 200 segment->end_code.set (cp); 201 segment->use_delta = true; 202 } else { 203 segment->end_code.set (cp); 204 if (last_gid + 1u != new_gid) 205 // gid's are not consecutive in this segment so delta 206 // cannot be used. 207 segment->use_delta = false; 208 } 209 210 last_gid = new_gid; 211 } 212 213 // There must be a final entry with end_code == 0xFFFF. Check if we need to add one. 214 if (segment == nullptr || segment->end_code != 0xFFFF) 215 { 216 segment = segments->push (); 217 segment->start_code.set (0xFFFF); 218 segment->end_code.set (0xFFFF); 219 segment->use_delta = true; 220 } 221 222 return true; 223 } 224 225 struct accelerator_t 226 { 227 inline void init (const CmapSubtableFormat4 *subtable) 228 { 229 segCount = subtable->segCountX2 / 2; 230 endCount = subtable->values; 231 startCount = endCount + segCount + 1; 232 idDelta = startCount + segCount; 233 idRangeOffset = idDelta + segCount; 234 glyphIdArray = idRangeOffset + segCount; 235 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; 236 } 237 238 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) 239 { 240 const accelerator_t *thiz = (const accelerator_t *) obj; 241 242 /* Custom two-array bsearch. */ 243 int min = 0, max = (int) thiz->segCount - 1; 244 const HBUINT16 *startCount = thiz->startCount; 245 const HBUINT16 *endCount = thiz->endCount; 246 unsigned int i; 247 while (min <= max) 248 { 249 int mid = (min + max) / 2; 250 if (codepoint < startCount[mid]) 251 max = mid - 1; 252 else if (codepoint > endCount[mid]) 253 min = mid + 1; 254 else 255 { 256 i = mid; 257 goto found; 258 } 259 } 260 return false; 261 262 found: 263 hb_codepoint_t gid; 264 unsigned int rangeOffset = thiz->idRangeOffset[i]; 265 if (rangeOffset == 0) 266 gid = codepoint + thiz->idDelta[i]; 267 else 268 { 269 /* Somebody has been smoking... */ 270 unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount; 271 if (unlikely (index >= thiz->glyphIdArrayLength)) 272 return false; 273 gid = thiz->glyphIdArray[index]; 274 if (unlikely (!gid)) 275 return false; 276 gid += thiz->idDelta[i]; 277 } 278 279 *glyph = gid & 0xFFFFu; 280 return true; 281 } 282 283 static inline void get_all_codepoints_func (const void *obj, hb_set_t *out) 284 { 285 const accelerator_t *thiz = (const accelerator_t *) obj; 286 for (unsigned int i = 0; i < thiz->segCount; i++) 287 { 288 if (thiz->startCount[i] != 0xFFFFu 289 || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF) 290 hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]); 291 } 292 } 293 294 const HBUINT16 *endCount; 295 const HBUINT16 *startCount; 296 const HBUINT16 *idDelta; 297 const HBUINT16 *idRangeOffset; 298 const HBUINT16 *glyphIdArray; 299 unsigned int segCount; 300 unsigned int glyphIdArrayLength; 301 }; 302 303 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 304 { 305 accelerator_t accel; 306 accel.init (this); 307 return accel.get_glyph_func (&accel, codepoint, glyph); 308 } 309 310 inline bool sanitize (hb_sanitize_context_t *c) const 311 { 312 TRACE_SANITIZE (this); 313 if (unlikely (!c->check_struct (this))) 314 return_trace (false); 315 316 if (unlikely (!c->check_range (this, length))) 317 { 318 /* Some broken fonts have too long of a "length" value. 319 * If that is the case, just change the value to truncate 320 * the subtable at the end of the blob. */ 321 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, 322 (uintptr_t) (c->end - 323 (char *) this)); 324 if (!c->try_set (&length, new_length)) 325 return_trace (false); 326 } 327 328 return_trace (16 + 4 * (unsigned int) segCountX2 <= length); 329 } 330 331 332 333 protected: 334 HBUINT16 format; /* Format number is set to 4. */ 335 HBUINT16 length; /* This is the length in bytes of the 336 * subtable. */ 337 HBUINT16 language; /* Ignore. */ 338 HBUINT16 segCountX2; /* 2 x segCount. */ 339 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */ 340 HBUINT16 entrySelector; /* log2(searchRange/2) */ 341 HBUINT16 rangeShift; /* 2 x segCount - searchRange */ 342 343 HBUINT16 values[VAR]; 344 #if 0 345 HBUINT16 endCount[segCount]; /* End characterCode for each segment, 346 * last=0xFFFFu. */ 347 HBUINT16 reservedPad; /* Set to 0. */ 348 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ 349 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ 350 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ 351 HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ 352 #endif 353 354 public: 355 DEFINE_SIZE_ARRAY (14, values); 356 }; 357 358 struct CmapSubtableLongGroup 359 { 360 friend struct CmapSubtableFormat12; 361 friend struct CmapSubtableFormat13; 362 template<typename U> 363 friend struct CmapSubtableLongSegmented; 364 friend struct cmap; 365 366 int cmp (hb_codepoint_t codepoint) const 367 { 368 if (codepoint < startCharCode) return -1; 369 if (codepoint > endCharCode) return +1; 370 return 0; 371 } 372 373 inline bool sanitize (hb_sanitize_context_t *c) const 374 { 375 TRACE_SANITIZE (this); 376 return_trace (c->check_struct (this)); 377 } 378 379 private: 380 HBUINT32 startCharCode; /* First character code in this group. */ 381 HBUINT32 endCharCode; /* Last character code in this group. */ 382 HBUINT32 glyphID; /* Glyph index; interpretation depends on 383 * subtable format. */ 384 public: 385 DEFINE_SIZE_STATIC (12); 386 }; 387 388 template <typename UINT> 389 struct CmapSubtableTrimmed 390 { 391 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 392 { 393 /* Rely on our implicit array bound-checking. */ 394 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; 395 if (!gid) 396 return false; 397 *glyph = gid; 398 return true; 399 } 400 401 inline bool sanitize (hb_sanitize_context_t *c) const 402 { 403 TRACE_SANITIZE (this); 404 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); 405 } 406 407 protected: 408 UINT formatReserved; /* Subtable format and (maybe) padding. */ 409 UINT length; /* Byte length of this subtable. */ 410 UINT language; /* Ignore. */ 411 UINT startCharCode; /* First character code covered. */ 412 ArrayOf<GlyphID, UINT> 413 glyphIdArray; /* Array of glyph index values for character 414 * codes in the range. */ 415 public: 416 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); 417 }; 418 419 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; 420 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; 421 422 template <typename T> 423 struct CmapSubtableLongSegmented 424 { 425 friend struct cmap; 426 427 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 428 { 429 int i = groups.bsearch (codepoint); 430 if (i == -1) 431 return false; 432 *glyph = T::group_get_glyph (groups[i], codepoint); 433 return true; 434 } 435 436 inline void get_all_codepoints (hb_set_t *out) const 437 { 438 for (unsigned int i = 0; i < this->groups.len; i++) { 439 hb_set_add_range (out, 440 this->groups[i].startCharCode, 441 this->groups[i].endCharCode); 442 } 443 } 444 445 inline bool sanitize (hb_sanitize_context_t *c) const 446 { 447 TRACE_SANITIZE (this); 448 return_trace (c->check_struct (this) && groups.sanitize (c)); 449 } 450 451 inline bool serialize (hb_serialize_context_t *c, 452 const hb_vector_t<CmapSubtableLongGroup> &group_data) 453 { 454 TRACE_SERIALIZE (this); 455 if (unlikely (!c->extend_min (*this))) return_trace (false); 456 Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len); 457 if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false); 458 return true; 459 } 460 461 protected: 462 HBUINT16 format; /* Subtable format; set to 12. */ 463 HBUINT16 reserved; /* Reserved; set to 0. */ 464 HBUINT32 length; /* Byte length of this subtable. */ 465 HBUINT32 language; /* Ignore. */ 466 SortedArrayOf<CmapSubtableLongGroup, HBUINT32> 467 groups; /* Groupings. */ 468 public: 469 DEFINE_SIZE_ARRAY (16, groups); 470 }; 471 472 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> 473 { 474 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 475 hb_codepoint_t u) 476 { return group.glyphID + (u - group.startCharCode); } 477 478 479 bool serialize (hb_serialize_context_t *c, 480 const hb_vector_t<CmapSubtableLongGroup> &groups) 481 { 482 if (unlikely (!c->extend_min (*this))) return false; 483 484 this->format.set (12); 485 this->reserved.set (0); 486 this->length.set (get_sub_table_size (groups)); 487 488 return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups); 489 } 490 491 static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups) 492 { 493 return 16 + 12 * groups.len; 494 } 495 496 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan, 497 hb_vector_t<CmapSubtableLongGroup> *groups) 498 { 499 CmapSubtableLongGroup *group = nullptr; 500 501 hb_codepoint_t cp = HB_SET_VALUE_INVALID; 502 while (plan->unicodes->next (&cp)) { 503 hb_codepoint_t new_gid; 504 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 505 { 506 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); 507 return false; 508 } 509 510 if (!group || !_is_gid_consecutive (group, cp, new_gid)) 511 { 512 group = groups->push (); 513 group->startCharCode.set (cp); 514 group->endCharCode.set (cp); 515 group->glyphID.set (new_gid); 516 } else 517 { 518 group->endCharCode.set (cp); 519 } 520 } 521 522 DEBUG_MSG(SUBSET, nullptr, "cmap"); 523 for (unsigned int i = 0; i < groups->len; i++) { 524 CmapSubtableLongGroup& group = (*groups)[i]; 525 DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode)); 526 } 527 528 return true; 529 } 530 531 private: 532 static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group, 533 hb_codepoint_t cp, 534 hb_codepoint_t new_gid) 535 { 536 return (cp - 1 == group->endCharCode) && 537 new_gid == group->glyphID + (cp - group->startCharCode); 538 } 539 540 }; 541 542 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> 543 { 544 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 545 hb_codepoint_t u HB_UNUSED) 546 { return group.glyphID; } 547 }; 548 549 typedef enum 550 { 551 GLYPH_VARIANT_NOT_FOUND = 0, 552 GLYPH_VARIANT_FOUND = 1, 553 GLYPH_VARIANT_USE_DEFAULT = 2 554 } glyph_variant_t; 555 556 struct UnicodeValueRange 557 { 558 inline int cmp (const hb_codepoint_t &codepoint) const 559 { 560 if (codepoint < startUnicodeValue) return -1; 561 if (codepoint > startUnicodeValue + additionalCount) return +1; 562 return 0; 563 } 564 565 inline bool sanitize (hb_sanitize_context_t *c) const 566 { 567 TRACE_SANITIZE (this); 568 return_trace (c->check_struct (this)); 569 } 570 571 HBUINT24 startUnicodeValue; /* First value in this range. */ 572 HBUINT8 additionalCount; /* Number of additional values in this 573 * range. */ 574 public: 575 DEFINE_SIZE_STATIC (4); 576 }; 577 578 typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS; 579 580 struct UVSMapping 581 { 582 inline int cmp (const hb_codepoint_t &codepoint) const 583 { 584 return unicodeValue.cmp (codepoint); 585 } 586 587 inline bool sanitize (hb_sanitize_context_t *c) const 588 { 589 TRACE_SANITIZE (this); 590 return_trace (c->check_struct (this)); 591 } 592 593 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ 594 GlyphID glyphID; /* Glyph ID of the UVS */ 595 public: 596 DEFINE_SIZE_STATIC (5); 597 }; 598 599 typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS; 600 601 struct VariationSelectorRecord 602 { 603 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint, 604 hb_codepoint_t *glyph, 605 const void *base) const 606 { 607 int i; 608 const DefaultUVS &defaults = base+defaultUVS; 609 i = defaults.bsearch (codepoint); 610 if (i != -1) 611 return GLYPH_VARIANT_USE_DEFAULT; 612 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; 613 i = nonDefaults.bsearch (codepoint); 614 if (i != -1) 615 { 616 *glyph = nonDefaults[i].glyphID; 617 return GLYPH_VARIANT_FOUND; 618 } 619 return GLYPH_VARIANT_NOT_FOUND; 620 } 621 622 inline int cmp (const hb_codepoint_t &variation_selector) const 623 { 624 return varSelector.cmp (variation_selector); 625 } 626 627 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 628 { 629 TRACE_SANITIZE (this); 630 return_trace (c->check_struct (this) && 631 defaultUVS.sanitize (c, base) && 632 nonDefaultUVS.sanitize (c, base)); 633 } 634 635 HBUINT24 varSelector; /* Variation selector. */ 636 LOffsetTo<DefaultUVS> 637 defaultUVS; /* Offset to Default UVS Table. May be 0. */ 638 LOffsetTo<NonDefaultUVS> 639 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ 640 public: 641 DEFINE_SIZE_STATIC (11); 642 }; 643 644 struct CmapSubtableFormat14 645 { 646 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, 647 hb_codepoint_t variation_selector, 648 hb_codepoint_t *glyph) const 649 { 650 return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); 651 } 652 653 inline bool sanitize (hb_sanitize_context_t *c) const 654 { 655 TRACE_SANITIZE (this); 656 return_trace (c->check_struct (this) && 657 record.sanitize (c, this)); 658 } 659 660 protected: 661 HBUINT16 format; /* Format number is set to 14. */ 662 HBUINT32 length; /* Byte length of this subtable. */ 663 SortedArrayOf<VariationSelectorRecord, HBUINT32> 664 record; /* Variation selector records; sorted 665 * in increasing order of `varSelector'. */ 666 public: 667 DEFINE_SIZE_ARRAY (10, record); 668 }; 669 670 struct CmapSubtable 671 { 672 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ 673 674 inline bool get_glyph (hb_codepoint_t codepoint, 675 hb_codepoint_t *glyph) const 676 { 677 switch (u.format) { 678 case 0: return u.format0 .get_glyph (codepoint, glyph); 679 case 4: return u.format4 .get_glyph (codepoint, glyph); 680 case 6: return u.format6 .get_glyph (codepoint, glyph); 681 case 10: return u.format10.get_glyph (codepoint, glyph); 682 case 12: return u.format12.get_glyph (codepoint, glyph); 683 case 13: return u.format13.get_glyph (codepoint, glyph); 684 case 14: 685 default: return false; 686 } 687 } 688 689 inline bool sanitize (hb_sanitize_context_t *c) const 690 { 691 TRACE_SANITIZE (this); 692 if (!u.format.sanitize (c)) return_trace (false); 693 switch (u.format) { 694 case 0: return_trace (u.format0 .sanitize (c)); 695 case 4: return_trace (u.format4 .sanitize (c)); 696 case 6: return_trace (u.format6 .sanitize (c)); 697 case 10: return_trace (u.format10.sanitize (c)); 698 case 12: return_trace (u.format12.sanitize (c)); 699 case 13: return_trace (u.format13.sanitize (c)); 700 case 14: return_trace (u.format14.sanitize (c)); 701 default:return_trace (true); 702 } 703 } 704 705 public: 706 union { 707 HBUINT16 format; /* Format identifier */ 708 CmapSubtableFormat0 format0; 709 CmapSubtableFormat4 format4; 710 CmapSubtableFormat6 format6; 711 CmapSubtableFormat10 format10; 712 CmapSubtableFormat12 format12; 713 CmapSubtableFormat13 format13; 714 CmapSubtableFormat14 format14; 715 } u; 716 public: 717 DEFINE_SIZE_UNION (2, format); 718 }; 719 720 721 struct EncodingRecord 722 { 723 inline int cmp (const EncodingRecord &other) const 724 { 725 int ret; 726 ret = platformID.cmp (other.platformID); 727 if (ret) return ret; 728 ret = encodingID.cmp (other.encodingID); 729 if (ret) return ret; 730 return 0; 731 } 732 733 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 734 { 735 TRACE_SANITIZE (this); 736 return_trace (c->check_struct (this) && 737 subtable.sanitize (c, base)); 738 } 739 740 HBUINT16 platformID; /* Platform ID. */ 741 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 742 LOffsetTo<CmapSubtable> 743 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ 744 public: 745 DEFINE_SIZE_STATIC (8); 746 }; 747 748 struct cmap 749 { 750 static const hb_tag_t tableTag = HB_OT_TAG_cmap; 751 752 struct subset_plan { 753 subset_plan(void) 754 { 755 format4_segments.init(); 756 format12_groups.init(); 757 } 758 759 ~subset_plan(void) 760 { 761 format4_segments.fini(); 762 format12_groups.fini(); 763 } 764 765 inline size_t final_size() const 766 { 767 return 4 // header 768 + 8 * 3 // 3 EncodingRecord 769 + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) 770 + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); 771 } 772 773 // Format 4 774 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments; 775 // Format 12 776 hb_vector_t<CmapSubtableLongGroup> format12_groups; 777 }; 778 779 inline bool sanitize (hb_sanitize_context_t *c) const 780 { 781 TRACE_SANITIZE (this); 782 return_trace (c->check_struct (this) && 783 likely (version == 0) && 784 encodingRecord.sanitize (c, this)); 785 } 786 787 inline bool _create_plan (const hb_subset_plan_t *plan, 788 subset_plan *cmap_plan) const 789 { 790 if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) 791 return false; 792 793 return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); 794 } 795 796 inline bool _subset (const hb_subset_plan_t *plan, 797 const subset_plan &cmap_subset_plan, 798 size_t dest_sz, 799 void *dest) const 800 { 801 hb_serialize_context_t c (dest, dest_sz); 802 803 OT::cmap *cmap = c.start_serialize<OT::cmap> (); 804 if (unlikely (!c.extend_min (*cmap))) 805 { 806 return false; 807 } 808 809 cmap->version.set (0); 810 811 if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3))) 812 return false; 813 814 // TODO(grieger): Convert the below to a for loop 815 816 // Format 4, Plat 0 Encoding Record 817 EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0]; 818 format4_plat0_rec.platformID.set (0); // Unicode 819 format4_plat0_rec.encodingID.set (3); 820 821 // Format 4, Plat 3 Encoding Record 822 EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1]; 823 format4_plat3_rec.platformID.set (3); // Windows 824 format4_plat3_rec.encodingID.set (1); // Unicode BMP 825 826 // Format 12 Encoding Record 827 EncodingRecord &format12_rec = cmap->encodingRecord[2]; 828 format12_rec.platformID.set (3); // Windows 829 format12_rec.encodingID.set (10); // Unicode UCS-4 830 831 // Write out format 4 sub table 832 { 833 CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap); 834 format4_plat3_rec.subtable.set (format4_plat0_rec.subtable); 835 subtable.u.format.set (4); 836 837 CmapSubtableFormat4 &format4 = subtable.u.format4; 838 if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) 839 return false; 840 } 841 842 // Write out format 12 sub table. 843 { 844 CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap); 845 subtable.u.format.set (12); 846 847 CmapSubtableFormat12 &format12 = subtable.u.format12; 848 if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) 849 return false; 850 } 851 852 c.end_serialize (); 853 854 return true; 855 } 856 857 inline bool subset (hb_subset_plan_t *plan) const 858 { 859 subset_plan cmap_subset_plan; 860 861 if (unlikely (!_create_plan (plan, &cmap_subset_plan))) 862 { 863 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan."); 864 return false; 865 } 866 867 // We now know how big our blob needs to be 868 size_t dest_sz = cmap_subset_plan.final_size(); 869 void *dest = malloc (dest_sz); 870 if (unlikely (!dest)) { 871 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); 872 return false; 873 } 874 875 if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest))) 876 { 877 DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap."); 878 free (dest); 879 return false; 880 } 881 882 // all done, write the blob into dest 883 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest, 884 dest_sz, 885 HB_MEMORY_MODE_READONLY, 886 dest, 887 free); 888 bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime); 889 hb_blob_destroy (cmap_prime); 890 return result; 891 } 892 893 struct accelerator_t 894 { 895 inline void init (hb_face_t *face) 896 { 897 this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap)); 898 const OT::cmap *cmap = this->blob->as<OT::cmap> (); 899 const OT::CmapSubtable *subtable = nullptr; 900 const OT::CmapSubtableFormat14 *subtable_uvs = nullptr; 901 902 bool symbol = false; 903 /* 32-bit subtables. */ 904 if (!subtable) subtable = cmap->find_subtable (3, 10); 905 if (!subtable) subtable = cmap->find_subtable (0, 6); 906 if (!subtable) subtable = cmap->find_subtable (0, 4); 907 /* 16-bit subtables. */ 908 if (!subtable) subtable = cmap->find_subtable (3, 1); 909 if (!subtable) subtable = cmap->find_subtable (0, 3); 910 if (!subtable) subtable = cmap->find_subtable (0, 2); 911 if (!subtable) subtable = cmap->find_subtable (0, 1); 912 if (!subtable) subtable = cmap->find_subtable (0, 0); 913 if (!subtable) 914 { 915 subtable = cmap->find_subtable (3, 0); 916 if (subtable) symbol = true; 917 } 918 /* Meh. */ 919 if (!subtable) subtable = &Null(OT::CmapSubtable); 920 921 /* UVS subtable. */ 922 if (!subtable_uvs) 923 { 924 const OT::CmapSubtable *st = cmap->find_subtable (0, 5); 925 if (st && st->u.format == 14) 926 subtable_uvs = &st->u.format14; 927 } 928 /* Meh. */ 929 if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14); 930 931 this->uvs_table = subtable_uvs; 932 933 this->get_glyph_data = subtable; 934 if (unlikely (symbol)) 935 { 936 this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>; 937 this->get_all_codepoints_func = null_get_all_codepoints_func; 938 } else { 939 switch (subtable->u.format) { 940 /* Accelerate format 4 and format 12. */ 941 default: 942 this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; 943 this->get_all_codepoints_func = null_get_all_codepoints_func; 944 break; 945 case 12: 946 this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; 947 this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>; 948 break; 949 case 4: 950 { 951 this->format4_accel.init (&subtable->u.format4); 952 this->get_glyph_data = &this->format4_accel; 953 this->get_glyph_func = this->format4_accel.get_glyph_func; 954 this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func; 955 } 956 break; 957 } 958 } 959 } 960 961 inline void fini (void) 962 { 963 hb_blob_destroy (this->blob); 964 } 965 966 inline bool get_nominal_glyph (hb_codepoint_t unicode, 967 hb_codepoint_t *glyph) const 968 { 969 return this->get_glyph_func (this->get_glyph_data, unicode, glyph); 970 } 971 972 inline bool get_variation_glyph (hb_codepoint_t unicode, 973 hb_codepoint_t variation_selector, 974 hb_codepoint_t *glyph) const 975 { 976 switch (this->uvs_table->get_glyph_variant (unicode, 977 variation_selector, 978 glyph)) 979 { 980 case OT::GLYPH_VARIANT_NOT_FOUND: return false; 981 case OT::GLYPH_VARIANT_FOUND: return true; 982 case OT::GLYPH_VARIANT_USE_DEFAULT: break; 983 } 984 985 return get_nominal_glyph (unicode, glyph); 986 } 987 988 inline void get_all_codepoints (hb_set_t *out) const 989 { 990 this->get_all_codepoints_func (get_glyph_data, out); 991 } 992 993 protected: 994 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, 995 hb_codepoint_t codepoint, 996 hb_codepoint_t *glyph); 997 typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj, 998 hb_set_t *out); 999 1000 static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out) 1001 { 1002 // NOOP 1003 } 1004 1005 template <typename Type> 1006 static inline bool get_glyph_from (const void *obj, 1007 hb_codepoint_t codepoint, 1008 hb_codepoint_t *glyph) 1009 { 1010 const Type *typed_obj = (const Type *) obj; 1011 return typed_obj->get_glyph (codepoint, glyph); 1012 } 1013 1014 template <typename Type> 1015 static inline void get_all_codepoints_from (const void *obj, 1016 hb_set_t *out) 1017 { 1018 const Type *typed_obj = (const Type *) obj; 1019 typed_obj->get_all_codepoints (out); 1020 } 1021 1022 template <typename Type> 1023 static inline bool get_glyph_from_symbol (const void *obj, 1024 hb_codepoint_t codepoint, 1025 hb_codepoint_t *glyph) 1026 { 1027 const Type *typed_obj = (const Type *) obj; 1028 if (likely (typed_obj->get_glyph (codepoint, glyph))) 1029 return true; 1030 1031 if (codepoint <= 0x00FFu) 1032 { 1033 /* For symbol-encoded OpenType fonts, we duplicate the 1034 * U+F000..F0FF range at U+0000..U+00FF. That's what 1035 * Windows seems to do, and that's hinted about at: 1036 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom 1037 * under "Non-Standard (Symbol) Fonts". */ 1038 return typed_obj->get_glyph (0xF000u + codepoint, glyph); 1039 } 1040 1041 return false; 1042 } 1043 1044 private: 1045 hb_cmap_get_glyph_func_t get_glyph_func; 1046 const void *get_glyph_data; 1047 hb_cmap_get_all_codepoints_func_t get_all_codepoints_func; 1048 1049 OT::CmapSubtableFormat4::accelerator_t format4_accel; 1050 1051 const OT::CmapSubtableFormat14 *uvs_table; 1052 hb_blob_t *blob; 1053 }; 1054 1055 protected: 1056 1057 inline const CmapSubtable *find_subtable (unsigned int platform_id, 1058 unsigned int encoding_id) const 1059 { 1060 EncodingRecord key; 1061 key.platformID.set (platform_id); 1062 key.encodingID.set (encoding_id); 1063 1064 /* Note: We can use bsearch, but since it has no performance 1065 * implications, we use lsearch and as such accept fonts with 1066 * unsorted subtable list. */ 1067 int result = encodingRecord./*bsearch*/lsearch (key); 1068 if (result == -1 || !encodingRecord[result].subtable) 1069 return nullptr; 1070 1071 return &(this+encodingRecord[result].subtable); 1072 } 1073 1074 protected: 1075 HBUINT16 version; /* Table version number (0). */ 1076 SortedArrayOf<EncodingRecord> 1077 encodingRecord; /* Encoding tables. */ 1078 public: 1079 DEFINE_SIZE_ARRAY (4, encodingRecord); 1080 }; 1081 1082 1083 } /* namespace OT */ 1084 1085 1086 #endif /* HB_OT_CMAP_TABLE_HH */ | 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 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_OT_CMAP_TABLE_HH 28 #define HB_OT_CMAP_TABLE_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-set.hh" 32 33 /* 34 * cmap -- Character to Glyph Index Mapping 35 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap 36 */ 37 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') 38 39 namespace OT { 40 41 42 struct CmapSubtableFormat0 43 { 44 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 45 { 46 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; 47 if (!gid) 48 return false; 49 *glyph = gid; 50 return true; 51 } 52 void collect_unicodes (hb_set_t *out) const 53 { 54 for (unsigned int i = 0; i < 256; i++) 55 if (glyphIdArray[i]) 56 out->add (i); 57 } 58 59 bool sanitize (hb_sanitize_context_t *c) const 60 { 61 TRACE_SANITIZE (this); 62 return_trace (c->check_struct (this)); 63 } 64 65 protected: 66 HBUINT16 format; /* Format number is set to 0. */ 67 HBUINT16 length; /* Byte length of this subtable. */ 68 HBUINT16 language; /* Ignore. */ 69 HBUINT8 glyphIdArray[256];/* An array that maps character 70 * code to glyph index values. */ 71 public: 72 DEFINE_SIZE_STATIC (6 + 256); 73 }; 74 75 struct CmapSubtableFormat4 76 { 77 struct segment_plan 78 { 79 HBUINT16 start_code; 80 HBUINT16 end_code; 81 bool use_delta; 82 }; 83 84 bool serialize (hb_serialize_context_t *c, 85 const hb_subset_plan_t *plan, 86 const hb_vector_t<segment_plan> &segments) 87 { 88 TRACE_SERIALIZE (this); 89 90 if (unlikely (!c->extend_min (*this))) return_trace (false); 91 92 this->format.set (4); 93 this->length.set (get_sub_table_size (segments)); 94 95 this->segCountX2.set (segments.length * 2); 96 this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1); 97 this->searchRange.set (2 * (1u << this->entrySelector)); 98 this->rangeShift.set (segments.length * 2 > this->searchRange 99 ? 2 * segments.length - this->searchRange 100 : 0); 101 102 HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); 103 c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding. 104 HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); 105 HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length); 106 HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); 107 108 if (id_range_offset == nullptr) 109 return_trace (false); 110 111 for (unsigned int i = 0; i < segments.length; i++) 112 { 113 end_count[i].set (segments[i].end_code); 114 start_count[i].set (segments[i].start_code); 115 if (segments[i].use_delta) 116 { 117 hb_codepoint_t cp = segments[i].start_code; 118 hb_codepoint_t start_gid = 0; 119 if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) 120 return_trace (false); 121 id_delta[i].set (start_gid - segments[i].start_code); 122 } else { 123 id_delta[i].set (0); 124 unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; 125 HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints); 126 if (glyph_id_array == nullptr) 127 return_trace (false); 128 // From the cmap spec: 129 // 130 // id_range_offset[i]/2 131 // + (cp - segments[i].start_code) 137 // 138 // id_range_offset[i] 139 // = 140 // 2 * (glyph_id_array - id_range_offset - i) 141 id_range_offset[i].set (2 * ( 142 glyph_id_array - id_range_offset - i)); 143 for (unsigned int j = 0; j < num_codepoints; j++) 144 { 145 hb_codepoint_t cp = segments[i].start_code + j; 146 hb_codepoint_t new_gid; 147 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 148 return_trace (false); 149 glyph_id_array[j].set (new_gid); 150 } 151 } 152 } 153 154 return_trace (true); 155 } 156 157 static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments) 158 { 159 size_t segment_size = 0; 160 for (unsigned int i = 0; i < segments.length; i++) 161 { 162 // Parallel array entries 163 segment_size += 164 2 // end count 165 + 2 // start count 166 + 2 // delta 167 + 2; // range offset 168 169 if (!segments[i].use_delta) 170 // Add bytes for the glyph index array entries for this segment. 171 segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; 172 } 173 174 return min_size 175 + 2 // Padding 176 + segment_size; 177 } 178 179 static bool create_sub_table_plan (const hb_subset_plan_t *plan, 180 hb_vector_t<segment_plan> *segments) 181 { 182 segment_plan *segment = nullptr; 183 hb_codepoint_t last_gid = 0; 184 185 hb_codepoint_t cp = HB_SET_VALUE_INVALID; 186 while (plan->unicodes->next (&cp)) { 187 hb_codepoint_t new_gid; 188 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 189 { 190 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); 191 return false; 192 } 193 194 /* Stop adding to cmap if we are now outside of unicode BMP. */ 195 if (cp > 0xFFFF) break; 196 197 if (!segment || 198 cp != segment->end_code + 1u) 199 { 200 segment = segments->push (); 201 segment->start_code.set (cp); 202 segment->end_code.set (cp); 203 segment->use_delta = true; 204 } else { 205 segment->end_code.set (cp); 206 if (last_gid + 1u != new_gid) 207 // gid's are not consecutive in this segment so delta 208 // cannot be used. 209 segment->use_delta = false; 210 } 211 212 last_gid = new_gid; 213 } 214 215 // There must be a final entry with end_code == 0xFFFF. Check if we need to add one. 216 if (segment == nullptr || segment->end_code != 0xFFFF) 217 { 218 segment = segments->push (); 219 segment->start_code.set (0xFFFF); 220 segment->end_code.set (0xFFFF); 221 segment->use_delta = true; 222 } 223 224 return true; 225 } 226 227 struct accelerator_t 228 { 229 accelerator_t () {} 230 accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } 231 ~accelerator_t () { fini (); } 232 233 void init (const CmapSubtableFormat4 *subtable) 234 { 235 segCount = subtable->segCountX2 / 2; 236 endCount = subtable->values.arrayZ; 237 startCount = endCount + segCount + 1; 238 idDelta = startCount + segCount; 239 idRangeOffset = idDelta + segCount; 240 glyphIdArray = idRangeOffset + segCount; 241 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; 242 } 243 void fini () {} 244 245 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 246 { 247 /* Custom two-array bsearch. */ 248 int min = 0, max = (int) this->segCount - 1; 249 const HBUINT16 *startCount = this->startCount; 250 const HBUINT16 *endCount = this->endCount; 251 unsigned int i; 252 while (min <= max) 253 { 254 int mid = ((unsigned int) min + (unsigned int) max) / 2; 255 if (codepoint < startCount[mid]) 256 max = mid - 1; 257 else if (codepoint > endCount[mid]) 258 min = mid + 1; 259 else 260 { 261 i = mid; 262 goto found; 263 } 264 } 265 return false; 266 267 found: 268 hb_codepoint_t gid; 269 unsigned int rangeOffset = this->idRangeOffset[i]; 270 if (rangeOffset == 0) 271 gid = codepoint + this->idDelta[i]; 272 else 273 { 274 /* Somebody has been smoking... */ 275 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; 276 if (unlikely (index >= this->glyphIdArrayLength)) 277 return false; 278 gid = this->glyphIdArray[index]; 279 if (unlikely (!gid)) 280 return false; 281 gid += this->idDelta[i]; 282 } 283 gid &= 0xFFFFu; 284 if (!gid) 285 return false; 286 *glyph = gid; 287 return true; 288 } 289 static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) 290 { 291 return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); 292 } 293 void collect_unicodes (hb_set_t *out) const 294 { 295 unsigned int count = this->segCount; 296 if (count && this->startCount[count - 1] == 0xFFFFu) 297 count--; /* Skip sentinel segment. */ 298 for (unsigned int i = 0; i < count; i++) 299 { 300 unsigned int rangeOffset = this->idRangeOffset[i]; 301 if (rangeOffset == 0) 302 out->add_range (this->startCount[i], this->endCount[i]); 303 else 304 { 305 for (hb_codepoint_t codepoint = this->startCount[i]; 306 codepoint <= this->endCount[i]; 307 codepoint++) 308 { 309 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; 310 if (unlikely (index >= this->glyphIdArrayLength)) 311 break; 312 hb_codepoint_t gid = this->glyphIdArray[index]; 313 if (unlikely (!gid)) 314 continue; 315 out->add (codepoint); 316 } 317 } 318 } 319 } 320 321 const HBUINT16 *endCount; 322 const HBUINT16 *startCount; 323 const HBUINT16 *idDelta; 324 const HBUINT16 *idRangeOffset; 325 const HBUINT16 *glyphIdArray; 326 unsigned int segCount; 327 unsigned int glyphIdArrayLength; 328 }; 329 330 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 331 { 332 accelerator_t accel (this); 333 return accel.get_glyph_func (&accel, codepoint, glyph); 334 } 335 void collect_unicodes (hb_set_t *out) const 336 { 337 accelerator_t accel (this); 338 accel.collect_unicodes (out); 339 } 340 341 bool sanitize (hb_sanitize_context_t *c) const 342 { 343 TRACE_SANITIZE (this); 344 if (unlikely (!c->check_struct (this))) 345 return_trace (false); 346 347 if (unlikely (!c->check_range (this, length))) 348 { 349 /* Some broken fonts have too long of a "length" value. 350 * If that is the case, just change the value to truncate 351 * the subtable at the end of the blob. */ 352 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, 353 (uintptr_t) (c->end - 354 (char *) this)); 355 if (!c->try_set (&length, new_length)) 356 return_trace (false); 357 } 358 359 return_trace (16 + 4 * (unsigned int) segCountX2 <= length); 360 } 361 362 363 364 protected: 365 HBUINT16 format; /* Format number is set to 4. */ 366 HBUINT16 length; /* This is the length in bytes of the 367 * subtable. */ 368 HBUINT16 language; /* Ignore. */ 369 HBUINT16 segCountX2; /* 2 x segCount. */ 370 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */ 371 HBUINT16 entrySelector; /* log2(searchRange/2) */ 372 HBUINT16 rangeShift; /* 2 x segCount - searchRange */ 373 374 UnsizedArrayOf<HBUINT16> 375 values; 376 #if 0 377 HBUINT16 endCount[segCount]; /* End characterCode for each segment, 378 * last=0xFFFFu. */ 379 HBUINT16 reservedPad; /* Set to 0. */ 380 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ 381 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ 382 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ 383 UnsizedArrayOf<HBUINT16> 384 glyphIdArray; /* Glyph index array (arbitrary length) */ 385 #endif 386 387 public: 388 DEFINE_SIZE_ARRAY (14, values); 389 }; 390 391 struct CmapSubtableLongGroup 392 { 393 friend struct CmapSubtableFormat12; 394 friend struct CmapSubtableFormat13; 395 template<typename U> 396 friend struct CmapSubtableLongSegmented; 397 friend struct cmap; 398 399 int cmp (hb_codepoint_t codepoint) const 400 { 401 if (codepoint < startCharCode) return -1; 402 if (codepoint > endCharCode) return +1; 403 return 0; 404 } 405 406 bool sanitize (hb_sanitize_context_t *c) const 407 { 408 TRACE_SANITIZE (this); 409 return_trace (c->check_struct (this)); 410 } 411 412 private: 413 HBUINT32 startCharCode; /* First character code in this group. */ 414 HBUINT32 endCharCode; /* Last character code in this group. */ 415 HBUINT32 glyphID; /* Glyph index; interpretation depends on 416 * subtable format. */ 417 public: 418 DEFINE_SIZE_STATIC (12); 419 }; 420 DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup); 421 422 template <typename UINT> 423 struct CmapSubtableTrimmed 424 { 425 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 426 { 427 /* Rely on our implicit array bound-checking. */ 428 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; 429 if (!gid) 430 return false; 431 *glyph = gid; 432 return true; 433 } 434 void collect_unicodes (hb_set_t *out) const 435 { 436 hb_codepoint_t start = startCharCode; 437 unsigned int count = glyphIdArray.len; 438 for (unsigned int i = 0; i < count; i++) 439 if (glyphIdArray[i]) 440 out->add (start + i); 441 } 442 443 bool sanitize (hb_sanitize_context_t *c) const 444 { 445 TRACE_SANITIZE (this); 446 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); 447 } 448 449 protected: 450 UINT formatReserved; /* Subtable format and (maybe) padding. */ 451 UINT length; /* Byte length of this subtable. */ 452 UINT language; /* Ignore. */ 453 UINT startCharCode; /* First character code covered. */ 454 ArrayOf<GlyphID, UINT> 455 glyphIdArray; /* Array of glyph index values for character 456 * codes in the range. */ 457 public: 458 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); 459 }; 460 461 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; 462 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; 463 464 template <typename T> 465 struct CmapSubtableLongSegmented 466 { 467 friend struct cmap; 468 469 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 470 { 471 hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); 472 if (!gid) 473 return false; 474 *glyph = gid; 475 return true; 476 } 477 478 void collect_unicodes (hb_set_t *out) const 479 { 480 for (unsigned int i = 0; i < this->groups.len; i++) { 481 out->add_range (this->groups[i].startCharCode, 482 MIN ((hb_codepoint_t) this->groups[i].endCharCode, 483 (hb_codepoint_t) HB_UNICODE_MAX)); 484 } 485 } 486 487 bool sanitize (hb_sanitize_context_t *c) const 488 { 489 TRACE_SANITIZE (this); 490 return_trace (c->check_struct (this) && groups.sanitize (c)); 491 } 492 493 bool serialize (hb_serialize_context_t *c, 494 const hb_vector_t<CmapSubtableLongGroup> &group_data) 495 { 496 TRACE_SERIALIZE (this); 497 if (unlikely (!c->extend_min (*this))) return_trace (false); 498 if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false); 499 return true; 500 } 501 502 protected: 503 HBUINT16 format; /* Subtable format; set to 12. */ 504 HBUINT16 reserved; /* Reserved; set to 0. */ 505 HBUINT32 length; /* Byte length of this subtable. */ 506 HBUINT32 language; /* Ignore. */ 507 SortedArrayOf<CmapSubtableLongGroup, HBUINT32> 508 groups; /* Groupings. */ 509 public: 510 DEFINE_SIZE_ARRAY (16, groups); 511 }; 512 513 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> 514 { 515 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 516 hb_codepoint_t u) 517 { return likely (group.startCharCode <= group.endCharCode) ? 518 group.glyphID + (u - group.startCharCode) : 0; } 519 520 521 bool serialize (hb_serialize_context_t *c, 522 const hb_vector_t<CmapSubtableLongGroup> &groups) 523 { 524 if (unlikely (!c->extend_min (*this))) return false; 525 526 this->format.set (12); 527 this->reserved.set (0); 528 this->length.set (get_sub_table_size (groups)); 529 530 return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups); 531 } 532 533 static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups) 534 { 535 return 16 + 12 * groups.length; 536 } 537 538 static bool create_sub_table_plan (const hb_subset_plan_t *plan, 539 hb_vector_t<CmapSubtableLongGroup> *groups) 540 { 541 CmapSubtableLongGroup *group = nullptr; 542 543 hb_codepoint_t cp = HB_SET_VALUE_INVALID; 544 while (plan->unicodes->next (&cp)) { 545 hb_codepoint_t new_gid; 546 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) 547 { 548 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); 549 return false; 550 } 551 552 if (!group || !_is_gid_consecutive (group, cp, new_gid)) 553 { 554 group = groups->push (); 555 group->startCharCode.set (cp); 556 group->endCharCode.set (cp); 557 group->glyphID.set (new_gid); 558 } 559 else group->endCharCode.set (cp); 560 } 561 562 DEBUG_MSG(SUBSET, nullptr, "cmap"); 563 for (unsigned int i = 0; i < groups->length; i++) { 564 CmapSubtableLongGroup& group = (*groups)[i]; 565 DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode)); 566 } 567 568 return true; 569 } 570 571 private: 572 static bool _is_gid_consecutive (CmapSubtableLongGroup *group, 573 hb_codepoint_t cp, 574 hb_codepoint_t new_gid) 575 { 576 return (cp - 1 == group->endCharCode) && 577 new_gid == group->glyphID + (cp - group->startCharCode); 578 } 579 580 }; 581 582 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> 583 { 584 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 585 hb_codepoint_t u HB_UNUSED) 586 { return group.glyphID; } 587 }; 588 589 typedef enum 590 { 591 GLYPH_VARIANT_NOT_FOUND = 0, 592 GLYPH_VARIANT_FOUND = 1, 593 GLYPH_VARIANT_USE_DEFAULT = 2 594 } glyph_variant_t; 595 596 struct UnicodeValueRange 597 { 598 int cmp (const hb_codepoint_t &codepoint) const 599 { 600 if (codepoint < startUnicodeValue) return -1; 601 if (codepoint > startUnicodeValue + additionalCount) return +1; 602 return 0; 603 } 604 605 bool sanitize (hb_sanitize_context_t *c) const 606 { 607 TRACE_SANITIZE (this); 608 return_trace (c->check_struct (this)); 609 } 610 611 HBUINT24 startUnicodeValue; /* First value in this range. */ 612 HBUINT8 additionalCount; /* Number of additional values in this 613 * range. */ 614 public: 615 DEFINE_SIZE_STATIC (4); 616 }; 617 618 struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32> 619 { 620 void collect_unicodes (hb_set_t *out) const 621 { 622 unsigned int count = len; 623 for (unsigned int i = 0; i < count; i++) 624 { 625 hb_codepoint_t first = arrayZ[i].startUnicodeValue; 626 hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount), 627 (hb_codepoint_t) HB_UNICODE_MAX); 628 out->add_range (first, last); 629 } 630 } 631 632 public: 633 DEFINE_SIZE_ARRAY (4, *this); 634 }; 635 636 struct UVSMapping 637 { 638 int cmp (const hb_codepoint_t &codepoint) const 639 { 640 return unicodeValue.cmp (codepoint); 641 } 642 643 bool sanitize (hb_sanitize_context_t *c) const 644 { 645 TRACE_SANITIZE (this); 646 return_trace (c->check_struct (this)); 647 } 648 649 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ 650 GlyphID glyphID; /* Glyph ID of the UVS */ 651 public: 652 DEFINE_SIZE_STATIC (5); 653 }; 654 655 struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32> 656 { 657 void collect_unicodes (hb_set_t *out) const 658 { 659 unsigned int count = len; 660 for (unsigned int i = 0; i < count; i++) 661 out->add (arrayZ[i].glyphID); 662 } 663 664 public: 665 DEFINE_SIZE_ARRAY (4, *this); 666 }; 667 668 struct VariationSelectorRecord 669 { 670 glyph_variant_t get_glyph (hb_codepoint_t codepoint, 671 hb_codepoint_t *glyph, 672 const void *base) const 673 { 674 if ((base+defaultUVS).bfind (codepoint)) 675 return GLYPH_VARIANT_USE_DEFAULT; 676 const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); 677 if (nonDefault.glyphID) 678 { 679 *glyph = nonDefault.glyphID; 680 return GLYPH_VARIANT_FOUND; 681 } 682 return GLYPH_VARIANT_NOT_FOUND; 683 } 684 685 void collect_unicodes (hb_set_t *out, const void *base) const 686 { 687 (base+defaultUVS).collect_unicodes (out); 688 (base+nonDefaultUVS).collect_unicodes (out); 689 } 690 691 int cmp (const hb_codepoint_t &variation_selector) const 692 { 693 return varSelector.cmp (variation_selector); 694 } 695 696 bool sanitize (hb_sanitize_context_t *c, const void *base) const 697 { 698 TRACE_SANITIZE (this); 699 return_trace (c->check_struct (this) && 700 defaultUVS.sanitize (c, base) && 701 nonDefaultUVS.sanitize (c, base)); 702 } 703 704 HBUINT24 varSelector; /* Variation selector. */ 705 LOffsetTo<DefaultUVS> 706 defaultUVS; /* Offset to Default UVS Table. May be 0. */ 707 LOffsetTo<NonDefaultUVS> 708 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ 709 public: 710 DEFINE_SIZE_STATIC (11); 711 }; 712 713 struct CmapSubtableFormat14 714 { 715 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, 716 hb_codepoint_t variation_selector, 717 hb_codepoint_t *glyph) const 718 { 719 return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); 720 } 721 722 void collect_variation_selectors (hb_set_t *out) const 723 { 724 unsigned int count = record.len; 725 for (unsigned int i = 0; i < count; i++) 726 out->add (record.arrayZ[i].varSelector); 727 } 728 void collect_variation_unicodes (hb_codepoint_t variation_selector, 729 hb_set_t *out) const 730 { 731 record.bsearch (variation_selector).collect_unicodes (out, this); 732 } 733 734 bool sanitize (hb_sanitize_context_t *c) const 735 { 736 TRACE_SANITIZE (this); 737 return_trace (c->check_struct (this) && 738 record.sanitize (c, this)); 739 } 740 741 protected: 742 HBUINT16 format; /* Format number is set to 14. */ 743 HBUINT32 length; /* Byte length of this subtable. */ 744 SortedArrayOf<VariationSelectorRecord, HBUINT32> 745 record; /* Variation selector records; sorted 746 * in increasing order of `varSelector'. */ 747 public: 748 DEFINE_SIZE_ARRAY (10, record); 749 }; 750 751 struct CmapSubtable 752 { 753 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ 754 755 bool get_glyph (hb_codepoint_t codepoint, 756 hb_codepoint_t *glyph) const 757 { 758 switch (u.format) { 759 case 0: return u.format0 .get_glyph (codepoint, glyph); 760 case 4: return u.format4 .get_glyph (codepoint, glyph); 761 case 6: return u.format6 .get_glyph (codepoint, glyph); 762 case 10: return u.format10.get_glyph (codepoint, glyph); 763 case 12: return u.format12.get_glyph (codepoint, glyph); 764 case 13: return u.format13.get_glyph (codepoint, glyph); 765 case 14: 766 default: return false; 767 } 768 } 769 void collect_unicodes (hb_set_t *out) const 770 { 771 switch (u.format) { 772 case 0: u.format0 .collect_unicodes (out); return; 773 case 4: u.format4 .collect_unicodes (out); return; 774 case 6: u.format6 .collect_unicodes (out); return; 775 case 10: u.format10.collect_unicodes (out); return; 776 case 12: u.format12.collect_unicodes (out); return; 777 case 13: u.format13.collect_unicodes (out); return; 778 case 14: 779 default: return; 780 } 781 } 782 783 bool sanitize (hb_sanitize_context_t *c) const 784 { 785 TRACE_SANITIZE (this); 786 if (!u.format.sanitize (c)) return_trace (false); 787 switch (u.format) { 788 case 0: return_trace (u.format0 .sanitize (c)); 789 case 4: return_trace (u.format4 .sanitize (c)); 790 case 6: return_trace (u.format6 .sanitize (c)); 791 case 10: return_trace (u.format10.sanitize (c)); 792 case 12: return_trace (u.format12.sanitize (c)); 793 case 13: return_trace (u.format13.sanitize (c)); 794 case 14: return_trace (u.format14.sanitize (c)); 795 default:return_trace (true); 796 } 797 } 798 799 public: 800 union { 801 HBUINT16 format; /* Format identifier */ 802 CmapSubtableFormat0 format0; 803 CmapSubtableFormat4 format4; 804 CmapSubtableFormat6 format6; 805 CmapSubtableFormat10 format10; 806 CmapSubtableFormat12 format12; 807 CmapSubtableFormat13 format13; 808 CmapSubtableFormat14 format14; 809 } u; 810 public: 811 DEFINE_SIZE_UNION (2, format); 812 }; 813 814 815 struct EncodingRecord 816 { 817 int cmp (const EncodingRecord &other) const 818 { 819 int ret; 820 ret = platformID.cmp (other.platformID); 821 if (ret) return ret; 822 ret = encodingID.cmp (other.encodingID); 823 if (ret) return ret; 824 return 0; 825 } 826 827 bool sanitize (hb_sanitize_context_t *c, const void *base) const 828 { 829 TRACE_SANITIZE (this); 830 return_trace (c->check_struct (this) && 831 subtable.sanitize (c, base)); 832 } 833 834 HBUINT16 platformID; /* Platform ID. */ 835 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 836 LOffsetTo<CmapSubtable> 837 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ 838 public: 839 DEFINE_SIZE_STATIC (8); 840 }; 841 842 struct cmap 843 { 844 static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; 845 846 struct subset_plan 847 { 848 size_t final_size () const 849 { 850 return 4 // header 851 + 8 * 3 // 3 EncodingRecord 852 + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) 853 + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); 854 } 855 856 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments; 857 hb_vector_t<CmapSubtableLongGroup> format12_groups; 858 }; 859 860 bool _create_plan (const hb_subset_plan_t *plan, 861 subset_plan *cmap_plan) const 862 { 863 if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) 864 return false; 865 866 return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); 867 } 868 869 bool _subset (const hb_subset_plan_t *plan, 870 const subset_plan &cmap_subset_plan, 871 size_t dest_sz, 872 void *dest) const 873 { 874 hb_serialize_context_t c (dest, dest_sz); 875 876 cmap *table = c.start_serialize<cmap> (); 877 if (unlikely (!c.extend_min (*table))) 878 { 879 return false; 880 } 881 882 table->version.set (0); 883 884 if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3))) 885 return false; 886 887 // TODO(grieger): Convert the below to a for loop 888 889 // Format 4, Plat 0 Encoding Record 890 EncodingRecord &format4_plat0_rec = table->encodingRecord[0]; 891 format4_plat0_rec.platformID.set (0); // Unicode 892 format4_plat0_rec.encodingID.set (3); 893 894 // Format 4, Plat 3 Encoding Record 895 EncodingRecord &format4_plat3_rec = table->encodingRecord[1]; 896 format4_plat3_rec.platformID.set (3); // Windows 897 format4_plat3_rec.encodingID.set (1); // Unicode BMP 898 899 // Format 12 Encoding Record 900 EncodingRecord &format12_rec = table->encodingRecord[2]; 901 format12_rec.platformID.set (3); // Windows 902 format12_rec.encodingID.set (10); // Unicode UCS-4 903 904 // Write out format 4 sub table 905 { 906 CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table); 907 format4_plat3_rec.subtable.set (format4_plat0_rec.subtable); 908 subtable.u.format.set (4); 909 910 CmapSubtableFormat4 &format4 = subtable.u.format4; 911 if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) 912 return false; 913 } 914 915 // Write out format 12 sub table. 916 { 917 CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table); 918 subtable.u.format.set (12); 919 920 CmapSubtableFormat12 &format12 = subtable.u.format12; 921 if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) 922 return false; 923 } 924 925 c.end_serialize (); 926 927 return true; 928 } 929 930 bool subset (hb_subset_plan_t *plan) const 931 { 932 subset_plan cmap_subset_plan; 933 934 if (unlikely (!_create_plan (plan, &cmap_subset_plan))) 935 { 936 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan."); 937 return false; 938 } 939 940 // We now know how big our blob needs to be 941 size_t dest_sz = cmap_subset_plan.final_size (); 942 void *dest = malloc (dest_sz); 943 if (unlikely (!dest)) { 944 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); 945 return false; 946 } 947 948 if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest))) 949 { 950 DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap."); 951 free (dest); 952 return false; 953 } 954 955 // all done, write the blob into dest 956 hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest, 957 dest_sz, 958 HB_MEMORY_MODE_READONLY, 959 dest, 960 free); 961 bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime); 962 hb_blob_destroy (cmap_prime); 963 return result; 964 } 965 966 const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const 967 { 968 if (symbol) *symbol = false; 969 970 const CmapSubtable *subtable; 971 972 /* 32-bit subtables. */ 973 if ((subtable = this->find_subtable (3, 10))) return subtable; 974 if ((subtable = this->find_subtable (0, 6))) return subtable; 975 if ((subtable = this->find_subtable (0, 4))) return subtable; 976 977 /* 16-bit subtables. */ 978 if ((subtable = this->find_subtable (3, 1))) return subtable; 979 if ((subtable = this->find_subtable (0, 3))) return subtable; 980 if ((subtable = this->find_subtable (0, 2))) return subtable; 981 if ((subtable = this->find_subtable (0, 1))) return subtable; 982 if ((subtable = this->find_subtable (0, 0))) return subtable; 983 984 /* Symbol subtable. */ 985 if ((subtable = this->find_subtable (3, 0))) 986 { 987 if (symbol) *symbol = true; 988 return subtable; 989 } 990 991 /* Meh. */ 992 return &Null (CmapSubtable); 993 } 994 995 struct accelerator_t 996 { 997 void init (hb_face_t *face) 998 { 999 this->table = hb_sanitize_context_t ().reference_table<cmap> (face); 1000 bool symbol; 1001 this->subtable = table->find_best_subtable (&symbol); 1002 this->subtable_uvs = &Null (CmapSubtableFormat14); 1003 { 1004 const CmapSubtable *st = table->find_subtable (0, 5); 1005 if (st && st->u.format == 14) 1006 subtable_uvs = &st->u.format14; 1007 } 1008 1009 this->get_glyph_data = subtable; 1010 if (unlikely (symbol)) 1011 { 1012 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>; 1013 } else { 1014 switch (subtable->u.format) { 1015 /* Accelerate format 4 and format 12. */ 1016 default: 1017 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>; 1018 break; 1019 case 12: 1020 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>; 1021 break; 1022 case 4: 1023 { 1024 this->format4_accel.init (&subtable->u.format4); 1025 this->get_glyph_data = &this->format4_accel; 1026 this->get_glyph_funcZ = this->format4_accel.get_glyph_func; 1027 } 1028 break; 1029 } 1030 } 1031 } 1032 1033 void fini () { this->table.destroy (); } 1034 1035 bool get_nominal_glyph (hb_codepoint_t unicode, 1036 hb_codepoint_t *glyph) const 1037 { 1038 if (unlikely (!this->get_glyph_funcZ)) return false; 1039 return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); 1040 } 1041 unsigned int get_nominal_glyphs (unsigned int count, 1042 const hb_codepoint_t *first_unicode, 1043 unsigned int unicode_stride, 1044 hb_codepoint_t *first_glyph, 1045 unsigned int glyph_stride) const 1046 { 1047 if (unlikely (!this->get_glyph_funcZ)) return 0; 1048 1049 hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; 1050 const void *get_glyph_data = this->get_glyph_data; 1051 1052 unsigned int done; 1053 for (done = 0; 1054 done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); 1055 done++) 1056 { 1057 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); 1058 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); 1059 } 1060 return done; 1061 } 1062 1063 bool get_variation_glyph (hb_codepoint_t unicode, 1064 hb_codepoint_t variation_selector, 1065 hb_codepoint_t *glyph) const 1066 { 1067 switch (this->subtable_uvs->get_glyph_variant (unicode, 1068 variation_selector, 1069 glyph)) 1070 { 1071 case GLYPH_VARIANT_NOT_FOUND: return false; 1072 case GLYPH_VARIANT_FOUND: return true; 1073 case GLYPH_VARIANT_USE_DEFAULT: break; 1074 } 1075 1076 return get_nominal_glyph (unicode, glyph); 1077 } 1078 1079 void collect_unicodes (hb_set_t *out) const 1080 { 1081 subtable->collect_unicodes (out); 1082 } 1083 void collect_variation_selectors (hb_set_t *out) const 1084 { 1085 subtable_uvs->collect_variation_selectors (out); 1086 } 1087 void collect_variation_unicodes (hb_codepoint_t variation_selector, 1088 hb_set_t *out) const 1089 { 1090 subtable_uvs->collect_variation_unicodes (variation_selector, out); 1091 } 1092 1093 protected: 1094 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, 1095 hb_codepoint_t codepoint, 1096 hb_codepoint_t *glyph); 1097 1098 template <typename Type> 1099 static bool get_glyph_from (const void *obj, 1100 hb_codepoint_t codepoint, 1101 hb_codepoint_t *glyph) 1102 { 1103 const Type *typed_obj = (const Type *) obj; 1104 return typed_obj->get_glyph (codepoint, glyph); 1105 } 1106 1107 template <typename Type> 1108 static bool get_glyph_from_symbol (const void *obj, 1109 hb_codepoint_t codepoint, 1110 hb_codepoint_t *glyph) 1111 { 1112 const Type *typed_obj = (const Type *) obj; 1113 if (likely (typed_obj->get_glyph (codepoint, glyph))) 1114 return true; 1115 1116 if (codepoint <= 0x00FFu) 1117 { 1118 /* For symbol-encoded OpenType fonts, we duplicate the 1119 * U+F000..F0FF range at U+0000..U+00FF. That's what 1120 * Windows seems to do, and that's hinted about at: 1121 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom 1122 * under "Non-Standard (Symbol) Fonts". */ 1123 return typed_obj->get_glyph (0xF000u + codepoint, glyph); 1124 } 1125 1126 return false; 1127 } 1128 1129 private: 1130 hb_nonnull_ptr_t<const CmapSubtable> subtable; 1131 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs; 1132 1133 hb_cmap_get_glyph_func_t get_glyph_funcZ; 1134 const void *get_glyph_data; 1135 1136 CmapSubtableFormat4::accelerator_t format4_accel; 1137 1138 hb_blob_ptr_t<cmap> table; 1139 }; 1140 1141 protected: 1142 1143 const CmapSubtable *find_subtable (unsigned int platform_id, 1144 unsigned int encoding_id) const 1145 { 1146 EncodingRecord key; 1147 key.platformID.set (platform_id); 1148 key.encodingID.set (encoding_id); 1149 1150 const EncodingRecord &result = encodingRecord.bsearch (key); 1151 if (!result.subtable) 1152 return nullptr; 1153 1154 return &(this+result.subtable); 1155 } 1156 1157 public: 1158 1159 bool sanitize (hb_sanitize_context_t *c) const 1160 { 1161 TRACE_SANITIZE (this); 1162 return_trace (c->check_struct (this) && 1163 likely (version == 0) && 1164 encodingRecord.sanitize (c, this)); 1165 } 1166 1167 protected: 1168 HBUINT16 version; /* Table version number (0). */ 1169 SortedArrayOf<EncodingRecord> 1170 encodingRecord; /* Encoding tables. */ 1171 public: 1172 DEFINE_SIZE_ARRAY (4, encodingRecord); 1173 }; 1174 1175 struct cmap_accelerator_t : cmap::accelerator_t {}; 1176 1177 } /* namespace OT */ 1178 1179 1180 #endif /* HB_OT_CMAP_TABLE_HH */ |