1 /* 2 * Copyright © 2018 Adobe 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 * Adobe Author(s): Michiharu Ariza 25 */ 26 27 #ifndef HB_OT_CFF1_TABLE_HH 28 #define HB_OT_CFF1_TABLE_HH 29 30 #include "hb-ot-head-table.hh" 31 #include "hb-ot-cff-common.hh" 32 #include "hb-subset-cff1.hh" 33 34 namespace CFF { 35 36 /* 37 * CFF -- Compact Font Format (CFF) 38 * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf 39 */ 40 #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') 41 42 #define CFF_UNDEF_SID CFF_UNDEF_CODE 43 44 enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; 45 enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; 46 47 typedef CFFIndex<HBUINT16> CFF1Index; 48 template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {}; 49 50 typedef CFFIndex<HBUINT16> CFF1Index; 51 typedef CFF1Index CFF1CharStrings; 52 typedef FDArray<HBUINT16> CFF1FDArray; 53 typedef Subrs<HBUINT16> CFF1Subrs; 54 55 struct CFF1FDSelect : FDSelect {}; 56 57 /* Encoding */ 58 struct Encoding0 { sanitizeCFF::Encoding059 bool sanitize (hb_sanitize_context_t *c) const 60 { 61 TRACE_SANITIZE (this); 62 return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c)); 63 } 64 get_codeCFF::Encoding065 hb_codepoint_t get_code (hb_codepoint_t glyph) const 66 { 67 assert (glyph > 0); 68 glyph--; 69 if (glyph < nCodes) 70 { 71 return (hb_codepoint_t)codes[glyph]; 72 } 73 else 74 return CFF_UNDEF_CODE; 75 } 76 get_sizeCFF::Encoding077 unsigned int get_size () const 78 { return HBUINT8::static_size * (nCodes + 1); } 79 80 HBUINT8 nCodes; 81 HBUINT8 codes[VAR]; 82 83 DEFINE_SIZE_ARRAY(1, codes); 84 }; 85 86 struct Encoding1_Range { sanitizeCFF::Encoding1_Range87 bool sanitize (hb_sanitize_context_t *c) const 88 { 89 TRACE_SANITIZE (this); 90 return_trace (c->check_struct (this)); 91 } 92 93 HBUINT8 first; 94 HBUINT8 nLeft; 95 96 DEFINE_SIZE_STATIC (2); 97 }; 98 99 struct Encoding1 { get_sizeCFF::Encoding1100 unsigned int get_size () const 101 { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; } 102 sanitizeCFF::Encoding1103 bool sanitize (hb_sanitize_context_t *c) const 104 { 105 TRACE_SANITIZE (this); 106 return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); 107 } 108 get_codeCFF::Encoding1109 hb_codepoint_t get_code (hb_codepoint_t glyph) const 110 { 111 assert (glyph > 0); 112 glyph--; 113 for (unsigned int i = 0; i < nRanges; i++) 114 { 115 if (glyph <= ranges[i].nLeft) 116 { 117 return (hb_codepoint_t)ranges[i].first + glyph; 118 } 119 glyph -= (ranges[i].nLeft + 1); 120 } 121 return CFF_UNDEF_CODE; 122 } 123 124 HBUINT8 nRanges; 125 Encoding1_Range ranges[VAR]; 126 127 DEFINE_SIZE_ARRAY (1, ranges); 128 }; 129 130 struct SuppEncoding { sanitizeCFF::SuppEncoding131 bool sanitize (hb_sanitize_context_t *c) const 132 { 133 TRACE_SANITIZE (this); 134 return_trace (c->check_struct (this)); 135 } 136 137 HBUINT8 code; 138 HBUINT16 glyph; 139 140 DEFINE_SIZE_STATIC (3); 141 }; 142 143 struct CFF1SuppEncData { sanitizeCFF::CFF1SuppEncData144 bool sanitize (hb_sanitize_context_t *c) const 145 { 146 TRACE_SANITIZE (this); 147 return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c))); 148 } 149 get_codesCFF::CFF1SuppEncData150 void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const 151 { 152 for (unsigned int i = 0; i < nSups; i++) 153 if (sid == supps[i].glyph) 154 codes.push (supps[i].code); 155 } 156 get_sizeCFF::CFF1SuppEncData157 unsigned int get_size () const 158 { return HBUINT8::static_size + SuppEncoding::static_size * nSups; } 159 160 HBUINT8 nSups; 161 SuppEncoding supps[VAR]; 162 163 DEFINE_SIZE_ARRAY (1, supps); 164 }; 165 166 struct Encoding { sanitizeCFF::Encoding167 bool sanitize (hb_sanitize_context_t *c) const 168 { 169 TRACE_SANITIZE (this); 170 171 if (unlikely (!c->check_struct (this))) 172 return_trace (false); 173 unsigned int fmt = format & 0x7F; 174 if (unlikely (fmt > 1)) 175 return_trace (false); 176 if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c)))) 177 return_trace (false); 178 return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c)); 179 } 180 181 /* serialize a fullset Encoding */ serializeCFF::Encoding182 bool serialize (hb_serialize_context_t *c, const Encoding &src) 183 { 184 TRACE_SERIALIZE (this); 185 unsigned int size = src.get_size (); 186 Encoding *dest = c->allocate_size<Encoding> (size); 187 if (unlikely (dest == nullptr)) return_trace (false); 188 memcpy (dest, &src, size); 189 return_trace (true); 190 } 191 192 /* serialize a subset Encoding */ serializeCFF::Encoding193 bool serialize (hb_serialize_context_t *c, 194 uint8_t format, 195 unsigned int enc_count, 196 const hb_vector_t<code_pair>& code_ranges, 197 const hb_vector_t<code_pair>& supp_codes) 198 { 199 TRACE_SERIALIZE (this); 200 Encoding *dest = c->extend_min (*this); 201 if (unlikely (dest == nullptr)) return_trace (false); 202 dest->format.set (format | ((supp_codes.len > 0)? 0x80: 0)); 203 if (format == 0) 204 { 205 Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count); 206 if (unlikely (fmt0 == nullptr)) return_trace (false); 207 fmt0->nCodes.set (enc_count); 208 unsigned int glyph = 0; 209 for (unsigned int i = 0; i < code_ranges.len; i++) 210 { 211 hb_codepoint_t code = code_ranges[i].code; 212 for (int left = (int)code_ranges[i].glyph; left >= 0; left--) 213 fmt0->codes[glyph++].set (code++); 214 if (unlikely (!((glyph <= 0x100) && (code <= 0x100)))) 215 return_trace (false); 216 } 217 } 218 else 219 { 220 Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.len); 221 if (unlikely (fmt1 == nullptr)) return_trace (false); 222 fmt1->nRanges.set (code_ranges.len); 223 for (unsigned int i = 0; i < code_ranges.len; i++) 224 { 225 if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)))) 226 return_trace (false); 227 fmt1->ranges[i].first.set (code_ranges[i].code); 228 fmt1->ranges[i].nLeft.set (code_ranges[i].glyph); 229 } 230 } 231 if (supp_codes.len > 0) 232 { 233 CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.len); 234 if (unlikely (suppData == nullptr)) return_trace (false); 235 suppData->nSups.set (supp_codes.len); 236 for (unsigned int i = 0; i < supp_codes.len; i++) 237 { 238 suppData->supps[i].code.set (supp_codes[i].code); 239 suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */ 240 } 241 } 242 return_trace (true); 243 } 244 245 /* parallel to above: calculate the size of a subset Encoding */ calculate_serialized_sizeCFF::Encoding246 static unsigned int calculate_serialized_size (uint8_t format, 247 unsigned int enc_count, 248 unsigned int supp_count) 249 { 250 unsigned int size = min_size; 251 if (format == 0) 252 size += Encoding0::min_size + HBUINT8::static_size * enc_count; 253 else 254 size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; 255 if (supp_count > 0) 256 size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; 257 return size; 258 } 259 get_sizeCFF::Encoding260 unsigned int get_size () const 261 { 262 unsigned int size = min_size; 263 if (table_format () == 0) 264 size += u.format0.get_size (); 265 else 266 size += u.format1.get_size (); 267 if (has_supplement ()) 268 size += suppEncData ().get_size (); 269 return size; 270 } 271 get_codeCFF::Encoding272 hb_codepoint_t get_code (hb_codepoint_t glyph) const 273 { 274 if (table_format () == 0) 275 return u.format0.get_code (glyph); 276 else 277 return u.format1.get_code (glyph); 278 } 279 table_formatCFF::Encoding280 uint8_t table_format () const { return (format & 0x7F); } has_supplementCFF::Encoding281 bool has_supplement () const { return (format & 0x80) != 0; } 282 get_supplement_codesCFF::Encoding283 void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const 284 { 285 codes.resize (0); 286 if (has_supplement ()) 287 suppEncData().get_codes (sid, codes); 288 } 289 290 protected: suppEncDataCFF::Encoding291 const CFF1SuppEncData &suppEncData () const 292 { 293 if ((format & 0x7F) == 0) 294 return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]); 295 else 296 return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]); 297 } 298 299 public: 300 HBUINT8 format; 301 302 union { 303 Encoding0 format0; 304 Encoding1 format1; 305 } u; 306 /* CFF1SuppEncData suppEncData; */ 307 308 DEFINE_SIZE_MIN (1); 309 }; 310 311 /* Charset */ 312 struct Charset0 { sanitizeCFF::Charset0313 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const 314 { 315 TRACE_SANITIZE (this); 316 return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); 317 } 318 get_sidCFF::Charset0319 hb_codepoint_t get_sid (hb_codepoint_t glyph) const 320 { 321 if (glyph == 0) 322 return 0; 323 else 324 return sids[glyph - 1]; 325 } 326 get_glyphCFF::Charset0327 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const 328 { 329 if (sid == 0) 330 return 0; 331 332 for (unsigned int glyph = 1; glyph < num_glyphs; glyph++) 333 { 334 if (sids[glyph-1] == sid) 335 return glyph; 336 } 337 return 0; 338 } 339 get_sizeCFF::Charset0340 unsigned int get_size (unsigned int num_glyphs) const 341 { 342 assert (num_glyphs > 0); 343 return HBUINT16::static_size * (num_glyphs - 1); 344 } 345 346 HBUINT16 sids[VAR]; 347 348 DEFINE_SIZE_ARRAY(0, sids); 349 }; 350 351 template <typename TYPE> 352 struct Charset_Range { sanitizeCFF::Charset_Range353 bool sanitize (hb_sanitize_context_t *c) const 354 { 355 TRACE_SANITIZE (this); 356 return_trace (c->check_struct (this)); 357 } 358 359 HBUINT16 first; 360 TYPE nLeft; 361 362 DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size); 363 }; 364 365 template <typename TYPE> 366 struct Charset1_2 { sanitizeCFF::Charset1_2367 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const 368 { 369 TRACE_SANITIZE (this); 370 if (unlikely (!c->check_struct (this))) 371 return_trace (false); 372 num_glyphs--; 373 for (unsigned int i = 0; num_glyphs > 0; i++) 374 { 375 if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) 376 return_trace (false); 377 num_glyphs -= (ranges[i].nLeft + 1); 378 } 379 return_trace (true); 380 } 381 get_sidCFF::Charset1_2382 hb_codepoint_t get_sid (hb_codepoint_t glyph) const 383 { 384 if (glyph == 0) return 0; 385 glyph--; 386 for (unsigned int i = 0;; i++) 387 { 388 if (glyph <= ranges[i].nLeft) 389 return (hb_codepoint_t)ranges[i].first + glyph; 390 glyph -= (ranges[i].nLeft + 1); 391 } 392 393 return 0; 394 } 395 get_glyphCFF::Charset1_2396 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const 397 { 398 if (sid == 0) return 0; 399 hb_codepoint_t glyph = 1; 400 for (unsigned int i = 0;; i++) 401 { 402 if (glyph >= num_glyphs) 403 return 0; 404 if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft)) 405 return glyph + (sid - ranges[i].first); 406 glyph += (ranges[i].nLeft + 1); 407 } 408 409 return 0; 410 } 411 get_sizeCFF::Charset1_2412 unsigned int get_size (unsigned int num_glyphs) const 413 { 414 unsigned int size = HBUINT8::static_size; 415 int glyph = (int)num_glyphs; 416 417 assert (glyph > 0); 418 glyph--; 419 for (unsigned int i = 0; glyph > 0; i++) 420 { 421 glyph -= (ranges[i].nLeft + 1); 422 size += Charset_Range<TYPE>::static_size; 423 } 424 425 return size; 426 } 427 428 Charset_Range<TYPE> ranges[VAR]; 429 430 DEFINE_SIZE_ARRAY (0, ranges); 431 }; 432 433 typedef Charset1_2<HBUINT8> Charset1; 434 typedef Charset1_2<HBUINT16> Charset2; 435 typedef Charset_Range<HBUINT8> Charset1_Range; 436 typedef Charset_Range<HBUINT16> Charset2_Range; 437 438 struct Charset { sanitizeCFF::Charset439 bool sanitize (hb_sanitize_context_t *c) const 440 { 441 TRACE_SANITIZE (this); 442 443 if (unlikely (!c->check_struct (this))) 444 return_trace (false); 445 if (format == 0) 446 return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); 447 else if (format == 1) 448 return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); 449 else if (likely (format == 2)) 450 return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); 451 else 452 return_trace (false); 453 } 454 455 /* serialize a fullset Charset */ serializeCFF::Charset456 bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) 457 { 458 TRACE_SERIALIZE (this); 459 unsigned int size = src.get_size (num_glyphs); 460 Charset *dest = c->allocate_size<Charset> (size); 461 if (unlikely (dest == nullptr)) return_trace (false); 462 memcpy (dest, &src, size); 463 return_trace (true); 464 } 465 466 /* serialize a subset Charset */ serializeCFF::Charset467 bool serialize (hb_serialize_context_t *c, 468 uint8_t format, 469 unsigned int num_glyphs, 470 const hb_vector_t<code_pair>& sid_ranges) 471 { 472 TRACE_SERIALIZE (this); 473 Charset *dest = c->extend_min (*this); 474 if (unlikely (dest == nullptr)) return_trace (false); 475 dest->format.set (format); 476 if (format == 0) 477 { 478 Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); 479 if (unlikely (fmt0 == nullptr)) return_trace (false); 480 unsigned int glyph = 0; 481 for (unsigned int i = 0; i < sid_ranges.len; i++) 482 { 483 hb_codepoint_t sid = sid_ranges[i].code; 484 for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) 485 fmt0->sids[glyph++].set (sid++); 486 } 487 } 488 else if (format == 1) 489 { 490 Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.len); 491 if (unlikely (fmt1 == nullptr)) return_trace (false); 492 for (unsigned int i = 0; i < sid_ranges.len; i++) 493 { 494 if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) 495 return_trace (false); 496 fmt1->ranges[i].first.set (sid_ranges[i].code); 497 fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph); 498 } 499 } 500 else /* format 2 */ 501 { 502 Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.len); 503 if (unlikely (fmt2 == nullptr)) return_trace (false); 504 for (unsigned int i = 0; i < sid_ranges.len; i++) 505 { 506 if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) 507 return_trace (false); 508 fmt2->ranges[i].first.set (sid_ranges[i].code); 509 fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph); 510 } 511 } 512 return_trace (true); 513 } 514 515 /* parallel to above: calculate the size of a subset Charset */ calculate_serialized_sizeCFF::Charset516 static unsigned int calculate_serialized_size ( 517 uint8_t format, 518 unsigned int count) 519 { 520 unsigned int size = min_size; 521 if (format == 0) 522 size += Charset0::min_size + HBUINT16::static_size * (count - 1); 523 else if (format == 1) 524 size += Charset1::min_size + Charset1_Range::static_size * count; 525 else 526 size += Charset2::min_size + Charset2_Range::static_size * count; 527 528 return size; 529 } 530 get_sizeCFF::Charset531 unsigned int get_size (unsigned int num_glyphs) const 532 { 533 unsigned int size = min_size; 534 if (format == 0) 535 size += u.format0.get_size (num_glyphs); 536 else if (format == 1) 537 size += u.format1.get_size (num_glyphs); 538 else 539 size += u.format2.get_size (num_glyphs); 540 return size; 541 } 542 get_sidCFF::Charset543 hb_codepoint_t get_sid (hb_codepoint_t glyph) const 544 { 545 if (format == 0) 546 return u.format0.get_sid (glyph); 547 else if (format == 1) 548 return u.format1.get_sid (glyph); 549 else 550 return u.format2.get_sid (glyph); 551 } 552 get_glyphCFF::Charset553 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const 554 { 555 if (format == 0) 556 return u.format0.get_glyph (sid, num_glyphs); 557 else if (format == 1) 558 return u.format1.get_glyph (sid, num_glyphs); 559 else 560 return u.format2.get_glyph (sid, num_glyphs); 561 } 562 563 HBUINT8 format; 564 union { 565 Charset0 format0; 566 Charset1 format1; 567 Charset2 format2; 568 } u; 569 570 DEFINE_SIZE_MIN (1); 571 }; 572 573 struct CFF1StringIndex : CFF1Index 574 { serializeCFF::CFF1StringIndex575 bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, 576 unsigned int offSize_, const Remap &sidmap) 577 { 578 TRACE_SERIALIZE (this); 579 if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) 580 { 581 if (!unlikely (c->extend_min (this->count))) 582 return_trace (false); 583 count.set (0); 584 return_trace (true); 585 } 586 587 ByteStrArray bytesArray; 588 bytesArray.init (); 589 if (!bytesArray.resize (sidmap.get_count ())) 590 return_trace (false); 591 for (unsigned int i = 0; i < strings.count; i++) 592 { 593 hb_codepoint_t j = sidmap[i]; 594 if (j != CFF_UNDEF_CODE) 595 bytesArray[j] = strings[i]; 596 } 597 598 bool result = CFF1Index::serialize (c, offSize_, bytesArray); 599 bytesArray.fini (); 600 return_trace (result); 601 } 602 603 /* in parallel to above */ calculate_serialized_sizeCFF::CFF1StringIndex604 unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const Remap &sidmap) const 605 { 606 offSize = 0; 607 if ((count == 0) || (sidmap.get_count () == 0)) 608 return count.static_size; 609 610 unsigned int dataSize = 0; 611 for (unsigned int i = 0; i < count; i++) 612 if (sidmap[i] != CFF_UNDEF_CODE) 613 dataSize += length_at (i); 614 615 offSize = calcOffSize(dataSize); 616 return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize); 617 } 618 }; 619 620 struct CFF1TopDictInterpEnv : NumInterpEnv 621 { CFF1TopDictInterpEnvCFF::CFF1TopDictInterpEnv622 CFF1TopDictInterpEnv () 623 : NumInterpEnv(), prev_offset(0), last_offset(0) {} 624 625 unsigned int prev_offset; 626 unsigned int last_offset; 627 }; 628 629 struct NameDictValues 630 { 631 enum NameDictValIndex 632 { 633 version, 634 notice, 635 copyright, 636 fullName, 637 familyName, 638 weight, 639 postscript, 640 fontName, 641 baseFontName, 642 registry, 643 ordering, 644 645 ValCount 646 }; 647 initCFF::NameDictValues648 void init () 649 { 650 for (unsigned int i = 0; i < ValCount; i++) 651 values[i] = CFF_UNDEF_SID; 652 } 653 operator []CFF::NameDictValues654 unsigned int& operator[] (unsigned int i) 655 { assert (i < ValCount); return values[i]; } 656 operator []CFF::NameDictValues657 unsigned int operator[] (unsigned int i) const 658 { assert (i < ValCount); return values[i]; } 659 name_op_to_indexCFF::NameDictValues660 static enum NameDictValIndex name_op_to_index (OpCode op) 661 { 662 switch (op) { 663 default: // can't happen - just make some compiler happy 664 case OpCode_version: 665 return version; 666 case OpCode_Notice: 667 return notice; 668 case OpCode_Copyright: 669 return copyright; 670 case OpCode_FullName: 671 return fullName; 672 case OpCode_FamilyName: 673 return familyName; 674 case OpCode_Weight: 675 return weight; 676 case OpCode_PostScript: 677 return postscript; 678 case OpCode_FontName: 679 return fontName; 680 case OpCode_BaseFontName: 681 return baseFontName; 682 } 683 } 684 685 unsigned int values[ValCount]; 686 }; 687 688 struct CFF1TopDictVal : OpStr 689 { 690 unsigned int last_arg_offset; 691 }; 692 693 struct CFF1TopDictValues : TopDictValues<CFF1TopDictVal> 694 { initCFF::CFF1TopDictValues695 void init () 696 { 697 TopDictValues<CFF1TopDictVal>::init (); 698 699 nameSIDs.init (); 700 ros_supplement = 0; 701 cidCount = 8720; 702 EncodingOffset = 0; 703 CharsetOffset = 0; 704 FDSelectOffset = 0; 705 privateDictInfo.init (); 706 } finiCFF::CFF1TopDictValues707 void fini () { TopDictValues<CFF1TopDictVal>::fini (); } 708 is_CIDCFF::CFF1TopDictValues709 bool is_CID () const 710 { return nameSIDs[NameDictValues::registry] != CFF_UNDEF_SID; } 711 712 NameDictValues nameSIDs; 713 unsigned int ros_supplement_offset; 714 unsigned int ros_supplement; 715 unsigned int cidCount; 716 717 unsigned int EncodingOffset; 718 unsigned int CharsetOffset; 719 unsigned int FDSelectOffset; 720 TableInfo privateDictInfo; 721 }; 722 723 struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal> 724 { process_opCFF::CFF1TopDictOpSet725 static void process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval) 726 { 727 CFF1TopDictVal val; 728 val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ 729 730 switch (op) { 731 case OpCode_version: 732 case OpCode_Notice: 733 case OpCode_Copyright: 734 case OpCode_FullName: 735 case OpCode_FamilyName: 736 case OpCode_Weight: 737 case OpCode_PostScript: 738 case OpCode_BaseFontName: 739 dictval.nameSIDs[NameDictValues::name_op_to_index (op)] = env.argStack.pop_uint (); 740 env.clear_args (); 741 break; 742 case OpCode_isFixedPitch: 743 case OpCode_ItalicAngle: 744 case OpCode_UnderlinePosition: 745 case OpCode_UnderlineThickness: 746 case OpCode_PaintType: 747 case OpCode_CharstringType: 748 case OpCode_UniqueID: 749 case OpCode_StrokeWidth: 750 case OpCode_SyntheticBase: 751 case OpCode_CIDFontVersion: 752 case OpCode_CIDFontRevision: 753 case OpCode_CIDFontType: 754 case OpCode_UIDBase: 755 case OpCode_FontBBox: 756 case OpCode_XUID: 757 case OpCode_BaseFontBlend: 758 env.clear_args (); 759 break; 760 761 case OpCode_CIDCount: 762 dictval.cidCount = env.argStack.pop_uint (); 763 env.clear_args (); 764 break; 765 766 case OpCode_ROS: 767 dictval.ros_supplement = env.argStack.pop_uint (); 768 dictval.nameSIDs[NameDictValues::ordering] = env.argStack.pop_uint (); 769 dictval.nameSIDs[NameDictValues::registry] = env.argStack.pop_uint (); 770 env.clear_args (); 771 break; 772 773 case OpCode_Encoding: 774 dictval.EncodingOffset = env.argStack.pop_uint (); 775 env.clear_args (); 776 if (unlikely (dictval.EncodingOffset == 0)) return; 777 break; 778 779 case OpCode_charset: 780 dictval.CharsetOffset = env.argStack.pop_uint (); 781 env.clear_args (); 782 if (unlikely (dictval.CharsetOffset == 0)) return; 783 break; 784 785 case OpCode_FDSelect: 786 dictval.FDSelectOffset = env.argStack.pop_uint (); 787 env.clear_args (); 788 break; 789 790 case OpCode_Private: 791 dictval.privateDictInfo.offset = env.argStack.pop_uint (); 792 dictval.privateDictInfo.size = env.argStack.pop_uint (); 793 env.clear_args (); 794 break; 795 796 default: 797 env.last_offset = env.substr.offset; 798 TopDictOpSet<CFF1TopDictVal>::process_op (op, env, dictval); 799 /* Record this operand below if stack is empty, otherwise done */ 800 if (!env.argStack.is_empty ()) return; 801 break; 802 } 803 804 if (unlikely (env.in_error ())) return; 805 806 dictval.add_op (op, env.substr, val); 807 } 808 }; 809 810 struct CFF1FontDictValues : DictValues<OpStr> 811 { initCFF::CFF1FontDictValues812 void init () 813 { 814 DictValues<OpStr>::init (); 815 privateDictInfo.init (); 816 fontName = CFF_UNDEF_SID; 817 } finiCFF::CFF1FontDictValues818 void fini () { DictValues<OpStr>::fini (); } 819 820 TableInfo privateDictInfo; 821 unsigned int fontName; 822 }; 823 824 struct CFF1FontDictOpSet : DictOpSet 825 { process_opCFF::CFF1FontDictOpSet826 static void process_op (OpCode op, NumInterpEnv& env, CFF1FontDictValues& dictval) 827 { 828 switch (op) { 829 case OpCode_FontName: 830 dictval.fontName = env.argStack.pop_uint (); 831 env.clear_args (); 832 break; 833 case OpCode_FontMatrix: 834 case OpCode_PaintType: 835 env.clear_args (); 836 break; 837 case OpCode_Private: 838 dictval.privateDictInfo.offset = env.argStack.pop_uint (); 839 dictval.privateDictInfo.size = env.argStack.pop_uint (); 840 env.clear_args (); 841 break; 842 843 default: 844 DictOpSet::process_op (op, env); 845 if (!env.argStack.is_empty ()) return; 846 break; 847 } 848 849 if (unlikely (env.in_error ())) return; 850 851 dictval.add_op (op, env.substr); 852 } 853 }; 854 855 template <typename VAL> 856 struct CFF1PrivateDictValues_Base : DictValues<VAL> 857 { initCFF::CFF1PrivateDictValues_Base858 void init () 859 { 860 DictValues<VAL>::init (); 861 subrsOffset = 0; 862 localSubrs = &Null(CFF1Subrs); 863 } finiCFF::CFF1PrivateDictValues_Base864 void fini () { DictValues<VAL>::fini (); } 865 calculate_serialized_sizeCFF::CFF1PrivateDictValues_Base866 unsigned int calculate_serialized_size () const 867 { 868 unsigned int size = 0; 869 for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++) 870 if (DictValues<VAL>::get_value (i).op == OpCode_Subrs) 871 size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); 872 else 873 size += DictValues<VAL>::get_value (i).str.len; 874 return size; 875 } 876 877 unsigned int subrsOffset; 878 const CFF1Subrs *localSubrs; 879 }; 880 881 typedef CFF1PrivateDictValues_Base<OpStr> CFF1PrivateDictValues_Subset; 882 typedef CFF1PrivateDictValues_Base<NumDictVal> CFF1PrivateDictValues; 883 884 struct CFF1PrivateDictOpSet : DictOpSet 885 { process_opCFF::CFF1PrivateDictOpSet886 static void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues& dictval) 887 { 888 NumDictVal val; 889 val.init (); 890 891 switch (op) { 892 case OpCode_BlueValues: 893 case OpCode_OtherBlues: 894 case OpCode_FamilyBlues: 895 case OpCode_FamilyOtherBlues: 896 case OpCode_StemSnapH: 897 case OpCode_StemSnapV: 898 env.clear_args (); 899 break; 900 case OpCode_StdHW: 901 case OpCode_StdVW: 902 case OpCode_BlueScale: 903 case OpCode_BlueShift: 904 case OpCode_BlueFuzz: 905 case OpCode_ForceBold: 906 case OpCode_LanguageGroup: 907 case OpCode_ExpansionFactor: 908 case OpCode_initialRandomSeed: 909 case OpCode_defaultWidthX: 910 case OpCode_nominalWidthX: 911 val.single_val = env.argStack.pop_num (); 912 env.clear_args (); 913 break; 914 case OpCode_Subrs: 915 dictval.subrsOffset = env.argStack.pop_uint (); 916 env.clear_args (); 917 break; 918 919 default: 920 DictOpSet::process_op (op, env); 921 if (!env.argStack.is_empty ()) return; 922 break; 923 } 924 925 if (unlikely (env.in_error ())) return; 926 927 dictval.add_op (op, env.substr, val); 928 } 929 }; 930 931 struct CFF1PrivateDictOpSet_Subset : DictOpSet 932 { process_opCFF::CFF1PrivateDictOpSet_Subset933 static void process_op (OpCode op, NumInterpEnv& env, CFF1PrivateDictValues_Subset& dictval) 934 { 935 switch (op) { 936 case OpCode_BlueValues: 937 case OpCode_OtherBlues: 938 case OpCode_FamilyBlues: 939 case OpCode_FamilyOtherBlues: 940 case OpCode_StemSnapH: 941 case OpCode_StemSnapV: 942 case OpCode_StdHW: 943 case OpCode_StdVW: 944 case OpCode_BlueScale: 945 case OpCode_BlueShift: 946 case OpCode_BlueFuzz: 947 case OpCode_ForceBold: 948 case OpCode_LanguageGroup: 949 case OpCode_ExpansionFactor: 950 case OpCode_initialRandomSeed: 951 case OpCode_defaultWidthX: 952 case OpCode_nominalWidthX: 953 env.clear_args (); 954 break; 955 956 case OpCode_Subrs: 957 dictval.subrsOffset = env.argStack.pop_uint (); 958 env.clear_args (); 959 break; 960 961 default: 962 DictOpSet::process_op (op, env); 963 if (!env.argStack.is_empty ()) return; 964 break; 965 } 966 967 if (unlikely (env.in_error ())) return; 968 969 dictval.add_op (op, env.substr); 970 } 971 }; 972 973 typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues, CFF1TopDictInterpEnv> CFF1TopDict_Interpreter; 974 typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter; 975 typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter; 976 977 typedef CFF1Index CFF1NameIndex; 978 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; 979 980 }; /* namespace CFF */ 981 982 namespace OT { 983 984 using namespace CFF; 985 986 struct cff1 987 { 988 static const hb_tag_t tableTag = HB_OT_TAG_cff1; 989 sanitizeOT::cff1990 bool sanitize (hb_sanitize_context_t *c) const 991 { 992 TRACE_SANITIZE (this); 993 return_trace (c->check_struct (this) && 994 likely (version.major == 1)); 995 } 996 997 template <typename PRIVOPSET, typename PRIVDICTVAL> 998 struct accelerator_templ_t 999 { initOT::cff1::accelerator_templ_t1000 void init (hb_face_t *face) 1001 { 1002 topDict.init (); 1003 fontDicts.init (); 1004 privateDicts.init (); 1005 1006 this->blob = sc.reference_table<cff1> (face); 1007 1008 /* setup for run-time santization */ 1009 sc.init (this->blob); 1010 sc.start_processing (); 1011 1012 const OT::cff1 *cff = this->blob->template as<OT::cff1> (); 1013 1014 if (cff == &Null(OT::cff1)) 1015 { fini (); return; } 1016 1017 nameIndex = &cff->nameIndex (cff); 1018 if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) 1019 { fini (); return; } 1020 1021 topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); 1022 if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) 1023 { fini (); return; } 1024 1025 { /* parse top dict */ 1026 const ByteStr topDictStr = (*topDictIndex)[0]; 1027 if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } 1028 CFF1TopDict_Interpreter top_interp; 1029 top_interp.env.init (topDictStr); 1030 topDict.init (); 1031 if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } 1032 } 1033 1034 if (is_predef_charset ()) 1035 charset = &Null(Charset); 1036 else 1037 { 1038 charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); 1039 if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } 1040 } 1041 1042 fdCount = 1; 1043 if (is_CID ()) 1044 { 1045 fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset); 1046 fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); 1047 if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || 1048 (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) 1049 { fini (); return; } 1050 1051 fdCount = fdArray->count; 1052 } 1053 else 1054 { 1055 fdArray = &Null(CFF1FDArray); 1056 fdSelect = &Null(CFF1FDSelect); 1057 } 1058 1059 stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); 1060 if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) 1061 { fini (); return; } 1062 1063 globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); 1064 if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) 1065 { fini (); return; } 1066 1067 charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset); 1068 1069 if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) 1070 { fini (); return; } 1071 1072 num_glyphs = charStrings->count; 1073 if (num_glyphs != sc.get_num_glyphs ()) 1074 { fini (); return; } 1075 1076 privateDicts.resize (fdCount); 1077 for (unsigned int i = 0; i < fdCount; i++) 1078 privateDicts[i].init (); 1079 1080 // parse CID font dicts and gather private dicts 1081 if (is_CID ()) 1082 { 1083 for (unsigned int i = 0; i < fdCount; i++) 1084 { 1085 ByteStr fontDictStr = (*fdArray)[i]; 1086 if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } 1087 CFF1FontDictValues *font; 1088 CFF1FontDict_Interpreter font_interp; 1089 font_interp.env.init (fontDictStr); 1090 font = fontDicts.push (); 1091 if (unlikely (font == &Crap(CFF1FontDictValues))) { fini (); return; } 1092 font->init (); 1093 if (unlikely (!font_interp.interpret (*font))) { fini (); return; } 1094 PRIVDICTVAL *priv = &privateDicts[i]; 1095 const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); 1096 if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } 1097 DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp; 1098 priv_interp.env.init (privDictStr); 1099 priv->init (); 1100 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } 1101 1102 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset); 1103 if (priv->localSubrs != &Null(CFF1Subrs) && 1104 unlikely (!priv->localSubrs->sanitize (&sc))) 1105 { fini (); return; } 1106 } 1107 } 1108 else /* non-CID */ 1109 { 1110 CFF1TopDictValues *font = &topDict; 1111 PRIVDICTVAL *priv = &privateDicts[0]; 1112 1113 const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); 1114 if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } 1115 DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp; 1116 priv_interp.env.init (privDictStr); 1117 priv->init (); 1118 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } 1119 1120 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset); 1121 if (priv->localSubrs != &Null(CFF1Subrs) && 1122 unlikely (!priv->localSubrs->sanitize (&sc))) 1123 { fini (); return; } 1124 } 1125 } 1126 finiOT::cff1::accelerator_templ_t1127 void fini () 1128 { 1129 sc.end_processing (); 1130 topDict.fini (); 1131 fontDicts.fini_deep (); 1132 privateDicts.fini_deep (); 1133 hb_blob_destroy (blob); 1134 blob = nullptr; 1135 } 1136 is_validOT::cff1::accelerator_templ_t1137 bool is_valid () const { return blob != nullptr; } is_CIDOT::cff1::accelerator_templ_t1138 bool is_CID () const { return topDict.is_CID (); } 1139 is_predef_charsetOT::cff1::accelerator_templ_t1140 bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } 1141 std_code_to_glyphOT::cff1::accelerator_templ_t1142 unsigned int std_code_to_glyph (hb_codepoint_t code) const 1143 { 1144 hb_codepoint_t sid = lookup_standard_encoding_for_sid (code); 1145 if (unlikely (sid == CFF_UNDEF_SID)) 1146 return 0; 1147 1148 if (charset != &Null(Charset)) 1149 return charset->get_glyph (sid, num_glyphs); 1150 else if ((topDict.CharsetOffset == ISOAdobeCharset) 1151 && (code <= 228 /*zcaron*/)) return sid; 1152 return 0; 1153 } 1154 1155 protected: 1156 hb_blob_t *blob; 1157 hb_sanitize_context_t sc; 1158 1159 public: 1160 const Charset *charset; 1161 const CFF1NameIndex *nameIndex; 1162 const CFF1TopDictIndex *topDictIndex; 1163 const CFF1StringIndex *stringIndex; 1164 const CFF1Subrs *globalSubrs; 1165 const CFF1CharStrings *charStrings; 1166 const CFF1FDArray *fdArray; 1167 const CFF1FDSelect *fdSelect; 1168 unsigned int fdCount; 1169 1170 CFF1TopDictValues topDict; 1171 hb_vector_t<CFF1FontDictValues> fontDicts; 1172 hb_vector_t<PRIVDICTVAL> privateDicts; 1173 1174 unsigned int num_glyphs; 1175 }; 1176 1177 struct accelerator_t : accelerator_templ_t<CFF1PrivateDictOpSet, CFF1PrivateDictValues> 1178 { 1179 HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; 1180 HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; 1181 }; 1182 1183 struct accelerator_subset_t : accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset> 1184 { initOT::cff1::accelerator_subset_t1185 void init (hb_face_t *face) 1186 { 1187 SUPER::init (face); 1188 if (blob == nullptr) return; 1189 1190 const OT::cff1 *cff = this->blob->as<OT::cff1> (); 1191 encoding = &Null(Encoding); 1192 if (is_CID ()) 1193 { 1194 if (unlikely (charset == &Null(Charset))) { fini (); return; } 1195 } 1196 else 1197 { 1198 if (!is_predef_encoding ()) 1199 { 1200 encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); 1201 if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } 1202 } 1203 } 1204 } 1205 is_predef_encodingOT::cff1::accelerator_subset_t1206 bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } 1207 glyph_to_codeOT::cff1::accelerator_subset_t1208 hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const 1209 { 1210 if (encoding != &Null(Encoding)) 1211 return encoding->get_code (glyph); 1212 else 1213 { 1214 hb_codepoint_t sid = glyph_to_sid (glyph); 1215 if (sid == 0) return 0; 1216 hb_codepoint_t code = 0; 1217 switch (topDict.EncodingOffset) 1218 { 1219 case StandardEncoding: 1220 code = lookup_standard_encoding_for_code (sid); 1221 break; 1222 case ExpertEncoding: 1223 code = lookup_expert_encoding_for_code (sid); 1224 break; 1225 default: 1226 break; 1227 } 1228 return code; 1229 } 1230 } 1231 glyph_to_sidOT::cff1::accelerator_subset_t1232 hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const 1233 { 1234 if (charset != &Null(Charset)) 1235 return charset->get_sid (glyph); 1236 else 1237 { 1238 hb_codepoint_t sid = 0; 1239 switch (topDict.CharsetOffset) 1240 { 1241 case ISOAdobeCharset: 1242 if (glyph <= 228 /*zcaron*/) sid = glyph; 1243 break; 1244 case ExpertCharset: 1245 sid = lookup_expert_charset_for_sid (glyph); 1246 break; 1247 case ExpertSubsetCharset: 1248 sid = lookup_expert_subset_charset_for_sid (glyph); 1249 break; 1250 default: 1251 break; 1252 } 1253 return sid; 1254 } 1255 } 1256 1257 const Encoding *encoding; 1258 1259 private: 1260 typedef accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset> SUPER; 1261 }; 1262 subsetOT::cff11263 bool subset (hb_subset_plan_t *plan) const 1264 { 1265 hb_blob_t *cff_prime = nullptr; 1266 1267 bool success = true; 1268 if (hb_subset_cff1 (plan, &cff_prime)) { 1269 success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime); 1270 hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); 1271 success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); 1272 hb_blob_destroy (head_blob); 1273 } else { 1274 success = false; 1275 } 1276 hb_blob_destroy (cff_prime); 1277 1278 return success; 1279 } 1280 1281 protected: 1282 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); 1283 HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); 1284 HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); 1285 HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); 1286 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); 1287 1288 public: 1289 FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */ 1290 OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */ 1291 HBUINT8 offSize; /* offset size (unused?) */ 1292 1293 public: 1294 DEFINE_SIZE_STATIC (4); 1295 }; 1296 1297 struct cff1_accelerator_t : cff1::accelerator_t {}; 1298 } /* namespace OT */ 1299 1300 #endif /* HB_OT_CFF1_TABLE_HH */ 1301