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 { serializeCFF::CFF2FDSelect51 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 get_sizeCFF::CFF2FDSelect61 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 get_fdCFF::CFF2FDSelect72 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 sanitizeCFF::CFF2FDSelect86 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 { sanitizeCFF::CFF2ItemVariationStore114 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 serializeCFF::CFF2ItemVariationStore123 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 get_sizeCFF::CFF2ItemVariationStore133 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 { initCFF::cff2_top_dict_values_t143 void init () 144 { 145 top_dict_values_t<>::init (); 146 vstoreOffset = 0; 147 FDSelectOffset = 0; 148 } finiCFF::cff2_top_dict_values_t149 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 { process_opCFF::cff2_top_dict_opset_t157 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 { initCFF::cff2_font_dict_values_t194 void init () 195 { 196 dict_values_t<op_str_t>::init (); 197 privateDictInfo.init (); 198 } finiCFF::cff2_font_dict_values_t199 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 { process_opCFF::cff2_font_dict_opset_t206 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 { initCFF::cff2_private_dict_values_base_t233 void init () 234 { 235 dict_values_t<VAL>::init (); 236 subrsOffset = 0; 237 localSubrs = &Null (CFF2Subrs); 238 ivs = 0; 239 } finiCFF::cff2_private_dict_values_base_t240 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 { cff2_priv_dict_interp_env_tCFF::cff2_priv_dict_interp_env_t252 cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) : 253 num_interp_env_t (str) {} 254 process_vsindexCFF::cff2_priv_dict_interp_env_t255 void process_vsindex () 256 { 257 if (likely (!seen_vsindex)) 258 { 259 set_ivs (argStack.pop_uint ()); 260 } 261 seen_vsindex = true; 262 } 263 get_ivsCFF::cff2_priv_dict_interp_env_t264 unsigned int get_ivs () const { return ivs; } set_ivsCFF::cff2_priv_dict_interp_env_t265 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 { process_opCFF::cff2_private_dict_opset_t274 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 { process_opCFF::cff2_private_dict_opset_subset_t321 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> serializeCFF::CFF2FDArray371 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 sanitizeOT::cff2385 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 accelerator_templ_tOT::cff2::accelerator_templ_t398 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 santization */ 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 (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail; 462 cff2_priv_dict_interp_env_t env2 (privDictStr); 463 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2); 464 privateDicts[i].init (); 465 if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; 466 467 privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc); 468 } 469 470 return; 471 472 fail: 473 _fini (); 474 } ~accelerator_templ_tOT::cff2::accelerator_templ_t475 ~accelerator_templ_t () { _fini (); } _finiOT::cff2::accelerator_templ_t476 void _fini () 477 { 478 sc.end_processing (); 479 topDict.fini (); 480 fontDicts.fini (); 481 privateDicts.fini (); 482 hb_blob_destroy (blob); 483 blob = nullptr; 484 } 485 create_glyph_to_sid_mapOT::cff2::accelerator_templ_t486 hb_vector_t<uint16_t> *create_glyph_to_sid_map () const 487 { 488 return nullptr; 489 } 490 get_blobOT::cff2::accelerator_templ_t491 hb_blob_t *get_blob () const { return blob; } 492 is_validOT::cff2::accelerator_templ_t493 bool is_valid () const { return blob; } 494 495 protected: 496 hb_sanitize_context_t sc; 497 498 public: 499 hb_blob_t *blob = nullptr; 500 cff2_top_dict_values_t topDict; 501 const CFF2Subrs *globalSubrs = nullptr; 502 const CFF2ItemVariationStore *varStore = nullptr; 503 const CFF2CharStrings *charStrings = nullptr; 504 const CFF2FDArray *fdArray = nullptr; 505 const CFF2FDSelect *fdSelect = nullptr; 506 unsigned int fdCount = 0; 507 508 hb_vector_t<cff2_font_dict_values_t> fontDicts; 509 hb_vector_t<PRIVDICTVAL> privateDicts; 510 511 unsigned int num_glyphs = 0; 512 }; 513 514 struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> 515 { accelerator_tOT::cff2::accelerator_t516 accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {} 517 518 HB_INTERNAL bool get_extents (hb_font_t *font, 519 hb_codepoint_t glyph, 520 hb_glyph_extents_t *extents) const; 521 HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; 522 HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; 523 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; 524 }; 525 526 struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> 527 { accelerator_subset_tOT::cff2::accelerator_subset_t528 accelerator_subset_t (hb_face_t *face) : SUPER (face) {} ~accelerator_subset_tOT::cff2::accelerator_subset_t529 ~accelerator_subset_t () 530 { 531 if (cff_accelerator) 532 cff_subset_accelerator_t::destroy (cff_accelerator); 533 } 534 535 HB_INTERNAL bool subset (hb_subset_context_t *c) const; 536 HB_INTERNAL bool serialize (hb_serialize_context_t *c, 537 struct cff2_subset_plan &plan, 538 hb_array_t<int> normalized_coords) const; 539 540 mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr; 541 542 typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER; 543 }; 544 545 public: 546 FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */ 547 NNOffsetTo<TopDict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */ 548 HBUINT16 topDictSize; /* Top DICT size */ 549 550 public: 551 DEFINE_SIZE_STATIC (5); 552 }; 553 554 struct cff2_accelerator_t : cff2::accelerator_t { cff2_accelerator_tOT::cff2_accelerator_t555 cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} 556 }; 557 558 struct cff2_subset_accelerator_t : cff2::accelerator_subset_t { cff2_subset_accelerator_tOT::cff2_subset_accelerator_t559 cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {} 560 }; 561 562 } /* namespace OT */ 563 564 #endif /* HB_OT_CFF2_TABLE_HH */ 565