hb-ot-cff2-table.hh (16242B)
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_CFF2_TABLE_HH 28 #define HB_OT_CFF2_TABLE_HH 29 30 #include "hb-ot-cff-common.hh" 31 #include "hb-subset-cff-common.hh" 32 #include "hb-draw.hh" 33 #include "hb-paint.hh" 34 35 namespace CFF { 36 37 /* 38 * CFF2 -- Compact Font Format (CFF) Version 2 39 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2 40 */ 41 #define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2') 42 43 typedef CFF2Index CFF2CharStrings; 44 typedef Subrs<HBUINT32> CFF2Subrs; 45 46 typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4; 47 typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range; 48 49 struct CFF2FDSelect 50 { 51 bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs) 52 { 53 TRACE_SERIALIZE (this); 54 unsigned int size = src.get_size (num_glyphs); 55 CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size); 56 if (unlikely (!dest)) return_trace (false); 57 hb_memcpy (dest, &src, size); 58 return_trace (true); 59 } 60 61 unsigned int get_size (unsigned int num_glyphs) const 62 { 63 switch (format) 64 { 65 case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs); 66 case 3: hb_barrier (); return format.static_size + u.format3.get_size (); 67 case 4: hb_barrier (); return format.static_size + u.format4.get_size (); 68 default:return 0; 69 } 70 } 71 72 hb_codepoint_t get_fd (hb_codepoint_t glyph) const 73 { 74 if (this == &Null (CFF2FDSelect)) 75 return 0; 76 77 switch (format) 78 { 79 case 0: hb_barrier (); return u.format0.get_fd (glyph); 80 case 3: hb_barrier (); return u.format3.get_fd (glyph); 81 case 4: hb_barrier (); return u.format4.get_fd (glyph); 82 default:return 0; 83 } 84 } 85 86 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const 87 { 88 TRACE_SANITIZE (this); 89 if (unlikely (!c->check_struct (this))) 90 return_trace (false); 91 hb_barrier (); 92 93 switch (format) 94 { 95 case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount)); 96 case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount)); 97 case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount)); 98 default:return_trace (false); 99 } 100 } 101 102 HBUINT8 format; 103 union { 104 FDSelect0 format0; 105 FDSelect3 format3; 106 FDSelect4 format4; 107 } u; 108 public: 109 DEFINE_SIZE_MIN (2); 110 }; 111 112 struct CFF2ItemVariationStore 113 { 114 bool sanitize (hb_sanitize_context_t *c) const 115 { 116 TRACE_SANITIZE (this); 117 return_trace (c->check_struct (this) && 118 hb_barrier () && 119 c->check_range (&varStore, size) && 120 varStore.sanitize (c)); 121 } 122 123 bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore) 124 { 125 TRACE_SERIALIZE (this); 126 unsigned int size_ = varStore->get_size (); 127 CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_); 128 if (unlikely (!dest)) return_trace (false); 129 hb_memcpy (dest, varStore, size_); 130 return_trace (true); 131 } 132 133 unsigned int get_size () const { return HBUINT16::static_size + size; } 134 135 HBUINT16 size; 136 ItemVariationStore varStore; 137 138 DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size); 139 }; 140 141 struct cff2_top_dict_values_t : top_dict_values_t<> 142 { 143 void init () 144 { 145 top_dict_values_t<>::init (); 146 vstoreOffset = 0; 147 FDSelectOffset = 0; 148 } 149 void fini () { top_dict_values_t<>::fini (); } 150 151 int vstoreOffset; 152 int FDSelectOffset; 153 }; 154 155 struct cff2_top_dict_opset_t : top_dict_opset_t<> 156 { 157 static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval) 158 { 159 switch (op) { 160 case OpCode_FontMatrix: 161 { 162 dict_val_t val; 163 val.init (); 164 dictval.add_op (op, env.str_ref); 165 env.clear_args (); 166 } 167 break; 168 169 case OpCode_vstore: 170 dictval.vstoreOffset = env.argStack.pop_int (); 171 env.clear_args (); 172 break; 173 case OpCode_FDSelect: 174 dictval.FDSelectOffset = env.argStack.pop_int (); 175 env.clear_args (); 176 break; 177 178 default: 179 SUPER::process_op (op, env, dictval); 180 /* Record this operand below if stack is empty, otherwise done */ 181 if (!env.argStack.is_empty ()) return; 182 } 183 184 if (unlikely (env.in_error ())) return; 185 186 dictval.add_op (op, env.str_ref); 187 } 188 189 typedef top_dict_opset_t<> SUPER; 190 }; 191 192 struct cff2_font_dict_values_t : dict_values_t<op_str_t> 193 { 194 void init () 195 { 196 dict_values_t<op_str_t>::init (); 197 privateDictInfo.init (); 198 } 199 void fini () { dict_values_t<op_str_t>::fini (); } 200 201 table_info_t privateDictInfo; 202 }; 203 204 struct cff2_font_dict_opset_t : dict_opset_t 205 { 206 static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval) 207 { 208 switch (op) { 209 case OpCode_Private: 210 dictval.privateDictInfo.offset = env.argStack.pop_uint (); 211 dictval.privateDictInfo.size = env.argStack.pop_uint (); 212 env.clear_args (); 213 break; 214 215 default: 216 SUPER::process_op (op, env); 217 if (!env.argStack.is_empty ()) 218 return; 219 } 220 221 if (unlikely (env.in_error ())) return; 222 223 dictval.add_op (op, env.str_ref); 224 } 225 226 private: 227 typedef dict_opset_t SUPER; 228 }; 229 230 template <typename VAL> 231 struct cff2_private_dict_values_base_t : dict_values_t<VAL> 232 { 233 void init () 234 { 235 dict_values_t<VAL>::init (); 236 subrsOffset = 0; 237 localSubrs = &Null (CFF2Subrs); 238 ivs = 0; 239 } 240 void fini () { dict_values_t<VAL>::fini (); } 241 242 int subrsOffset; 243 const CFF2Subrs *localSubrs; 244 unsigned int ivs; 245 }; 246 247 typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t; 248 typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t; 249 250 struct cff2_priv_dict_interp_env_t : num_interp_env_t 251 { 252 cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) : 253 num_interp_env_t (str) {} 254 255 void process_vsindex () 256 { 257 if (likely (!seen_vsindex)) 258 { 259 set_ivs (argStack.pop_uint ()); 260 } 261 seen_vsindex = true; 262 } 263 264 unsigned int get_ivs () const { return ivs; } 265 void set_ivs (unsigned int ivs_) { ivs = ivs_; } 266 267 protected: 268 unsigned int ivs = 0; 269 bool seen_vsindex = false; 270 }; 271 272 struct cff2_private_dict_opset_t : dict_opset_t 273 { 274 static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval) 275 { 276 num_dict_val_t val; 277 val.init (); 278 279 switch (op) { 280 case OpCode_StdHW: 281 case OpCode_StdVW: 282 case OpCode_BlueScale: 283 case OpCode_BlueShift: 284 case OpCode_BlueFuzz: 285 case OpCode_ExpansionFactor: 286 case OpCode_LanguageGroup: 287 case OpCode_BlueValues: 288 case OpCode_OtherBlues: 289 case OpCode_FamilyBlues: 290 case OpCode_FamilyOtherBlues: 291 case OpCode_StemSnapH: 292 case OpCode_StemSnapV: 293 env.clear_args (); 294 break; 295 case OpCode_Subrs: 296 dictval.subrsOffset = env.argStack.pop_int (); 297 env.clear_args (); 298 break; 299 case OpCode_vsindexdict: 300 env.process_vsindex (); 301 dictval.ivs = env.get_ivs (); 302 env.clear_args (); 303 break; 304 case OpCode_blenddict: 305 break; 306 307 default: 308 dict_opset_t::process_op (op, env); 309 if (!env.argStack.is_empty ()) return; 310 break; 311 } 312 313 if (unlikely (env.in_error ())) return; 314 315 dictval.add_op (op, env.str_ref, val); 316 } 317 }; 318 319 struct cff2_private_dict_opset_subset_t : dict_opset_t 320 { 321 static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval) 322 { 323 switch (op) { 324 case OpCode_BlueValues: 325 case OpCode_OtherBlues: 326 case OpCode_FamilyBlues: 327 case OpCode_FamilyOtherBlues: 328 case OpCode_StdHW: 329 case OpCode_StdVW: 330 case OpCode_BlueScale: 331 case OpCode_BlueShift: 332 case OpCode_BlueFuzz: 333 case OpCode_StemSnapH: 334 case OpCode_StemSnapV: 335 case OpCode_LanguageGroup: 336 case OpCode_ExpansionFactor: 337 env.clear_args (); 338 break; 339 340 case OpCode_blenddict: 341 env.clear_args (); 342 return; 343 344 case OpCode_Subrs: 345 dictval.subrsOffset = env.argStack.pop_int (); 346 env.clear_args (); 347 break; 348 349 default: 350 SUPER::process_op (op, env); 351 if (!env.argStack.is_empty ()) return; 352 break; 353 } 354 355 if (unlikely (env.in_error ())) return; 356 357 dictval.add_op (op, env.str_ref); 358 } 359 360 private: 361 typedef dict_opset_t SUPER; 362 }; 363 364 typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t; 365 typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t; 366 367 struct CFF2FDArray : FDArray<HBUINT32> 368 { 369 /* FDArray::serialize does not compile without this partial specialization */ 370 template <typename ITER, typename OP_SERIALIZER> 371 bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) 372 { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); } 373 }; 374 375 } /* namespace CFF */ 376 377 namespace OT { 378 379 using namespace CFF; 380 381 struct cff2 382 { 383 static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2; 384 385 bool sanitize (hb_sanitize_context_t *c) const 386 { 387 TRACE_SANITIZE (this); 388 return_trace (c->check_struct (this) && 389 hb_barrier () && 390 likely (version.major == 2)); 391 } 392 393 template <typename PRIVOPSET, typename PRIVDICTVAL> 394 struct accelerator_templ_t 395 { 396 static constexpr hb_tag_t tableTag = cff2::tableTag; 397 398 accelerator_templ_t (hb_face_t *face) 399 { 400 if (!face) return; 401 402 topDict.init (); 403 fontDicts.init (); 404 privateDicts.init (); 405 406 this->blob = sc.reference_table<cff2> (face); 407 408 /* setup for run-time sanitization */ 409 sc.init (this->blob); 410 sc.start_processing (); 411 412 const OT::cff2 *cff2 = this->blob->template as<OT::cff2> (); 413 414 if (cff2 == &Null (OT::cff2)) 415 goto fail; 416 417 { /* parse top dict */ 418 hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); 419 if (unlikely (!topDictStr.sanitize (&sc))) goto fail; 420 hb_barrier (); 421 num_interp_env_t env (topDictStr); 422 cff2_top_dict_interpreter_t top_interp (env); 423 topDict.init (); 424 if (unlikely (!top_interp.interpret (topDict))) goto fail; 425 } 426 427 globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc); 428 varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc); 429 charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc); 430 fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc); 431 fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count); 432 433 if (charStrings == &Null (CFF2CharStrings) || 434 globalSubrs == &Null (CFF2Subrs) || 435 fdArray == &Null (CFF2FDArray)) 436 goto fail; 437 438 num_glyphs = charStrings->count; 439 if (num_glyphs != sc.get_num_glyphs ()) 440 goto fail; 441 442 fdCount = fdArray->count; 443 if (!privateDicts.resize (fdCount)) 444 goto fail; 445 446 /* parse font dicts and gather private dicts */ 447 for (unsigned int i = 0; i < fdCount; i++) 448 { 449 const hb_ubytes_t fontDictStr = (*fdArray)[i]; 450 if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; 451 hb_barrier (); 452 cff2_font_dict_values_t *font; 453 num_interp_env_t env (fontDictStr); 454 cff2_font_dict_interpreter_t font_interp (env); 455 font = fontDicts.push (); 456 if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail; 457 font->init (); 458 if (unlikely (!font_interp.interpret (*font))) goto fail; 459 460 const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size); 461 if (unlikely (font->privateDictInfo.size && 462 privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; 463 cff2_priv_dict_interp_env_t env2 (privDictStr); 464 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2); 465 privateDicts[i].init (); 466 if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; 467 468 privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc); 469 } 470 471 return; 472 473 fail: 474 _fini (); 475 } 476 ~accelerator_templ_t () { _fini (); } 477 void _fini () 478 { 479 sc.end_processing (); 480 topDict.fini (); 481 fontDicts.fini (); 482 privateDicts.fini (); 483 hb_blob_destroy (blob); 484 blob = nullptr; 485 486 auto *scalars = cached_scalars_vector.get_acquire (); 487 if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr)) 488 { 489 scalars->fini (); 490 hb_free (scalars); 491 } 492 } 493 494 hb_vector_t<uint16_t> *create_glyph_to_sid_map () const 495 { 496 return nullptr; 497 } 498 499 hb_blob_t *get_blob () const { return blob; } 500 501 bool is_valid () const { return blob; } 502 503 protected: 504 hb_sanitize_context_t sc; 505 506 public: 507 hb_blob_t *blob = nullptr; 508 cff2_top_dict_values_t topDict; 509 const CFF2Subrs *globalSubrs = nullptr; 510 const CFF2ItemVariationStore *varStore = nullptr; 511 const CFF2CharStrings *charStrings = nullptr; 512 const CFF2FDArray *fdArray = nullptr; 513 const CFF2FDSelect *fdSelect = nullptr; 514 unsigned int fdCount = 0; 515 516 hb_vector_t<cff2_font_dict_values_t> fontDicts; 517 hb_vector_t<PRIVDICTVAL> privateDicts; 518 519 mutable hb_atomic_t<hb_vector_t<float> *> cached_scalars_vector; 520 521 unsigned int num_glyphs = 0; 522 }; 523 524 struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> 525 { 526 accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {} 527 528 HB_INTERNAL bool get_extents (hb_font_t *font, 529 hb_codepoint_t glyph, 530 hb_glyph_extents_t *extents) const; 531 HB_INTERNAL bool get_extents_at (hb_font_t *font, 532 hb_codepoint_t glyph, 533 hb_glyph_extents_t *extents, 534 hb_array_t<const int> coords) const; 535 HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; 536 HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const; 537 }; 538 539 struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> 540 { 541 accelerator_subset_t (hb_face_t *face) : SUPER (face) {} 542 ~accelerator_subset_t () 543 { 544 if (cff_accelerator) 545 cff_subset_accelerator_t::destroy (cff_accelerator); 546 } 547 548 HB_INTERNAL bool subset (hb_subset_context_t *c) const; 549 HB_INTERNAL bool serialize (hb_serialize_context_t *c, 550 struct cff2_subset_plan &plan, 551 hb_array_t<int> normalized_coords) const; 552 553 mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; 554 555 typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER; 556 }; 557 558 public: 559 FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */ 560 NNOffsetTo<TopDict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */ 561 HBUINT16 topDictSize; /* Top DICT size */ 562 563 public: 564 DEFINE_SIZE_STATIC (5); 565 }; 566 567 struct cff2_accelerator_t : cff2::accelerator_t { 568 cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} 569 }; 570 571 struct cff2_subset_accelerator_t : cff2::accelerator_subset_t { 572 cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {} 573 }; 574 575 } /* namespace OT */ 576 577 #endif /* HB_OT_CFF2_TABLE_HH */