1 /* 2 * Copyright © 2014 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * 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-subset-plan.hh" 32 33 namespace OT { 34 35 36 /* 37 * cmap -- Character To Glyph Index Mapping Table 38 */ 39 40 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') 41 42 43 struct CmapSubtableFormat0 44 { get_glyphOT::CmapSubtableFormat045 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 46 { 47 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; 48 if (!gid) 49 return false; 50 *glyph = gid; 51 return true; 52 } 53 sanitizeOT::CmapSubtableFormat054 inline bool sanitize (hb_sanitize_context_t *c) const 55 { 56 TRACE_SANITIZE (this); 57 return_trace (c->check_struct (this)); 58 } 59 60 protected: 61 HBUINT16 format; /* Format number is set to 0. */ 62 HBUINT16 lengthZ; /* Byte length of this subtable. */ 63 HBUINT16 languageZ; /* Ignore. */ 64 HBUINT8 glyphIdArray[256];/* An array that maps character 65 * code to glyph index values. */ 66 public: 67 DEFINE_SIZE_STATIC (6 + 256); 68 }; 69 70 struct CmapSubtableFormat4 71 { 72 struct accelerator_t 73 { initOT::CmapSubtableFormat4::accelerator_t74 inline void init (const CmapSubtableFormat4 *subtable) 75 { 76 segCount = subtable->segCountX2 / 2; 77 endCount = subtable->values; 78 startCount = endCount + segCount + 1; 79 idDelta = startCount + segCount; 80 idRangeOffset = idDelta + segCount; 81 glyphIdArray = idRangeOffset + segCount; 82 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; 83 } 84 get_glyph_funcOT::CmapSubtableFormat4::accelerator_t85 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) 86 { 87 const accelerator_t *thiz = (const accelerator_t *) obj; 88 89 /* Custom two-array bsearch. */ 90 int min = 0, max = (int) thiz->segCount - 1; 91 const HBUINT16 *startCount = thiz->startCount; 92 const HBUINT16 *endCount = thiz->endCount; 93 unsigned int i; 94 while (min <= max) 95 { 96 int mid = (min + max) / 2; 97 if (codepoint < startCount[mid]) 98 max = mid - 1; 99 else if (codepoint > endCount[mid]) 100 min = mid + 1; 101 else 102 { 103 i = mid; 104 goto found; 105 } 106 } 107 return false; 108 109 found: 110 hb_codepoint_t gid; 111 unsigned int rangeOffset = thiz->idRangeOffset[i]; 112 if (rangeOffset == 0) 113 gid = codepoint + thiz->idDelta[i]; 114 else 115 { 116 /* Somebody has been smoking... */ 117 unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount; 118 if (unlikely (index >= thiz->glyphIdArrayLength)) 119 return false; 120 gid = thiz->glyphIdArray[index]; 121 if (unlikely (!gid)) 122 return false; 123 gid += thiz->idDelta[i]; 124 } 125 126 *glyph = gid & 0xFFFFu; 127 return true; 128 } 129 130 const HBUINT16 *endCount; 131 const HBUINT16 *startCount; 132 const HBUINT16 *idDelta; 133 const HBUINT16 *idRangeOffset; 134 const HBUINT16 *glyphIdArray; 135 unsigned int segCount; 136 unsigned int glyphIdArrayLength; 137 }; 138 get_glyphOT::CmapSubtableFormat4139 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 140 { 141 accelerator_t accel; 142 accel.init (this); 143 return accel.get_glyph_func (&accel, codepoint, glyph); 144 } 145 sanitizeOT::CmapSubtableFormat4146 inline bool sanitize (hb_sanitize_context_t *c) const 147 { 148 TRACE_SANITIZE (this); 149 if (unlikely (!c->check_struct (this))) 150 return_trace (false); 151 152 if (unlikely (!c->check_range (this, length))) 153 { 154 /* Some broken fonts have too long of a "length" value. 155 * If that is the case, just change the value to truncate 156 * the subtable at the end of the blob. */ 157 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, 158 (uintptr_t) (c->end - 159 (char *) this)); 160 if (!c->try_set (&length, new_length)) 161 return_trace (false); 162 } 163 164 return_trace (16 + 4 * (unsigned int) segCountX2 <= length); 165 } 166 167 protected: 168 HBUINT16 format; /* Format number is set to 4. */ 169 HBUINT16 length; /* This is the length in bytes of the 170 * subtable. */ 171 HBUINT16 languageZ; /* Ignore. */ 172 HBUINT16 segCountX2; /* 2 x segCount. */ 173 HBUINT16 searchRangeZ; /* 2 * (2**floor(log2(segCount))) */ 174 HBUINT16 entrySelectorZ; /* log2(searchRange/2) */ 175 HBUINT16 rangeShiftZ; /* 2 x segCount - searchRange */ 176 177 HBUINT16 values[VAR]; 178 #if 0 179 HBUINT16 endCount[segCount]; /* End characterCode for each segment, 180 * last=0xFFFFu. */ 181 HBUINT16 reservedPad; /* Set to 0. */ 182 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ 183 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ 184 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ 185 HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ 186 #endif 187 188 public: 189 DEFINE_SIZE_ARRAY (14, values); 190 }; 191 192 struct CmapSubtableLongGroup 193 { 194 friend struct CmapSubtableFormat12; 195 friend struct CmapSubtableFormat13; 196 friend struct cmap; 197 cmpOT::CmapSubtableLongGroup198 int cmp (hb_codepoint_t codepoint) const 199 { 200 if (codepoint < startCharCode) return -1; 201 if (codepoint > endCharCode) return +1; 202 return 0; 203 } 204 sanitizeOT::CmapSubtableLongGroup205 inline bool sanitize (hb_sanitize_context_t *c) const 206 { 207 TRACE_SANITIZE (this); 208 return_trace (c->check_struct (this)); 209 } 210 211 private: 212 HBUINT32 startCharCode; /* First character code in this group. */ 213 HBUINT32 endCharCode; /* Last character code in this group. */ 214 HBUINT32 glyphID; /* Glyph index; interpretation depends on 215 * subtable format. */ 216 public: 217 DEFINE_SIZE_STATIC (12); 218 }; 219 220 template <typename UINT> 221 struct CmapSubtableTrimmed 222 { get_glyphOT::CmapSubtableTrimmed223 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 224 { 225 /* Rely on our implicit array bound-checking. */ 226 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; 227 if (!gid) 228 return false; 229 *glyph = gid; 230 return true; 231 } 232 sanitizeOT::CmapSubtableTrimmed233 inline bool sanitize (hb_sanitize_context_t *c) const 234 { 235 TRACE_SANITIZE (this); 236 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); 237 } 238 239 protected: 240 UINT formatReserved; /* Subtable format and (maybe) padding. */ 241 UINT lengthZ; /* Byte length of this subtable. */ 242 UINT languageZ; /* Ignore. */ 243 UINT startCharCode; /* First character code covered. */ 244 ArrayOf<GlyphID, UINT> 245 glyphIdArray; /* Array of glyph index values for character 246 * codes in the range. */ 247 public: 248 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); 249 }; 250 251 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; 252 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; 253 254 template <typename T> 255 struct CmapSubtableLongSegmented 256 { 257 friend struct cmap; 258 get_glyphOT::CmapSubtableLongSegmented259 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 260 { 261 int i = groups.bsearch (codepoint); 262 if (i == -1) 263 return false; 264 *glyph = T::group_get_glyph (groups[i], codepoint); 265 return true; 266 } 267 sanitizeOT::CmapSubtableLongSegmented268 inline bool sanitize (hb_sanitize_context_t *c) const 269 { 270 TRACE_SANITIZE (this); 271 return_trace (c->check_struct (this) && groups.sanitize (c)); 272 } 273 serializeOT::CmapSubtableLongSegmented274 inline bool serialize (hb_serialize_context_t *c, 275 hb_prealloced_array_t<CmapSubtableLongGroup> &group_data) 276 { 277 TRACE_SERIALIZE (this); 278 if (unlikely (!c->extend_min (*this))) return_trace (false); 279 Supplier<CmapSubtableLongGroup> supplier (group_data.array, group_data.len); 280 if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false); 281 return true; 282 } 283 284 protected: 285 HBUINT16 format; /* Subtable format; set to 12. */ 286 HBUINT16 reservedZ; /* Reserved; set to 0. */ 287 HBUINT32 lengthZ; /* Byte length of this subtable. */ 288 HBUINT32 languageZ; /* Ignore. */ 289 SortedArrayOf<CmapSubtableLongGroup, HBUINT32> 290 groups; /* Groupings. */ 291 public: 292 DEFINE_SIZE_ARRAY (16, groups); 293 }; 294 295 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> 296 { group_get_glyphOT::CmapSubtableFormat12297 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 298 hb_codepoint_t u) 299 { return group.glyphID + (u - group.startCharCode); } 300 }; 301 302 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> 303 { group_get_glyphOT::CmapSubtableFormat13304 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 305 hb_codepoint_t u HB_UNUSED) 306 { return group.glyphID; } 307 }; 308 309 typedef enum 310 { 311 GLYPH_VARIANT_NOT_FOUND = 0, 312 GLYPH_VARIANT_FOUND = 1, 313 GLYPH_VARIANT_USE_DEFAULT = 2 314 } glyph_variant_t; 315 316 struct UnicodeValueRange 317 { cmpOT::UnicodeValueRange318 inline int cmp (const hb_codepoint_t &codepoint) const 319 { 320 if (codepoint < startUnicodeValue) return -1; 321 if (codepoint > startUnicodeValue + additionalCount) return +1; 322 return 0; 323 } 324 sanitizeOT::UnicodeValueRange325 inline bool sanitize (hb_sanitize_context_t *c) const 326 { 327 TRACE_SANITIZE (this); 328 return_trace (c->check_struct (this)); 329 } 330 331 UINT24 startUnicodeValue; /* First value in this range. */ 332 HBUINT8 additionalCount; /* Number of additional values in this 333 * range. */ 334 public: 335 DEFINE_SIZE_STATIC (4); 336 }; 337 338 typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS; 339 340 struct UVSMapping 341 { cmpOT::UVSMapping342 inline int cmp (const hb_codepoint_t &codepoint) const 343 { 344 return unicodeValue.cmp (codepoint); 345 } 346 sanitizeOT::UVSMapping347 inline bool sanitize (hb_sanitize_context_t *c) const 348 { 349 TRACE_SANITIZE (this); 350 return_trace (c->check_struct (this)); 351 } 352 353 UINT24 unicodeValue; /* Base Unicode value of the UVS */ 354 GlyphID glyphID; /* Glyph ID of the UVS */ 355 public: 356 DEFINE_SIZE_STATIC (5); 357 }; 358 359 typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS; 360 361 struct VariationSelectorRecord 362 { get_glyphOT::VariationSelectorRecord363 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint, 364 hb_codepoint_t *glyph, 365 const void *base) const 366 { 367 int i; 368 const DefaultUVS &defaults = base+defaultUVS; 369 i = defaults.bsearch (codepoint); 370 if (i != -1) 371 return GLYPH_VARIANT_USE_DEFAULT; 372 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; 373 i = nonDefaults.bsearch (codepoint); 374 if (i != -1) 375 { 376 *glyph = nonDefaults[i].glyphID; 377 return GLYPH_VARIANT_FOUND; 378 } 379 return GLYPH_VARIANT_NOT_FOUND; 380 } 381 cmpOT::VariationSelectorRecord382 inline int cmp (const hb_codepoint_t &variation_selector) const 383 { 384 return varSelector.cmp (variation_selector); 385 } 386 sanitizeOT::VariationSelectorRecord387 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 388 { 389 TRACE_SANITIZE (this); 390 return_trace (c->check_struct (this) && 391 defaultUVS.sanitize (c, base) && 392 nonDefaultUVS.sanitize (c, base)); 393 } 394 395 UINT24 varSelector; /* Variation selector. */ 396 LOffsetTo<DefaultUVS> 397 defaultUVS; /* Offset to Default UVS Table. May be 0. */ 398 LOffsetTo<NonDefaultUVS> 399 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ 400 public: 401 DEFINE_SIZE_STATIC (11); 402 }; 403 404 struct CmapSubtableFormat14 405 { get_glyph_variantOT::CmapSubtableFormat14406 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, 407 hb_codepoint_t variation_selector, 408 hb_codepoint_t *glyph) const 409 { 410 return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); 411 } 412 sanitizeOT::CmapSubtableFormat14413 inline bool sanitize (hb_sanitize_context_t *c) const 414 { 415 TRACE_SANITIZE (this); 416 return_trace (c->check_struct (this) && 417 record.sanitize (c, this)); 418 } 419 420 protected: 421 HBUINT16 format; /* Format number is set to 14. */ 422 HBUINT32 lengthZ; /* Byte length of this subtable. */ 423 SortedArrayOf<VariationSelectorRecord, HBUINT32> 424 record; /* Variation selector records; sorted 425 * in increasing order of `varSelector'. */ 426 public: 427 DEFINE_SIZE_ARRAY (10, record); 428 }; 429 430 struct CmapSubtable 431 { 432 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ 433 get_glyphOT::CmapSubtable434 inline bool get_glyph (hb_codepoint_t codepoint, 435 hb_codepoint_t *glyph) const 436 { 437 switch (u.format) { 438 case 0: return u.format0 .get_glyph (codepoint, glyph); 439 case 4: return u.format4 .get_glyph (codepoint, glyph); 440 case 6: return u.format6 .get_glyph (codepoint, glyph); 441 case 10: return u.format10.get_glyph (codepoint, glyph); 442 case 12: return u.format12.get_glyph (codepoint, glyph); 443 case 13: return u.format13.get_glyph (codepoint, glyph); 444 case 14: 445 default: return false; 446 } 447 } 448 sanitizeOT::CmapSubtable449 inline bool sanitize (hb_sanitize_context_t *c) const 450 { 451 TRACE_SANITIZE (this); 452 if (!u.format.sanitize (c)) return_trace (false); 453 switch (u.format) { 454 case 0: return_trace (u.format0 .sanitize (c)); 455 case 4: return_trace (u.format4 .sanitize (c)); 456 case 6: return_trace (u.format6 .sanitize (c)); 457 case 10: return_trace (u.format10.sanitize (c)); 458 case 12: return_trace (u.format12.sanitize (c)); 459 case 13: return_trace (u.format13.sanitize (c)); 460 case 14: return_trace (u.format14.sanitize (c)); 461 default:return_trace (true); 462 } 463 } 464 465 public: 466 union { 467 HBUINT16 format; /* Format identifier */ 468 CmapSubtableFormat0 format0; 469 CmapSubtableFormat4 format4; 470 CmapSubtableFormat6 format6; 471 CmapSubtableFormat10 format10; 472 CmapSubtableFormat12 format12; 473 CmapSubtableFormat13 format13; 474 CmapSubtableFormat14 format14; 475 } u; 476 public: 477 DEFINE_SIZE_UNION (2, format); 478 }; 479 480 481 struct EncodingRecord 482 { cmpOT::EncodingRecord483 inline int cmp (const EncodingRecord &other) const 484 { 485 int ret; 486 ret = platformID.cmp (other.platformID); 487 if (ret) return ret; 488 ret = encodingID.cmp (other.encodingID); 489 if (ret) return ret; 490 return 0; 491 } 492 sanitizeOT::EncodingRecord493 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 494 { 495 TRACE_SANITIZE (this); 496 return_trace (c->check_struct (this) && 497 subtable.sanitize (c, base)); 498 } 499 500 HBUINT16 platformID; /* Platform ID. */ 501 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 502 LOffsetTo<CmapSubtable> 503 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ 504 public: 505 DEFINE_SIZE_STATIC (8); 506 }; 507 508 struct cmap 509 { 510 static const hb_tag_t tableTag = HB_OT_TAG_cmap; 511 sanitizeOT::cmap512 inline bool sanitize (hb_sanitize_context_t *c) const 513 { 514 TRACE_SANITIZE (this); 515 return_trace (c->check_struct (this) && 516 likely (version == 0) && 517 encodingRecord.sanitize (c, this)); 518 } 519 populate_groupsOT::cmap520 inline bool populate_groups (hb_subset_plan_t *plan, 521 hb_prealloced_array_t<CmapSubtableLongGroup> *groups) const 522 { 523 CmapSubtableLongGroup *group = nullptr; 524 for (unsigned int i = 0; i < plan->codepoints.len; i++) { 525 526 hb_codepoint_t cp = plan->codepoints[i]; 527 if (!group || cp - 1 != group->endCharCode) 528 { 529 group = groups->push (); 530 group->startCharCode.set (cp); 531 group->endCharCode.set (cp); 532 hb_codepoint_t new_gid; 533 if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid))) 534 { 535 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); 536 return false; 537 } 538 group->glyphID.set (new_gid); 539 } else 540 { 541 group->endCharCode.set (cp); 542 } 543 } 544 545 DEBUG_MSG(SUBSET, nullptr, "cmap"); 546 for (unsigned int i = 0; i < groups->len; i++) { 547 CmapSubtableLongGroup& group = (*groups)[i]; 548 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)); 549 } 550 551 return true; 552 } 553 _subsetOT::cmap554 inline bool _subset (hb_prealloced_array_t<CmapSubtableLongGroup> &groups, 555 size_t dest_sz, 556 void *dest) const 557 { 558 hb_serialize_context_t c (dest, dest_sz); 559 560 OT::cmap *cmap = c.start_serialize<OT::cmap> (); 561 if (unlikely (!c.extend_min (*cmap))) 562 { 563 return false; 564 } 565 566 cmap->version.set (0); 567 568 if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 1))) return false; 569 570 EncodingRecord &rec = cmap->encodingRecord[0]; 571 rec.platformID.set (3); // Windows 572 rec.encodingID.set (10); // Unicode UCS-4 573 574 /* capture offset to subtable */ 575 CmapSubtable &subtable = rec.subtable.serialize (&c, cmap); 576 577 subtable.u.format.set (12); 578 579 CmapSubtableFormat12 &format12 = subtable.u.format12; 580 if (unlikely (!c.extend_min (format12))) return false; 581 582 format12.format.set (12); 583 format12.reservedZ.set (0); 584 format12.lengthZ.set (16 + 12 * groups.len); 585 586 if (unlikely (!format12.serialize (&c, groups))) return false; 587 588 c.end_serialize (); 589 590 return true; 591 } 592 subsetOT::cmap593 inline bool subset (hb_subset_plan_t *plan) const 594 { 595 hb_auto_array_t<CmapSubtableLongGroup> groups; 596 597 if (unlikely (!populate_groups (plan, &groups))) return false; 598 599 // We now know how big our blob needs to be 600 // TODO use APIs from the structs to get size? 601 size_t dest_sz = 4 // header 602 + 8 // 1 EncodingRecord 603 + 16 // Format 12 header 604 + 12 * groups.len; // SequentialMapGroup records 605 void *dest = malloc (dest_sz); 606 if (unlikely (!dest)) { 607 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); 608 return false; 609 } 610 611 if (unlikely (!_subset (groups, dest_sz, dest))) 612 { 613 free (dest); 614 return false; 615 } 616 617 // all done, write the blob into dest 618 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest, 619 dest_sz, 620 HB_MEMORY_MODE_READONLY, 621 dest, 622 free); 623 bool result = hb_subset_plan_add_table (plan, HB_OT_TAG_cmap, cmap_prime); 624 hb_blob_destroy (cmap_prime); 625 return result; 626 } 627 628 struct accelerator_t 629 { initOT::cmap::accelerator_t630 inline void init (hb_face_t *face) 631 { 632 this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap)); 633 const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob); 634 const OT::CmapSubtable *subtable = nullptr; 635 const OT::CmapSubtableFormat14 *subtable_uvs = nullptr; 636 637 bool symbol = false; 638 /* 32-bit subtables. */ 639 if (!subtable) subtable = cmap->find_subtable (3, 10); 640 if (!subtable) subtable = cmap->find_subtable (0, 6); 641 if (!subtable) subtable = cmap->find_subtable (0, 4); 642 /* 16-bit subtables. */ 643 if (!subtable) subtable = cmap->find_subtable (3, 1); 644 if (!subtable) subtable = cmap->find_subtable (0, 3); 645 if (!subtable) subtable = cmap->find_subtable (0, 2); 646 if (!subtable) subtable = cmap->find_subtable (0, 1); 647 if (!subtable) subtable = cmap->find_subtable (0, 0); 648 if (!subtable) 649 { 650 subtable = cmap->find_subtable (3, 0); 651 if (subtable) symbol = true; 652 } 653 /* Meh. */ 654 if (!subtable) subtable = &OT::Null(OT::CmapSubtable); 655 656 /* UVS subtable. */ 657 if (!subtable_uvs) 658 { 659 const OT::CmapSubtable *st = cmap->find_subtable (0, 5); 660 if (st && st->u.format == 14) 661 subtable_uvs = &st->u.format14; 662 } 663 /* Meh. */ 664 if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14); 665 666 this->uvs_table = subtable_uvs; 667 668 this->get_glyph_data = subtable; 669 if (unlikely (symbol)) 670 this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>; 671 else 672 switch (subtable->u.format) { 673 /* Accelerate format 4 and format 12. */ 674 default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break; 675 case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break; 676 case 4: 677 { 678 this->format4_accel.init (&subtable->u.format4); 679 this->get_glyph_data = &this->format4_accel; 680 this->get_glyph_func = this->format4_accel.get_glyph_func; 681 } 682 break; 683 } 684 } 685 finiOT::cmap::accelerator_t686 inline void fini (void) 687 { 688 hb_blob_destroy (this->blob); 689 } 690 get_nominal_glyphOT::cmap::accelerator_t691 inline bool get_nominal_glyph (hb_codepoint_t unicode, 692 hb_codepoint_t *glyph) const 693 { 694 return this->get_glyph_func (this->get_glyph_data, unicode, glyph); 695 } 696 get_variation_glyphOT::cmap::accelerator_t697 inline bool get_variation_glyph (hb_codepoint_t unicode, 698 hb_codepoint_t variation_selector, 699 hb_codepoint_t *glyph) const 700 { 701 switch (this->uvs_table->get_glyph_variant (unicode, 702 variation_selector, 703 glyph)) 704 { 705 case OT::GLYPH_VARIANT_NOT_FOUND: return false; 706 case OT::GLYPH_VARIANT_FOUND: return true; 707 case OT::GLYPH_VARIANT_USE_DEFAULT: break; 708 } 709 710 return get_nominal_glyph (unicode, glyph); 711 } 712 713 protected: 714 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, 715 hb_codepoint_t codepoint, 716 hb_codepoint_t *glyph); 717 718 template <typename Type> get_glyph_fromOT::cmap::accelerator_t719 static inline bool get_glyph_from (const void *obj, 720 hb_codepoint_t codepoint, 721 hb_codepoint_t *glyph) 722 { 723 const Type *typed_obj = (const Type *) obj; 724 return typed_obj->get_glyph (codepoint, glyph); 725 } 726 727 template <typename Type> get_glyph_from_symbolOT::cmap::accelerator_t728 static inline bool get_glyph_from_symbol (const void *obj, 729 hb_codepoint_t codepoint, 730 hb_codepoint_t *glyph) 731 { 732 const Type *typed_obj = (const Type *) obj; 733 if (likely (typed_obj->get_glyph (codepoint, glyph))) 734 return true; 735 736 if (codepoint <= 0x00FFu) 737 { 738 /* For symbol-encoded OpenType fonts, we duplicate the 739 * U+F000..F0FF range at U+0000..U+00FF. That's what 740 * Windows seems to do, and that's hinted about at: 741 * http://www.microsoft.com/typography/otspec/recom.htm 742 * under "Non-Standard (Symbol) Fonts". */ 743 return typed_obj->get_glyph (0xF000u + codepoint, glyph); 744 } 745 746 return false; 747 } 748 749 private: 750 hb_cmap_get_glyph_func_t get_glyph_func; 751 const void *get_glyph_data; 752 OT::CmapSubtableFormat4::accelerator_t format4_accel; 753 754 const OT::CmapSubtableFormat14 *uvs_table; 755 hb_blob_t *blob; 756 }; 757 758 protected: 759 find_subtableOT::cmap760 inline const CmapSubtable *find_subtable (unsigned int platform_id, 761 unsigned int encoding_id) const 762 { 763 EncodingRecord key; 764 key.platformID.set (platform_id); 765 key.encodingID.set (encoding_id); 766 767 /* Note: We can use bsearch, but since it has no performance 768 * implications, we use lsearch and as such accept fonts with 769 * unsorted subtable list. */ 770 int result = encodingRecord./*bsearch*/lsearch (key); 771 if (result == -1 || !encodingRecord[result].subtable) 772 return nullptr; 773 774 return &(this+encodingRecord[result].subtable); 775 } 776 777 protected: 778 HBUINT16 version; /* Table version number (0). */ 779 SortedArrayOf<EncodingRecord> 780 encodingRecord; /* Encoding tables. */ 781 public: 782 DEFINE_SIZE_ARRAY (4, encodingRecord); 783 }; 784 785 786 } /* namespace OT */ 787 788 789 #endif /* HB_OT_CMAP_TABLE_HH */ 790