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.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 { get_glyphOT::CmapSubtableFormat044 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 } collect_unicodesOT::CmapSubtableFormat052 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 sanitizeOT::CmapSubtableFormat059 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 78 template<typename Iterator, 79 hb_requires (hb_is_iterator (Iterator))> serialize_endcode_arrayOT::CmapSubtableFormat480 HBUINT16* serialize_endcode_array (hb_serialize_context_t *c, 81 Iterator it) 82 { 83 HBUINT16 *endCode = c->start_embed<HBUINT16> (); 84 hb_codepoint_t prev_endcp = 0xFFFF; 85 86 + it 87 | hb_apply ([&] (const hb_item_type<Iterator> _) 88 { 89 if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) 90 { 91 HBUINT16 end_code; 92 end_code = prev_endcp; 93 c->copy<HBUINT16> (end_code); 94 } 95 prev_endcp = _.first; 96 }) 97 ; 98 99 { 100 // last endCode 101 HBUINT16 endcode; 102 endcode = prev_endcp; 103 if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr; 104 // There must be a final entry with end_code == 0xFFFF. 105 if (prev_endcp != 0xFFFF) 106 { 107 HBUINT16 finalcode; 108 finalcode = 0xFFFF; 109 if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr; 110 } 111 } 112 113 return endCode; 114 } 115 116 template<typename Iterator, 117 hb_requires (hb_is_iterator (Iterator))> serialize_startcode_arrayOT::CmapSubtableFormat4118 HBUINT16* serialize_startcode_array (hb_serialize_context_t *c, 119 Iterator it) 120 { 121 HBUINT16 *startCode = c->start_embed<HBUINT16> (); 122 hb_codepoint_t prev_cp = 0xFFFF; 123 124 + it 125 | hb_apply ([&] (const hb_item_type<Iterator> _) 126 { 127 if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) 128 { 129 HBUINT16 start_code; 130 start_code = _.first; 131 c->copy<HBUINT16> (start_code); 132 } 133 134 prev_cp = _.first; 135 }) 136 ; 137 138 // There must be a final entry with end_code == 0xFFFF. 139 if (it.len () == 0 || prev_cp != 0xFFFF) 140 { 141 HBUINT16 finalcode; 142 finalcode = 0xFFFF; 143 if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr; 144 } 145 146 return startCode; 147 } 148 149 template<typename Iterator, 150 hb_requires (hb_is_iterator (Iterator))> serialize_idDelta_arrayOT::CmapSubtableFormat4151 HBINT16* serialize_idDelta_array (hb_serialize_context_t *c, 152 Iterator it, 153 HBUINT16 *endCode, 154 HBUINT16 *startCode, 155 unsigned segcount) 156 { 157 unsigned i = 0; 158 hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF; 159 bool use_delta = true; 160 161 HBINT16 *idDelta = c->start_embed<HBINT16> (); 162 if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size) 163 return nullptr; 164 165 + it 166 | hb_apply ([&] (const hb_item_type<Iterator> _) 167 { 168 if (_.first == startCode[i]) 169 { 170 use_delta = true; 171 start_gid = _.second; 172 } 173 else if (_.second != last_gid + 1) use_delta = false; 174 175 if (_.first == endCode[i]) 176 { 177 HBINT16 delta; 178 if (use_delta) delta = (int)start_gid - (int)startCode[i]; 179 else delta = 0; 180 c->copy<HBINT16> (delta); 181 182 i++; 183 } 184 185 last_gid = _.second; 186 last_cp = _.first; 187 }) 188 ; 189 190 if (it.len () == 0 || last_cp != 0xFFFF) 191 { 192 HBINT16 delta; 193 delta = 1; 194 if (unlikely (!c->copy<HBINT16> (delta))) return nullptr; 195 } 196 197 return idDelta; 198 } 199 200 template<typename Iterator, 201 hb_requires (hb_is_iterator (Iterator))> serialize_rangeoffset_glyidOT::CmapSubtableFormat4202 HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, 203 Iterator it, 204 HBUINT16 *endCode, 205 HBUINT16 *startCode, 206 HBINT16 *idDelta, 207 unsigned segcount) 208 { 209 HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); 210 if (unlikely (!c->check_success (idRangeOffset))) return nullptr; 211 if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; 212 213 + hb_range (segcount) 214 | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }) 215 | hb_apply ([&] (const unsigned i) 216 { 217 idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i); 218 219 + it 220 | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; }) 221 | hb_apply ([&] (const hb_item_type<Iterator> _) 222 { 223 HBUINT16 glyID; 224 glyID = _.second; 225 c->copy<HBUINT16> (glyID); 226 }) 227 ; 228 229 230 }) 231 ; 232 233 return idRangeOffset; 234 } 235 236 template<typename Iterator, 237 hb_requires (hb_is_iterator (Iterator))> serializeOT::CmapSubtableFormat4238 void serialize (hb_serialize_context_t *c, 239 Iterator it) 240 { 241 unsigned table_initpos = c->length (); 242 if (unlikely (!c->extend_min (*this))) return; 243 this->format = 4; 244 245 //serialize endCode[] 246 HBUINT16 *endCode = serialize_endcode_array (c, it); 247 if (unlikely (!endCode)) return; 248 249 unsigned segcount = (c->length () - min_size) / HBUINT16::static_size; 250 251 // 2 bytes of padding. 252 if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding. 253 254 // serialize startCode[] 255 HBUINT16 *startCode = serialize_startcode_array (c, it); 256 if (unlikely (!startCode)) return; 257 258 //serialize idDelta[] 259 HBINT16 *idDelta = serialize_idDelta_array (c, it, endCode, startCode, segcount); 260 if (unlikely (!idDelta)) return; 261 262 HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, it, endCode, startCode, idDelta, segcount); 263 if (unlikely (!c->check_success (idRangeOffset))) return; 264 265 if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return; 266 this->segCountX2 = segcount * 2; 267 this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1; 268 this->searchRange = 2 * (1u << this->entrySelector); 269 this->rangeShift = segcount * 2 > this->searchRange 270 ? 2 * segcount - this->searchRange 271 : 0; 272 } 273 274 struct accelerator_t 275 { accelerator_tOT::CmapSubtableFormat4::accelerator_t276 accelerator_t () {} accelerator_tOT::CmapSubtableFormat4::accelerator_t277 accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } ~accelerator_tOT::CmapSubtableFormat4::accelerator_t278 ~accelerator_t () { fini (); } 279 initOT::CmapSubtableFormat4::accelerator_t280 void init (const CmapSubtableFormat4 *subtable) 281 { 282 segCount = subtable->segCountX2 / 2; 283 endCount = subtable->values.arrayZ; 284 startCount = endCount + segCount + 1; 285 idDelta = startCount + segCount; 286 idRangeOffset = idDelta + segCount; 287 glyphIdArray = idRangeOffset + segCount; 288 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; 289 } finiOT::CmapSubtableFormat4::accelerator_t290 void fini () {} 291 get_glyphOT::CmapSubtableFormat4::accelerator_t292 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 293 { 294 /* Custom two-array bsearch. */ 295 int min = 0, max = (int) this->segCount - 1; 296 const HBUINT16 *startCount = this->startCount; 297 const HBUINT16 *endCount = this->endCount; 298 unsigned int i; 299 while (min <= max) 300 { 301 int mid = ((unsigned int) min + (unsigned int) max) / 2; 302 if (codepoint < startCount[mid]) 303 max = mid - 1; 304 else if (codepoint > endCount[mid]) 305 min = mid + 1; 306 else 307 { 308 i = mid; 309 goto found; 310 } 311 } 312 return false; 313 314 found: 315 hb_codepoint_t gid; 316 unsigned int rangeOffset = this->idRangeOffset[i]; 317 if (rangeOffset == 0) 318 gid = codepoint + this->idDelta[i]; 319 else 320 { 321 /* Somebody has been smoking... */ 322 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; 323 if (unlikely (index >= this->glyphIdArrayLength)) 324 return false; 325 gid = this->glyphIdArray[index]; 326 if (unlikely (!gid)) 327 return false; 328 gid += this->idDelta[i]; 329 } 330 gid &= 0xFFFFu; 331 if (!gid) 332 return false; 333 *glyph = gid; 334 return true; 335 } get_glyph_funcOT::CmapSubtableFormat4::accelerator_t336 HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) 337 { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); } collect_unicodesOT::CmapSubtableFormat4::accelerator_t338 void collect_unicodes (hb_set_t *out) const 339 { 340 unsigned int count = this->segCount; 341 if (count && this->startCount[count - 1] == 0xFFFFu) 342 count--; /* Skip sentinel segment. */ 343 for (unsigned int i = 0; i < count; i++) 344 { 345 hb_codepoint_t start = this->startCount[i]; 346 hb_codepoint_t end = this->endCount[i]; 347 unsigned int rangeOffset = this->idRangeOffset[i]; 348 if (rangeOffset == 0) 349 { 350 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) 351 { 352 hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; 353 if (unlikely (!gid)) 354 continue; 355 out->add (codepoint); 356 } 357 } 358 else 359 { 360 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) 361 { 362 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; 363 if (unlikely (index >= this->glyphIdArrayLength)) 364 break; 365 hb_codepoint_t gid = this->glyphIdArray[index]; 366 if (unlikely (!gid)) 367 continue; 368 out->add (codepoint); 369 } 370 } 371 } 372 } 373 374 const HBUINT16 *endCount; 375 const HBUINT16 *startCount; 376 const HBUINT16 *idDelta; 377 const HBUINT16 *idRangeOffset; 378 const HBUINT16 *glyphIdArray; 379 unsigned int segCount; 380 unsigned int glyphIdArrayLength; 381 }; 382 get_glyphOT::CmapSubtableFormat4383 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 384 { 385 accelerator_t accel (this); 386 return accel.get_glyph_func (&accel, codepoint, glyph); 387 } collect_unicodesOT::CmapSubtableFormat4388 void collect_unicodes (hb_set_t *out) const 389 { 390 accelerator_t accel (this); 391 accel.collect_unicodes (out); 392 } 393 sanitizeOT::CmapSubtableFormat4394 bool sanitize (hb_sanitize_context_t *c) const 395 { 396 TRACE_SANITIZE (this); 397 if (unlikely (!c->check_struct (this))) 398 return_trace (false); 399 400 if (unlikely (!c->check_range (this, length))) 401 { 402 /* Some broken fonts have too long of a "length" value. 403 * If that is the case, just change the value to truncate 404 * the subtable at the end of the blob. */ 405 uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535, 406 (uintptr_t) (c->end - 407 (char *) this)); 408 if (!c->try_set (&length, new_length)) 409 return_trace (false); 410 } 411 412 return_trace (16 + 4 * (unsigned int) segCountX2 <= length); 413 } 414 415 416 417 protected: 418 HBUINT16 format; /* Format number is set to 4. */ 419 HBUINT16 length; /* This is the length in bytes of the 420 * subtable. */ 421 HBUINT16 language; /* Ignore. */ 422 HBUINT16 segCountX2; /* 2 x segCount. */ 423 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */ 424 HBUINT16 entrySelector; /* log2(searchRange/2) */ 425 HBUINT16 rangeShift; /* 2 x segCount - searchRange */ 426 427 UnsizedArrayOf<HBUINT16> 428 values; 429 #if 0 430 HBUINT16 endCount[segCount]; /* End characterCode for each segment, 431 * last=0xFFFFu. */ 432 HBUINT16 reservedPad; /* Set to 0. */ 433 HBUINT16 startCount[segCount]; /* Start character code for each segment. */ 434 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */ 435 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ 436 UnsizedArrayOf<HBUINT16> 437 glyphIdArray; /* Glyph index array (arbitrary length) */ 438 #endif 439 440 public: 441 DEFINE_SIZE_ARRAY (14, values); 442 }; 443 444 struct CmapSubtableLongGroup 445 { 446 friend struct CmapSubtableFormat12; 447 friend struct CmapSubtableFormat13; 448 template<typename U> 449 friend struct CmapSubtableLongSegmented; 450 friend struct cmap; 451 cmpOT::CmapSubtableLongGroup452 int cmp (hb_codepoint_t codepoint) const 453 { 454 if (codepoint < startCharCode) return -1; 455 if (codepoint > endCharCode) return +1; 456 return 0; 457 } 458 sanitizeOT::CmapSubtableLongGroup459 bool sanitize (hb_sanitize_context_t *c) const 460 { 461 TRACE_SANITIZE (this); 462 return_trace (c->check_struct (this)); 463 } 464 465 private: 466 HBUINT32 startCharCode; /* First character code in this group. */ 467 HBUINT32 endCharCode; /* Last character code in this group. */ 468 HBUINT32 glyphID; /* Glyph index; interpretation depends on 469 * subtable format. */ 470 public: 471 DEFINE_SIZE_STATIC (12); 472 }; 473 DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup); 474 475 template <typename UINT> 476 struct CmapSubtableTrimmed 477 { get_glyphOT::CmapSubtableTrimmed478 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 479 { 480 /* Rely on our implicit array bound-checking. */ 481 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; 482 if (!gid) 483 return false; 484 *glyph = gid; 485 return true; 486 } collect_unicodesOT::CmapSubtableTrimmed487 void collect_unicodes (hb_set_t *out) const 488 { 489 hb_codepoint_t start = startCharCode; 490 unsigned int count = glyphIdArray.len; 491 for (unsigned int i = 0; i < count; i++) 492 if (glyphIdArray[i]) 493 out->add (start + i); 494 } 495 sanitizeOT::CmapSubtableTrimmed496 bool sanitize (hb_sanitize_context_t *c) const 497 { 498 TRACE_SANITIZE (this); 499 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); 500 } 501 502 protected: 503 UINT formatReserved; /* Subtable format and (maybe) padding. */ 504 UINT length; /* Byte length of this subtable. */ 505 UINT language; /* Ignore. */ 506 UINT startCharCode; /* First character code covered. */ 507 ArrayOf<HBGlyphID, UINT> 508 glyphIdArray; /* Array of glyph index values for character 509 * codes in the range. */ 510 public: 511 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); 512 }; 513 514 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; 515 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; 516 517 template <typename T> 518 struct CmapSubtableLongSegmented 519 { 520 friend struct cmap; 521 get_glyphOT::CmapSubtableLongSegmented522 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const 523 { 524 hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); 525 if (!gid) 526 return false; 527 *glyph = gid; 528 return true; 529 } 530 collect_unicodesOT::CmapSubtableLongSegmented531 void collect_unicodes (hb_set_t *out) const 532 { 533 for (unsigned int i = 0; i < this->groups.len; i++) 534 { 535 hb_codepoint_t start = this->groups[i].startCharCode; 536 hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, 537 (hb_codepoint_t) HB_UNICODE_MAX); 538 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) 539 { 540 hb_codepoint_t gid = T::group_get_glyph (this->groups[i], codepoint); 541 if (unlikely (!gid)) 542 continue; 543 out->add (codepoint); 544 } 545 } 546 } 547 sanitizeOT::CmapSubtableLongSegmented548 bool sanitize (hb_sanitize_context_t *c) const 549 { 550 TRACE_SANITIZE (this); 551 return_trace (c->check_struct (this) && groups.sanitize (c)); 552 } 553 554 protected: 555 HBUINT16 format; /* Subtable format; set to 12. */ 556 HBUINT16 reserved; /* Reserved; set to 0. */ 557 HBUINT32 length; /* Byte length of this subtable. */ 558 HBUINT32 language; /* Ignore. */ 559 SortedArrayOf<CmapSubtableLongGroup, HBUINT32> 560 groups; /* Groupings. */ 561 public: 562 DEFINE_SIZE_ARRAY (16, groups); 563 }; 564 565 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> 566 { group_get_glyphOT::CmapSubtableFormat12567 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 568 hb_codepoint_t u) 569 { return likely (group.startCharCode <= group.endCharCode) ? 570 group.glyphID + (u - group.startCharCode) : 0; } 571 572 573 template<typename Iterator, 574 hb_requires (hb_is_iterator (Iterator))> serializeOT::CmapSubtableFormat12575 void serialize (hb_serialize_context_t *c, 576 Iterator it) 577 { 578 if (it.len () == 0) return; 579 unsigned table_initpos = c->length (); 580 if (unlikely (!c->extend_min (*this))) return; 581 582 hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; 583 hb_codepoint_t glyphID = 0; 584 585 + it 586 | hb_apply ([&] (const hb_item_type<Iterator> _) 587 { 588 if (startCharCode == 0xFFFF) 589 { 590 startCharCode = _.first; 591 endCharCode = _.first; 592 glyphID = _.second; 593 } 594 else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second)) 595 { 596 CmapSubtableLongGroup grouprecord; 597 grouprecord.startCharCode = startCharCode; 598 grouprecord.endCharCode = endCharCode; 599 grouprecord.glyphID = glyphID; 600 c->copy<CmapSubtableLongGroup> (grouprecord); 601 602 startCharCode = _.first; 603 endCharCode = _.first; 604 glyphID = _.second; 605 } 606 else 607 { 608 endCharCode = _.first; 609 } 610 }) 611 ; 612 613 CmapSubtableLongGroup record; 614 record.startCharCode = startCharCode; 615 record.endCharCode = endCharCode; 616 record.glyphID = glyphID; 617 c->copy<CmapSubtableLongGroup> (record); 618 619 this->format = 12; 620 this->reserved = 0; 621 this->length = c->length () - table_initpos; 622 this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; 623 } 624 get_sub_table_sizeOT::CmapSubtableFormat12625 static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data) 626 { return 16 + 12 * groups_data.length; } 627 628 private: _is_gid_consecutiveOT::CmapSubtableFormat12629 static bool _is_gid_consecutive (hb_codepoint_t endCharCode, 630 hb_codepoint_t startCharCode, 631 hb_codepoint_t glyphID, 632 hb_codepoint_t cp, 633 hb_codepoint_t new_gid) 634 { 635 return (cp - 1 == endCharCode) && 636 new_gid == glyphID + (cp - startCharCode); 637 } 638 639 }; 640 641 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> 642 { group_get_glyphOT::CmapSubtableFormat13643 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, 644 hb_codepoint_t u HB_UNUSED) 645 { return group.glyphID; } 646 }; 647 648 typedef enum 649 { 650 GLYPH_VARIANT_NOT_FOUND = 0, 651 GLYPH_VARIANT_FOUND = 1, 652 GLYPH_VARIANT_USE_DEFAULT = 2 653 } glyph_variant_t; 654 655 struct UnicodeValueRange 656 { cmpOT::UnicodeValueRange657 int cmp (const hb_codepoint_t &codepoint) const 658 { 659 if (codepoint < startUnicodeValue) return -1; 660 if (codepoint > startUnicodeValue + additionalCount) return +1; 661 return 0; 662 } 663 sanitizeOT::UnicodeValueRange664 bool sanitize (hb_sanitize_context_t *c) const 665 { 666 TRACE_SANITIZE (this); 667 return_trace (c->check_struct (this)); 668 } 669 670 HBUINT24 startUnicodeValue; /* First value in this range. */ 671 HBUINT8 additionalCount; /* Number of additional values in this 672 * range. */ 673 public: 674 DEFINE_SIZE_STATIC (4); 675 }; 676 677 struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32> 678 { collect_unicodesOT::DefaultUVS679 void collect_unicodes (hb_set_t *out) const 680 { 681 unsigned int count = len; 682 for (unsigned int i = 0; i < count; i++) 683 { 684 hb_codepoint_t first = arrayZ[i].startUnicodeValue; 685 hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), 686 (hb_codepoint_t) HB_UNICODE_MAX); 687 out->add_range (first, last); 688 } 689 } 690 copyOT::DefaultUVS691 DefaultUVS* copy (hb_serialize_context_t *c, 692 const hb_set_t *unicodes) const 693 { 694 DefaultUVS *out = c->start_embed<DefaultUVS> (); 695 if (unlikely (!out)) return nullptr; 696 auto snap = c->snapshot (); 697 698 HBUINT32 len; 699 len = 0; 700 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr; 701 unsigned init_len = c->length (); 702 703 hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; 704 int count = -1; 705 706 for (const UnicodeValueRange& _ : as_array ()) 707 { 708 for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) 709 { 710 unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; 711 if (!unicodes->has (curEntry)) continue; 712 count += 1; 713 if (lastCode == HB_MAP_VALUE_INVALID) 714 lastCode = curEntry; 715 else if (lastCode + count != curEntry) 716 { 717 UnicodeValueRange rec; 718 rec.startUnicodeValue = lastCode; 719 rec.additionalCount = count - 1; 720 c->copy<UnicodeValueRange> (rec); 721 722 lastCode = curEntry; 723 count = 0; 724 } 725 } 726 } 727 728 if (lastCode != HB_MAP_VALUE_INVALID) 729 { 730 UnicodeValueRange rec; 731 rec.startUnicodeValue = lastCode; 732 rec.additionalCount = count; 733 c->copy<UnicodeValueRange> (rec); 734 } 735 736 if (c->length () - init_len == 0) 737 { 738 c->revert (snap); 739 return nullptr; 740 } 741 else 742 { 743 if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr; 744 return out; 745 } 746 } 747 748 public: 749 DEFINE_SIZE_ARRAY (4, *this); 750 }; 751 752 struct UVSMapping 753 { cmpOT::UVSMapping754 int cmp (const hb_codepoint_t &codepoint) const 755 { return unicodeValue.cmp (codepoint); } 756 sanitizeOT::UVSMapping757 bool sanitize (hb_sanitize_context_t *c) const 758 { 759 TRACE_SANITIZE (this); 760 return_trace (c->check_struct (this)); 761 } 762 763 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ 764 HBGlyphID glyphID; /* Glyph ID of the UVS */ 765 public: 766 DEFINE_SIZE_STATIC (5); 767 }; 768 769 struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32> 770 { collect_unicodesOT::NonDefaultUVS771 void collect_unicodes (hb_set_t *out) const 772 { 773 unsigned int count = len; 774 for (unsigned int i = 0; i < count; i++) 775 out->add (arrayZ[i].glyphID); 776 } 777 closure_glyphsOT::NonDefaultUVS778 void closure_glyphs (const hb_set_t *unicodes, 779 hb_set_t *glyphset) const 780 { 781 + as_array () 782 | hb_filter (unicodes, &UVSMapping::unicodeValue) 783 | hb_map (&UVSMapping::glyphID) 784 | hb_sink (glyphset) 785 ; 786 } 787 copyOT::NonDefaultUVS788 NonDefaultUVS* copy (hb_serialize_context_t *c, 789 const hb_set_t *unicodes, 790 const hb_set_t *glyphs, 791 const hb_map_t *glyph_map) const 792 { 793 NonDefaultUVS *out = c->start_embed<NonDefaultUVS> (); 794 if (unlikely (!out)) return nullptr; 795 796 auto it = 797 + as_array () 798 | hb_filter ([&] (const UVSMapping& _) 799 { 800 return unicodes->has (_.unicodeValue) || glyphs->has (_.glyphID); 801 }) 802 ; 803 804 if (!it) return nullptr; 805 806 HBUINT32 len; 807 len = it.len (); 808 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr; 809 810 for (const UVSMapping& _ : it) 811 { 812 UVSMapping mapping; 813 mapping.unicodeValue = _.unicodeValue; 814 mapping.glyphID = glyph_map->get (_.glyphID); 815 c->copy<UVSMapping> (mapping); 816 } 817 818 return out; 819 } 820 821 public: 822 DEFINE_SIZE_ARRAY (4, *this); 823 }; 824 825 struct VariationSelectorRecord 826 { get_glyphOT::VariationSelectorRecord827 glyph_variant_t get_glyph (hb_codepoint_t codepoint, 828 hb_codepoint_t *glyph, 829 const void *base) const 830 { 831 if ((base+defaultUVS).bfind (codepoint)) 832 return GLYPH_VARIANT_USE_DEFAULT; 833 const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); 834 if (nonDefault.glyphID) 835 { 836 *glyph = nonDefault.glyphID; 837 return GLYPH_VARIANT_FOUND; 838 } 839 return GLYPH_VARIANT_NOT_FOUND; 840 } 841 collect_unicodesOT::VariationSelectorRecord842 void collect_unicodes (hb_set_t *out, const void *base) const 843 { 844 (base+defaultUVS).collect_unicodes (out); 845 (base+nonDefaultUVS).collect_unicodes (out); 846 } 847 cmpOT::VariationSelectorRecord848 int cmp (const hb_codepoint_t &variation_selector) const 849 { return varSelector.cmp (variation_selector); } 850 sanitizeOT::VariationSelectorRecord851 bool sanitize (hb_sanitize_context_t *c, const void *base) const 852 { 853 TRACE_SANITIZE (this); 854 return_trace (c->check_struct (this) && 855 defaultUVS.sanitize (c, base) && 856 nonDefaultUVS.sanitize (c, base)); 857 } 858 copyOT::VariationSelectorRecord859 VariationSelectorRecord* copy (hb_serialize_context_t *c, 860 const hb_set_t *unicodes, 861 const hb_set_t *glyphs, 862 const hb_map_t *glyph_map, 863 const void *src_base, 864 const void *dst_base) const 865 { 866 auto snap = c->snapshot (); 867 auto *out = c->embed<VariationSelectorRecord> (*this); 868 if (unlikely (!out)) return nullptr; 869 870 out->defaultUVS = 0; 871 out->nonDefaultUVS = 0; 872 873 bool drop = true; 874 875 if (defaultUVS != 0) 876 { 877 c->push (); 878 if (c->copy (src_base+defaultUVS, unicodes)) 879 { 880 c->add_link (out->defaultUVS, c->pop_pack (), dst_base); 881 drop = false; 882 } 883 else c->pop_discard (); 884 } 885 886 if (nonDefaultUVS != 0) 887 { 888 c->push (); 889 if (c->copy (src_base+nonDefaultUVS, unicodes, glyphs, glyph_map)) 890 { 891 c->add_link (out->nonDefaultUVS, c->pop_pack (), dst_base); 892 drop = false; 893 } 894 else c->pop_discard (); 895 } 896 897 if (drop) 898 { 899 c->revert (snap); 900 return nullptr; 901 } 902 else return out; 903 } 904 905 HBUINT24 varSelector; /* Variation selector. */ 906 LOffsetTo<DefaultUVS> 907 defaultUVS; /* Offset to Default UVS Table. May be 0. */ 908 LOffsetTo<NonDefaultUVS> 909 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ 910 public: 911 DEFINE_SIZE_STATIC (11); 912 }; 913 914 struct CmapSubtableFormat14 915 { get_glyph_variantOT::CmapSubtableFormat14916 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, 917 hb_codepoint_t variation_selector, 918 hb_codepoint_t *glyph) const 919 { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); } 920 collect_variation_selectorsOT::CmapSubtableFormat14921 void collect_variation_selectors (hb_set_t *out) const 922 { 923 unsigned int count = record.len; 924 for (unsigned int i = 0; i < count; i++) 925 out->add (record.arrayZ[i].varSelector); 926 } collect_variation_unicodesOT::CmapSubtableFormat14927 void collect_variation_unicodes (hb_codepoint_t variation_selector, 928 hb_set_t *out) const 929 { record.bsearch (variation_selector).collect_unicodes (out, this); } 930 serializeOT::CmapSubtableFormat14931 void serialize (hb_serialize_context_t *c, 932 const hb_set_t *unicodes, 933 const hb_set_t *glyphs, 934 const hb_map_t *glyph_map, 935 const void *src_base) 936 { 937 auto snap = c->snapshot (); 938 unsigned table_initpos = c->length (); 939 const char* init_tail = c->tail; 940 941 if (unlikely (!c->extend_min (*this))) return; 942 this->format = 14; 943 944 const CmapSubtableFormat14 *src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (src_base); 945 for (const VariationSelectorRecord& _ : src_tbl->record) 946 c->copy (_, unicodes, glyphs, glyph_map, src_base, this); 947 948 if (c->length () - table_initpos == CmapSubtableFormat14::min_size) 949 c->revert (snap); 950 else 951 { 952 int tail_len = init_tail - c->tail; 953 c->check_assign (this->length, c->length () - table_initpos + tail_len); 954 c->check_assign (this->record.len, (c->length () - table_initpos - CmapSubtableFormat14::min_size) / VariationSelectorRecord::static_size); 955 } 956 } 957 closure_glyphsOT::CmapSubtableFormat14958 void closure_glyphs (const hb_set_t *unicodes, 959 hb_set_t *glyphset) const 960 { 961 + hb_iter (record) 962 | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS) 963 | hb_map (&VariationSelectorRecord::nonDefaultUVS) 964 | hb_map (hb_add (this)) 965 | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); }) 966 ; 967 } 968 sanitizeOT::CmapSubtableFormat14969 bool sanitize (hb_sanitize_context_t *c) const 970 { 971 TRACE_SANITIZE (this); 972 return_trace (c->check_struct (this) && 973 record.sanitize (c, this)); 974 } 975 976 protected: 977 HBUINT16 format; /* Format number is set to 14. */ 978 HBUINT32 length; /* Byte length of this subtable. */ 979 SortedArrayOf<VariationSelectorRecord, HBUINT32> 980 record; /* Variation selector records; sorted 981 * in increasing order of `varSelector'. */ 982 public: 983 DEFINE_SIZE_ARRAY (10, record); 984 }; 985 986 struct CmapSubtable 987 { 988 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ 989 get_glyphOT::CmapSubtable990 bool get_glyph (hb_codepoint_t codepoint, 991 hb_codepoint_t *glyph) const 992 { 993 switch (u.format) { 994 case 0: return u.format0 .get_glyph (codepoint, glyph); 995 case 4: return u.format4 .get_glyph (codepoint, glyph); 996 case 6: return u.format6 .get_glyph (codepoint, glyph); 997 case 10: return u.format10.get_glyph (codepoint, glyph); 998 case 12: return u.format12.get_glyph (codepoint, glyph); 999 case 13: return u.format13.get_glyph (codepoint, glyph); 1000 case 14: 1001 default: return false; 1002 } 1003 } collect_unicodesOT::CmapSubtable1004 void collect_unicodes (hb_set_t *out) const 1005 { 1006 switch (u.format) { 1007 case 0: u.format0 .collect_unicodes (out); return; 1008 case 4: u.format4 .collect_unicodes (out); return; 1009 case 6: u.format6 .collect_unicodes (out); return; 1010 case 10: u.format10.collect_unicodes (out); return; 1011 case 12: u.format12.collect_unicodes (out); return; 1012 case 13: u.format13.collect_unicodes (out); return; 1013 case 14: 1014 default: return; 1015 } 1016 } 1017 1018 template<typename Iterator, 1019 hb_requires (hb_is_iterator (Iterator))> serializeOT::CmapSubtable1020 void serialize (hb_serialize_context_t *c, 1021 Iterator it, 1022 unsigned format, 1023 const hb_subset_plan_t *plan, 1024 const void *src_base) 1025 { 1026 switch (format) { 1027 case 4: u.format4.serialize (c, it); return; 1028 case 12: u.format12.serialize (c, it); return; 1029 case 14: u.format14.serialize (c, plan->unicodes, plan->_glyphset, plan->glyph_map, src_base); return; 1030 default: return; 1031 } 1032 } 1033 sanitizeOT::CmapSubtable1034 bool sanitize (hb_sanitize_context_t *c) const 1035 { 1036 TRACE_SANITIZE (this); 1037 if (!u.format.sanitize (c)) return_trace (false); 1038 switch (u.format) { 1039 case 0: return_trace (u.format0 .sanitize (c)); 1040 case 4: return_trace (u.format4 .sanitize (c)); 1041 case 6: return_trace (u.format6 .sanitize (c)); 1042 case 10: return_trace (u.format10.sanitize (c)); 1043 case 12: return_trace (u.format12.sanitize (c)); 1044 case 13: return_trace (u.format13.sanitize (c)); 1045 case 14: return_trace (u.format14.sanitize (c)); 1046 default:return_trace (true); 1047 } 1048 } 1049 1050 public: 1051 union { 1052 HBUINT16 format; /* Format identifier */ 1053 CmapSubtableFormat0 format0; 1054 CmapSubtableFormat4 format4; 1055 CmapSubtableFormat6 format6; 1056 CmapSubtableFormat10 format10; 1057 CmapSubtableFormat12 format12; 1058 CmapSubtableFormat13 format13; 1059 CmapSubtableFormat14 format14; 1060 } u; 1061 public: 1062 DEFINE_SIZE_UNION (2, format); 1063 }; 1064 1065 1066 struct EncodingRecord 1067 { cmpOT::EncodingRecord1068 int cmp (const EncodingRecord &other) const 1069 { 1070 int ret; 1071 ret = platformID.cmp (other.platformID); 1072 if (ret) return ret; 1073 ret = encodingID.cmp (other.encodingID); 1074 if (ret) return ret; 1075 return 0; 1076 } 1077 sanitizeOT::EncodingRecord1078 bool sanitize (hb_sanitize_context_t *c, const void *base) const 1079 { 1080 TRACE_SANITIZE (this); 1081 return_trace (c->check_struct (this) && 1082 subtable.sanitize (c, base)); 1083 } 1084 1085 template<typename Iterator, 1086 hb_requires (hb_is_iterator (Iterator))> copyOT::EncodingRecord1087 EncodingRecord* copy (hb_serialize_context_t *c, 1088 Iterator it, 1089 unsigned format, 1090 const void *src_base, 1091 const void *dst_base, 1092 const hb_subset_plan_t *plan, 1093 /* INOUT */ unsigned *objidx) const 1094 { 1095 TRACE_SERIALIZE (this); 1096 auto snap = c->snapshot (); 1097 auto *out = c->embed (this); 1098 if (unlikely (!out)) return_trace (nullptr); 1099 out->subtable = 0; 1100 1101 if (*objidx == 0) 1102 { 1103 CmapSubtable *cmapsubtable = c->push<CmapSubtable> (); 1104 unsigned origin_length = c->length (); 1105 cmapsubtable->serialize (c, it, format, plan, &(src_base+subtable)); 1106 if (c->length () - origin_length > 0) *objidx = c->pop_pack (); 1107 else c->pop_discard (); 1108 } 1109 1110 if (*objidx == 0) 1111 { 1112 c->revert (snap); 1113 return_trace (nullptr); 1114 } 1115 1116 c->add_link (out->subtable, *objidx, dst_base); 1117 return_trace (out); 1118 } 1119 1120 HBUINT16 platformID; /* Platform ID. */ 1121 HBUINT16 encodingID; /* Platform-specific encoding ID. */ 1122 LOffsetTo<CmapSubtable> 1123 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ 1124 public: 1125 DEFINE_SIZE_STATIC (8); 1126 }; 1127 1128 struct cmap 1129 { 1130 static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; 1131 1132 template<typename Iterator, typename EncodingRecIter, 1133 hb_requires (hb_is_iterator (Iterator))> serializeOT::cmap1134 void serialize (hb_serialize_context_t *c, 1135 Iterator it, 1136 EncodingRecIter encodingrec_iter, 1137 const void *src_base, 1138 const hb_subset_plan_t *plan) 1139 { 1140 if (unlikely (!c->extend_min ((*this)))) return; 1141 this->version = 0; 1142 1143 unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; 1144 1145 for (const EncodingRecord& _ : encodingrec_iter) 1146 { 1147 unsigned format = (src_base+_.subtable).u.format; 1148 1149 if (format == 4) c->copy (_, it, 4u, src_base, this, plan, &format4objidx); 1150 else if (format == 12) c->copy (_, it, 12u, src_base, this, plan, &format12objidx); 1151 else if (format == 14) c->copy (_, it, 14u, src_base, this, plan, &format14objidx); 1152 } 1153 1154 c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size); 1155 } 1156 closure_glyphsOT::cmap1157 void closure_glyphs (const hb_set_t *unicodes, 1158 hb_set_t *glyphset) const 1159 { 1160 + hb_iter (encodingRecord) 1161 | hb_map (&EncodingRecord::subtable) 1162 | hb_map (hb_add (this)) 1163 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; }) 1164 | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); }) 1165 ; 1166 } 1167 subsetOT::cmap1168 bool subset (hb_subset_context_t *c) const 1169 { 1170 TRACE_SUBSET (this); 1171 1172 cmap *cmap_prime = c->serializer->start_embed<cmap> (); 1173 if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); 1174 1175 auto encodingrec_iter = 1176 + hb_iter (encodingRecord) 1177 | hb_filter ([&] (const EncodingRecord& _) 1178 { 1179 if ((_.platformID == 0 && _.encodingID == 3) || 1180 (_.platformID == 0 && _.encodingID == 4) || 1181 (_.platformID == 3 && _.encodingID == 1) || 1182 (_.platformID == 3 && _.encodingID == 10) || 1183 (this + _.subtable).u.format == 14) 1184 return true; 1185 1186 return false; 1187 }) 1188 ; 1189 1190 1191 if (unlikely (!encodingrec_iter.len ())) return_trace (false); 1192 1193 const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr; 1194 bool has_format12 = false; 1195 1196 for (const EncodingRecord& _ : encodingrec_iter) 1197 { 1198 unsigned format = (this + _.subtable).u.format; 1199 if (format == 12) has_format12 = true; 1200 1201 const EncodingRecord *table = hb_addressof (_); 1202 if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table; 1203 else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table; 1204 else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table; 1205 else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table; 1206 } 1207 1208 if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false); 1209 if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); 1210 1211 auto it = 1212 + hb_iter (c->plan->unicodes) 1213 | hb_map ([&] (hb_codepoint_t _) 1214 { 1215 hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; 1216 c->plan->new_gid_for_codepoint (_, &new_gid); 1217 return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid); 1218 }) 1219 | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) 1220 { return (_.second != HB_MAP_VALUE_INVALID); }) 1221 ; 1222 1223 cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan); 1224 return_trace (true); 1225 } 1226 find_best_subtableOT::cmap1227 const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const 1228 { 1229 if (symbol) *symbol = false; 1230 1231 const CmapSubtable *subtable; 1232 1233 /* Symbol subtable. 1234 * Prefer symbol if available. 1235 * https://github.com/harfbuzz/harfbuzz/issues/1918 */ 1236 if ((subtable = this->find_subtable (3, 0))) 1237 { 1238 if (symbol) *symbol = true; 1239 return subtable; 1240 } 1241 1242 /* 32-bit subtables. */ 1243 if ((subtable = this->find_subtable (3, 10))) return subtable; 1244 if ((subtable = this->find_subtable (0, 6))) return subtable; 1245 if ((subtable = this->find_subtable (0, 4))) return subtable; 1246 1247 /* 16-bit subtables. */ 1248 if ((subtable = this->find_subtable (3, 1))) return subtable; 1249 if ((subtable = this->find_subtable (0, 3))) return subtable; 1250 if ((subtable = this->find_subtable (0, 2))) return subtable; 1251 if ((subtable = this->find_subtable (0, 1))) return subtable; 1252 if ((subtable = this->find_subtable (0, 0))) return subtable; 1253 1254 /* Meh. */ 1255 return &Null (CmapSubtable); 1256 } 1257 1258 struct accelerator_t 1259 { initOT::cmap::accelerator_t1260 void init (hb_face_t *face) 1261 { 1262 this->table = hb_sanitize_context_t ().reference_table<cmap> (face); 1263 bool symbol; 1264 this->subtable = table->find_best_subtable (&symbol); 1265 this->subtable_uvs = &Null (CmapSubtableFormat14); 1266 { 1267 const CmapSubtable *st = table->find_subtable (0, 5); 1268 if (st && st->u.format == 14) 1269 subtable_uvs = &st->u.format14; 1270 } 1271 1272 this->get_glyph_data = subtable; 1273 if (unlikely (symbol)) 1274 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>; 1275 else 1276 { 1277 switch (subtable->u.format) { 1278 /* Accelerate format 4 and format 12. */ 1279 default: 1280 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>; 1281 break; 1282 case 12: 1283 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>; 1284 break; 1285 case 4: 1286 { 1287 this->format4_accel.init (&subtable->u.format4); 1288 this->get_glyph_data = &this->format4_accel; 1289 this->get_glyph_funcZ = this->format4_accel.get_glyph_func; 1290 break; 1291 } 1292 } 1293 } 1294 } 1295 finiOT::cmap::accelerator_t1296 void fini () { this->table.destroy (); } 1297 get_nominal_glyphOT::cmap::accelerator_t1298 bool get_nominal_glyph (hb_codepoint_t unicode, 1299 hb_codepoint_t *glyph) const 1300 { 1301 if (unlikely (!this->get_glyph_funcZ)) return false; 1302 return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); 1303 } get_nominal_glyphsOT::cmap::accelerator_t1304 unsigned int get_nominal_glyphs (unsigned int count, 1305 const hb_codepoint_t *first_unicode, 1306 unsigned int unicode_stride, 1307 hb_codepoint_t *first_glyph, 1308 unsigned int glyph_stride) const 1309 { 1310 if (unlikely (!this->get_glyph_funcZ)) return 0; 1311 1312 hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; 1313 const void *get_glyph_data = this->get_glyph_data; 1314 1315 unsigned int done; 1316 for (done = 0; 1317 done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); 1318 done++) 1319 { 1320 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); 1321 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); 1322 } 1323 return done; 1324 } 1325 get_variation_glyphOT::cmap::accelerator_t1326 bool get_variation_glyph (hb_codepoint_t unicode, 1327 hb_codepoint_t variation_selector, 1328 hb_codepoint_t *glyph) const 1329 { 1330 switch (this->subtable_uvs->get_glyph_variant (unicode, 1331 variation_selector, 1332 glyph)) 1333 { 1334 case GLYPH_VARIANT_NOT_FOUND: return false; 1335 case GLYPH_VARIANT_FOUND: return true; 1336 case GLYPH_VARIANT_USE_DEFAULT: break; 1337 } 1338 1339 return get_nominal_glyph (unicode, glyph); 1340 } 1341 collect_unicodesOT::cmap::accelerator_t1342 void collect_unicodes (hb_set_t *out) const 1343 { subtable->collect_unicodes (out); } collect_variation_selectorsOT::cmap::accelerator_t1344 void collect_variation_selectors (hb_set_t *out) const 1345 { subtable_uvs->collect_variation_selectors (out); } collect_variation_unicodesOT::cmap::accelerator_t1346 void collect_variation_unicodes (hb_codepoint_t variation_selector, 1347 hb_set_t *out) const 1348 { subtable_uvs->collect_variation_unicodes (variation_selector, out); } 1349 1350 protected: 1351 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, 1352 hb_codepoint_t codepoint, 1353 hb_codepoint_t *glyph); 1354 1355 template <typename Type> get_glyph_fromOT::cmap::accelerator_t1356 HB_INTERNAL static bool get_glyph_from (const void *obj, 1357 hb_codepoint_t codepoint, 1358 hb_codepoint_t *glyph) 1359 { 1360 const Type *typed_obj = (const Type *) obj; 1361 return typed_obj->get_glyph (codepoint, glyph); 1362 } 1363 1364 template <typename Type> get_glyph_from_symbolOT::cmap::accelerator_t1365 HB_INTERNAL static bool get_glyph_from_symbol (const void *obj, 1366 hb_codepoint_t codepoint, 1367 hb_codepoint_t *glyph) 1368 { 1369 const Type *typed_obj = (const Type *) obj; 1370 if (likely (typed_obj->get_glyph (codepoint, glyph))) 1371 return true; 1372 1373 if (codepoint <= 0x00FFu) 1374 { 1375 /* For symbol-encoded OpenType fonts, we duplicate the 1376 * U+F000..F0FF range at U+0000..U+00FF. That's what 1377 * Windows seems to do, and that's hinted about at: 1378 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom 1379 * under "Non-Standard (Symbol) Fonts". */ 1380 return typed_obj->get_glyph (0xF000u + codepoint, glyph); 1381 } 1382 1383 return false; 1384 } 1385 1386 private: 1387 hb_nonnull_ptr_t<const CmapSubtable> subtable; 1388 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs; 1389 1390 hb_cmap_get_glyph_func_t get_glyph_funcZ; 1391 const void *get_glyph_data; 1392 1393 CmapSubtableFormat4::accelerator_t format4_accel; 1394 1395 public: 1396 hb_blob_ptr_t<cmap> table; 1397 }; 1398 1399 protected: 1400 find_subtableOT::cmap1401 const CmapSubtable *find_subtable (unsigned int platform_id, 1402 unsigned int encoding_id) const 1403 { 1404 EncodingRecord key; 1405 key.platformID = platform_id; 1406 key.encodingID = encoding_id; 1407 1408 const EncodingRecord &result = encodingRecord.bsearch (key); 1409 if (!result.subtable) 1410 return nullptr; 1411 1412 return &(this+result.subtable); 1413 } 1414 find_encodingrecOT::cmap1415 const EncodingRecord *find_encodingrec (unsigned int platform_id, 1416 unsigned int encoding_id) const 1417 { 1418 EncodingRecord key; 1419 key.platformID = platform_id; 1420 key.encodingID = encoding_id; 1421 1422 return encodingRecord.as_array ().bsearch (key); 1423 } 1424 find_subtableOT::cmap1425 bool find_subtable (unsigned format) const 1426 { 1427 auto it = 1428 + hb_iter (encodingRecord) 1429 | hb_map (&EncodingRecord::subtable) 1430 | hb_map (hb_add (this)) 1431 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; }) 1432 ; 1433 1434 return it.len (); 1435 } 1436 1437 public: 1438 sanitizeOT::cmap1439 bool sanitize (hb_sanitize_context_t *c) const 1440 { 1441 TRACE_SANITIZE (this); 1442 return_trace (c->check_struct (this) && 1443 likely (version == 0) && 1444 encodingRecord.sanitize (c, this)); 1445 } 1446 1447 protected: 1448 HBUINT16 version; /* Table version number (0). */ 1449 SortedArrayOf<EncodingRecord> 1450 encodingRecord; /* Encoding tables. */ 1451 public: 1452 DEFINE_SIZE_ARRAY (4, encodingRecord); 1453 }; 1454 1455 struct cmap_accelerator_t : cmap::accelerator_t {}; 1456 1457 } /* namespace OT */ 1458 1459 1460 #endif /* HB_OT_CMAP_TABLE_HH */ 1461