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 #ifndef HB_OT_CFF_COMMON_HH 27 #define HB_OT_CFF_COMMON_HH 28 29 #include "hb-open-type.hh" 30 #include "hb-ot-layout-common.hh" 31 #include "hb-cff-interp-dict-common.hh" 32 #include "hb-subset-plan.hh" 33 34 namespace CFF { 35 36 using namespace OT; 37 38 #define CFF_UNDEF_CODE 0xFFFFFFFF 39 40 /* utility macro */ 41 template<typename Type> 42 static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset) 43 { return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); } 44 45 inline unsigned int calcOffSize(unsigned int dataSize) 46 { 47 unsigned int size = 1; 48 unsigned int offset = dataSize + 1; 49 while ((offset & ~0xFF) != 0) 50 { 51 size++; 52 offset >>= 8; 53 } 54 /* format does not support size > 4; caller should handle it as an error */ 55 return size; 56 } 57 58 struct code_pair 59 { 60 hb_codepoint_t code; 61 hb_codepoint_t glyph; 62 }; 63 64 typedef hb_vector_t<char, 1> StrBuff; 65 struct StrBuffArray : hb_vector_t<StrBuff> 66 { 67 void fini () { SUPER::fini_deep (); } 68 69 unsigned int total_size () const 70 { 71 unsigned int size = 0; 72 for (unsigned int i = 0; i < len; i++) 73 size += (*this)[i].len; 74 return size; 75 } 76 77 private: 78 typedef hb_vector_t<StrBuff> SUPER; 79 }; 80 81 /* CFF INDEX */ 82 template <typename COUNT> 83 struct CFFIndex 84 { 85 bool sanitize (hb_sanitize_context_t *c) const 86 { 87 TRACE_SANITIZE (this); 88 return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */ 89 (c->check_struct (this) && offSize >= 1 && offSize <= 4 && 90 c->check_array (offsets, offSize, count + 1) && 91 c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1)))); 92 } 93 94 static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) 95 { return offSize * (count + 1); } 96 97 unsigned int offset_array_size () const 98 { return calculate_offset_array_size (offSize, count); } 99 100 static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize) 101 { 102 if (count == 0) 103 return COUNT::static_size; 104 else 105 return min_size + calculate_offset_array_size (offSize, count) + dataSize; 106 } 107 108 bool serialize (hb_serialize_context_t *c, const CFFIndex &src) 109 { 110 TRACE_SERIALIZE (this); 111 unsigned int size = src.get_size (); 112 CFFIndex *dest = c->allocate_size<CFFIndex> (size); 113 if (unlikely (dest == nullptr)) return_trace (false); 114 memcpy (dest, &src, size); 115 return_trace (true); 116 } 117 118 bool serialize (hb_serialize_context_t *c, 119 unsigned int offSize_, 120 const ByteStrArray &byteArray) 121 { 122 TRACE_SERIALIZE (this); 123 if (byteArray.len == 0) 124 { 125 COUNT *dest = c->allocate_min<COUNT> (); 126 if (unlikely (dest == nullptr)) return_trace (false); 127 dest->set (0); 128 } 129 else 130 { 131 /* serialize CFFIndex header */ 132 if (unlikely (!c->extend_min (*this))) return_trace (false); 133 this->count.set (byteArray.len); 134 this->offSize.set (offSize_); 135 if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1)))) 136 return_trace (false); 137 138 /* serialize indices */ 139 unsigned int offset = 1; 140 unsigned int i = 0; 141 for (; i < byteArray.len; i++) 142 { 143 set_offset_at (i, offset); 144 offset += byteArray[i].get_size (); 145 } 146 set_offset_at (i, offset); 147 148 /* serialize data */ 149 for (unsigned int i = 0; i < byteArray.len; i++) 150 { 151 ByteStr *dest = c->start_embed<ByteStr> (); 152 if (unlikely (dest == nullptr || 153 !dest->serialize (c, byteArray[i]))) 154 return_trace (false); 155 } 156 } 157 return_trace (true); 158 } 159 160 bool serialize (hb_serialize_context_t *c, 161 unsigned int offSize_, 162 const StrBuffArray &buffArray) 163 { 164 ByteStrArray byteArray; 165 byteArray.init (); 166 byteArray.resize (buffArray.len); 167 for (unsigned int i = 0; i < byteArray.len; i++) 168 { 169 byteArray[i] = ByteStr (buffArray[i].arrayZ (), buffArray[i].len); 170 } 171 bool result = this->serialize (c, offSize_, byteArray); 172 byteArray.fini (); 173 return result; 174 } 175 176 void set_offset_at (unsigned int index, unsigned int offset) 177 { 178 HBUINT8 *p = offsets + offSize * index + offSize; 179 unsigned int size = offSize; 180 for (; size; size--) 181 { 182 --p; 183 p->set (offset & 0xFF); 184 offset >>= 8; 185 } 186 } 187 188 unsigned int offset_at (unsigned int index) const 189 { 190 assert (index <= count); 191 const HBUINT8 *p = offsets + offSize * index; 192 unsigned int size = offSize; 193 unsigned int offset = 0; 194 for (; size; size--) 195 offset = (offset << 8) + *p++; 196 return offset; 197 } 198 199 unsigned int length_at (unsigned int index) const 200 { 201 if (likely ((offset_at (index + 1) >= offset_at (index)) && 202 (offset_at (index + 1) <= offset_at (count)))) 203 return offset_at (index + 1) - offset_at (index); 204 else 205 return 0; 206 } 207 208 const char *data_base () const 209 { return (const char *)this + min_size + offset_array_size (); } 210 211 unsigned int data_size () const { return HBINT8::static_size; } 212 213 ByteStr operator [] (unsigned int index) const 214 { 215 if (likely (index < count)) 216 return ByteStr (data_base () + offset_at (index) - 1, length_at (index)); 217 else 218 return Null(ByteStr); 219 } 220 221 unsigned int get_size () const 222 { 223 if (this != &Null(CFFIndex)) 224 { 225 if (count > 0) 226 return min_size + offset_array_size () + (offset_at (count) - 1); 227 else 228 return count.static_size; /* empty CFFIndex contains count only */ 229 } 230 else 231 return 0; 232 } 233 234 protected: 235 unsigned int max_offset () const 236 { 237 unsigned int max = 0; 238 for (unsigned int i = 0; i < count + 1u; i++) 239 { 240 unsigned int off = offset_at (i); 241 if (off > max) max = off; 242 } 243 return max; 244 } 245 246 public: 247 COUNT count; /* Number of object data. Note there are (count+1) offsets */ 248 HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ 249 HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */ 250 /* HBUINT8 data[VAR]; Object data */ 251 public: 252 DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); 253 }; 254 255 template <typename COUNT, typename TYPE> 256 struct CFFIndexOf : CFFIndex<COUNT> 257 { 258 const ByteStr operator [] (unsigned int index) const 259 { 260 if (likely (index < CFFIndex<COUNT>::count)) 261 return ByteStr (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index)); 262 return Null(ByteStr); 263 } 264 265 template <typename DATA, typename PARAM1, typename PARAM2> 266 bool serialize (hb_serialize_context_t *c, 267 unsigned int offSize_, 268 const DATA *dataArray, 269 unsigned int dataArrayLen, 270 const hb_vector_t<unsigned int> &dataSizeArray, 271 const PARAM1 ¶m1, 272 const PARAM2 ¶m2) 273 { 274 TRACE_SERIALIZE (this); 275 /* serialize CFFIndex header */ 276 if (unlikely (!c->extend_min (*this))) return_trace (false); 277 this->count.set (dataArrayLen); 278 this->offSize.set (offSize_); 279 if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1)))) 280 return_trace (false); 281 282 /* serialize indices */ 283 unsigned int offset = 1; 284 unsigned int i = 0; 285 for (; i < dataArrayLen; i++) 286 { 287 CFFIndex<COUNT>::set_offset_at (i, offset); 288 offset += dataSizeArray[i]; 289 } 290 CFFIndex<COUNT>::set_offset_at (i, offset); 291 292 /* serialize data */ 293 for (unsigned int i = 0; i < dataArrayLen; i++) 294 { 295 TYPE *dest = c->start_embed<TYPE> (); 296 if (unlikely (dest == nullptr || 297 !dest->serialize (c, dataArray[i], param1, param2))) 298 return_trace (false); 299 } 300 return_trace (true); 301 } 302 303 /* in parallel to above */ 304 template <typename DATA, typename PARAM> 305 static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, 306 const DATA *dataArray, 307 unsigned int dataArrayLen, 308 hb_vector_t<unsigned int> &dataSizeArray, /* OUT */ 309 const PARAM ¶m) 310 { 311 /* determine offset size */ 312 unsigned int totalDataSize = 0; 313 for (unsigned int i = 0; i < dataArrayLen; i++) 314 { 315 unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); 316 dataSizeArray[i] = dataSize; 317 totalDataSize += dataSize; 318 } 319 offSize_ = calcOffSize (totalDataSize); 320 321 return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize); 322 } 323 }; 324 325 /* Top Dict, Font Dict, Private Dict */ 326 struct Dict : UnsizedByteStr 327 { 328 template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM> 329 bool serialize (hb_serialize_context_t *c, 330 const DICTVAL &dictval, 331 OP_SERIALIZER& opszr, 332 PARAM& param) 333 { 334 TRACE_SERIALIZE (this); 335 for (unsigned int i = 0; i < dictval.get_count (); i++) 336 { 337 if (unlikely (!opszr.serialize (c, dictval[i], param))) 338 return_trace (false); 339 } 340 return_trace (true); 341 } 342 343 /* in parallel to above */ 344 template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM> 345 static unsigned int calculate_serialized_size (const DICTVAL &dictval, 346 OP_SERIALIZER& opszr, 347 PARAM& param) 348 { 349 unsigned int size = 0; 350 for (unsigned int i = 0; i < dictval.get_count (); i++) 351 size += opszr.calculate_serialized_size (dictval[i], param); 352 return size; 353 } 354 355 template <typename DICTVAL, typename OP_SERIALIZER> 356 static unsigned int calculate_serialized_size (const DICTVAL &dictval, 357 OP_SERIALIZER& opszr) 358 { 359 unsigned int size = 0; 360 for (unsigned int i = 0; i < dictval.get_count (); i++) 361 size += opszr.calculate_serialized_size (dictval[i]); 362 return size; 363 } 364 365 template <typename INTTYPE, int minVal, int maxVal> 366 static bool serialize_int_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp) 367 { 368 // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation 369 if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value))) 370 return false; 371 372 TRACE_SERIALIZE (this); 373 /* serialize the opcode */ 374 HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op)); 375 if (unlikely (p == nullptr)) return_trace (false); 376 if (Is_OpCode_ESC (op)) 377 { 378 p->set (OpCode_escape); 379 op = Unmake_OpCode_ESC (op); 380 p++; 381 } 382 p->set (op); 383 return_trace (true); 384 } 385 386 static bool serialize_uint4_op (hb_serialize_context_t *c, OpCode op, int value) 387 { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); } 388 389 static bool serialize_uint2_op (hb_serialize_context_t *c, OpCode op, int value) 390 { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); } 391 392 static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value) 393 { 394 return serialize_uint4_op (c, op, value); 395 } 396 397 static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value) 398 { 399 return serialize_uint2_op (c, op, value); 400 } 401 }; 402 403 struct TopDict : Dict {}; 404 struct FontDict : Dict {}; 405 struct PrivateDict : Dict {}; 406 407 struct TableInfo 408 { 409 void init () { offSize = offset = size = 0; } 410 411 unsigned int offset; 412 unsigned int size; 413 unsigned int offSize; 414 }; 415 416 /* used to remap font index or SID from fullset to subset. 417 * set to CFF_UNDEF_CODE if excluded from subset */ 418 struct Remap : hb_vector_t<hb_codepoint_t> 419 { 420 void init () { SUPER::init (); } 421 422 void fini () { SUPER::fini (); } 423 424 bool reset (unsigned int size) 425 { 426 if (unlikely (!SUPER::resize (size))) 427 return false; 428 for (unsigned int i = 0; i < len; i++) 429 (*this)[i] = CFF_UNDEF_CODE; 430 count = 0; 431 return true; 432 } 433 434 bool identity (unsigned int size) 435 { 436 if (unlikely (!SUPER::resize (size))) 437 return false; 438 unsigned int i; 439 for (i = 0; i < len; i++) 440 (*this)[i] = i; 441 count = i; 442 return true; 443 } 444 445 bool excludes (hb_codepoint_t id) const 446 { return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); } 447 448 bool includes (hb_codepoint_t id) const 449 { return !excludes (id); } 450 451 unsigned int add (unsigned int i) 452 { 453 if ((*this)[i] == CFF_UNDEF_CODE) 454 (*this)[i] = count++; 455 return (*this)[i]; 456 } 457 458 hb_codepoint_t get_count () const { return count; } 459 460 protected: 461 hb_codepoint_t count; 462 463 private: 464 typedef hb_vector_t<hb_codepoint_t> SUPER; 465 }; 466 467 template <typename COUNT> 468 struct FDArray : CFFIndexOf<COUNT, FontDict> 469 { 470 /* used by CFF1 */ 471 template <typename DICTVAL, typename OP_SERIALIZER> 472 bool serialize (hb_serialize_context_t *c, 473 unsigned int offSize_, 474 const hb_vector_t<DICTVAL> &fontDicts, 475 OP_SERIALIZER& opszr) 476 { 477 TRACE_SERIALIZE (this); 478 if (unlikely (!c->extend_min (*this))) return_trace (false); 479 this->count.set (fontDicts.len); 480 this->offSize.set (offSize_); 481 if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.len + 1)))) 482 return_trace (false); 483 484 /* serialize font dict offsets */ 485 unsigned int offset = 1; 486 unsigned int fid = 0; 487 for (; fid < fontDicts.len; fid++) 488 { 489 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); 490 offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr); 491 } 492 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); 493 494 /* serialize font dicts */ 495 for (unsigned int i = 0; i < fontDicts.len; i++) 496 { 497 FontDict *dict = c->start_embed<FontDict> (); 498 if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) 499 return_trace (false); 500 } 501 return_trace (true); 502 } 503 504 /* used by CFF2 */ 505 template <typename DICTVAL, typename OP_SERIALIZER> 506 bool serialize (hb_serialize_context_t *c, 507 unsigned int offSize_, 508 const hb_vector_t<DICTVAL> &fontDicts, 509 unsigned int fdCount, 510 const Remap &fdmap, 511 OP_SERIALIZER& opszr, 512 const hb_vector_t<TableInfo> &privateInfos) 513 { 514 TRACE_SERIALIZE (this); 515 if (unlikely (!c->extend_min (*this))) return_trace (false); 516 this->count.set (fdCount); 517 this->offSize.set (offSize_); 518 if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1)))) 519 return_trace (false); 520 521 /* serialize font dict offsets */ 522 unsigned int offset = 1; 523 unsigned int fid = 0; 524 for (unsigned i = 0; i < fontDicts.len; i++) 525 if (fdmap.includes (i)) 526 { 527 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset); 528 offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); 529 } 530 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); 531 532 /* serialize font dicts */ 533 for (unsigned int i = 0; i < fontDicts.len; i++) 534 if (fdmap.includes (i)) 535 { 536 FontDict *dict = c->start_embed<FontDict> (); 537 if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) 538 return_trace (false); 539 } 540 return_trace (true); 541 } 542 543 /* in parallel to above */ 544 template <typename OP_SERIALIZER, typename DICTVAL> 545 static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, 546 const hb_vector_t<DICTVAL> &fontDicts, 547 unsigned int fdCount, 548 const Remap &fdmap, 549 OP_SERIALIZER& opszr) 550 { 551 unsigned int dictsSize = 0; 552 for (unsigned int i = 0; i < fontDicts.len; i++) 553 if (fdmap.includes (i)) 554 dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); 555 556 offSize_ = calcOffSize (dictsSize); 557 return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize); 558 } 559 }; 560 561 /* FDSelect */ 562 struct FDSelect0 { 563 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const 564 { 565 TRACE_SANITIZE (this); 566 if (unlikely (!(c->check_struct (this)))) 567 return_trace (false); 568 for (unsigned int i = 0; i < c->get_num_glyphs (); i++) 569 if (unlikely (!fds[i].sanitize (c))) 570 return_trace (false); 571 572 return_trace (true); 573 } 574 575 hb_codepoint_t get_fd (hb_codepoint_t glyph) const 576 { 577 return (hb_codepoint_t)fds[glyph]; 578 } 579 580 unsigned int get_size (unsigned int num_glyphs) const 581 { return HBUINT8::static_size * num_glyphs; } 582 583 HBUINT8 fds[VAR]; 584 585 DEFINE_SIZE_MIN (1); 586 }; 587 588 template <typename GID_TYPE, typename FD_TYPE> 589 struct FDSelect3_4_Range { 590 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const 591 { 592 TRACE_SANITIZE (this); 593 return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount))); 594 } 595 596 GID_TYPE first; 597 FD_TYPE fd; 598 599 DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size); 600 }; 601 602 template <typename GID_TYPE, typename FD_TYPE> 603 struct FDSelect3_4 { 604 unsigned int get_size () const 605 { return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; } 606 607 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const 608 { 609 TRACE_SANITIZE (this); 610 if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0)))) 611 return_trace (false); 612 613 for (unsigned int i = 0; i < nRanges; i++) 614 { 615 if (unlikely (!ranges[i].sanitize (c, fdcount))) 616 return_trace (false); 617 if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first)) 618 return_trace (false); 619 } 620 if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) 621 return_trace (false); 622 623 return_trace (true); 624 } 625 626 hb_codepoint_t get_fd (hb_codepoint_t glyph) const 627 { 628 unsigned int i; 629 for (i = 1; i < nRanges; i++) 630 if (glyph < ranges[i].first) 631 break; 632 633 return (hb_codepoint_t)ranges[i - 1].fd; 634 } 635 636 GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); } 637 const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); } 638 639 GID_TYPE nRanges; 640 FDSelect3_4_Range<GID_TYPE, FD_TYPE> ranges[VAR]; 641 /* GID_TYPE sentinel */ 642 643 DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges); 644 }; 645 646 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3; 647 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range; 648 649 struct FDSelect { 650 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const 651 { 652 TRACE_SANITIZE (this); 653 654 return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) && 655 (format == 0)? 656 u.format0.sanitize (c, fdcount): 657 u.format3.sanitize (c, fdcount))); 658 } 659 660 bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs) 661 { 662 TRACE_SERIALIZE (this); 663 unsigned int size = src.get_size (num_glyphs); 664 FDSelect *dest = c->allocate_size<FDSelect> (size); 665 if (unlikely (dest == nullptr)) return_trace (false); 666 memcpy (dest, &src, size); 667 return_trace (true); 668 } 669 670 unsigned int calculate_serialized_size (unsigned int num_glyphs) const 671 { return get_size (num_glyphs); } 672 673 unsigned int get_size (unsigned int num_glyphs) const 674 { 675 unsigned int size = format.static_size; 676 if (format == 0) 677 size += u.format0.get_size (num_glyphs); 678 else 679 size += u.format3.get_size (); 680 return size; 681 } 682 683 hb_codepoint_t get_fd (hb_codepoint_t glyph) const 684 { 685 if (this == &Null(FDSelect)) 686 return 0; 687 if (format == 0) 688 return u.format0.get_fd (glyph); 689 else 690 return u.format3.get_fd (glyph); 691 } 692 693 HBUINT8 format; 694 union { 695 FDSelect0 format0; 696 FDSelect3 format3; 697 } u; 698 699 DEFINE_SIZE_MIN (1); 700 }; 701 702 template <typename COUNT> 703 struct Subrs : CFFIndex<COUNT> 704 { 705 typedef COUNT count_type; 706 typedef CFFIndex<COUNT> SUPER; 707 }; 708 709 } /* namespace CFF */ 710 711 #endif /* HB_OT_CFF_COMMON_HH */ 712