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