hb-subset-cff1.cc (28232B)
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 #include "hb.hh" 28 29 #ifndef HB_NO_SUBSET_CFF 30 31 #include "hb-open-type.hh" 32 #include "hb-ot-cff1-table.hh" 33 #include "hb-set.h" 34 #include "hb-bimap.hh" 35 #include "hb-subset-plan.hh" 36 #include "hb-subset-cff-common.hh" 37 #include "hb-cff1-interp-cs.hh" 38 39 using namespace CFF; 40 41 struct remap_sid_t 42 { 43 unsigned get_population () const { return vector.length; } 44 45 void alloc (unsigned size) 46 { 47 map.alloc (size); 48 vector.alloc_exact (size); 49 } 50 51 bool in_error () const 52 { return map.in_error () || vector.in_error (); } 53 54 unsigned int add (unsigned int sid) 55 { 56 if (is_std_str (sid) || (sid == CFF_UNDEF_SID)) 57 return sid; 58 59 sid = unoffset_sid (sid); 60 unsigned v = next; 61 if (map.set (sid, v, false)) 62 { 63 vector.push (sid); 64 next++; 65 } 66 else 67 v = map.get (sid); // already exists 68 return offset_sid (v); 69 } 70 71 unsigned int operator[] (unsigned int sid) const 72 { 73 if (is_std_str (sid) || (sid == CFF_UNDEF_SID)) 74 return sid; 75 76 return offset_sid (map.get (unoffset_sid (sid))); 77 } 78 79 static const unsigned int num_std_strings = 391; 80 81 static bool is_std_str (unsigned int sid) { return sid < num_std_strings; } 82 static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; } 83 static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } 84 unsigned next = 0; 85 86 hb_map_t map; 87 hb_vector_t<unsigned> vector; 88 }; 89 90 struct cff1_sub_table_info_t : cff_sub_table_info_t 91 { 92 cff1_sub_table_info_t () 93 : cff_sub_table_info_t (), 94 encoding_link (0), 95 charset_link (0) 96 { 97 privateDictInfo.init (); 98 } 99 100 objidx_t encoding_link; 101 objidx_t charset_link; 102 table_info_t privateDictInfo; 103 }; 104 105 /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */ 106 struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t 107 { 108 void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t)) 109 { 110 SUPER::init (); 111 base = base_; 112 } 113 114 void fini () { SUPER::fini (); } 115 116 unsigned get_count () const { return base->get_count () + SUPER::get_count (); } 117 const cff1_top_dict_val_t &get_value (unsigned int i) const 118 { 119 if (i < base->get_count ()) 120 return (*base)[i]; 121 else 122 return SUPER::values[i - base->get_count ()]; 123 } 124 const cff1_top_dict_val_t &operator [] (unsigned int i) const { return get_value (i); } 125 126 void reassignSIDs (const remap_sid_t& sidmap) 127 { 128 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) 129 nameSIDs[i] = sidmap[base->nameSIDs[i]]; 130 } 131 132 protected: 133 typedef cff1_top_dict_values_t SUPER; 134 const cff1_top_dict_values_t *base; 135 }; 136 137 struct top_dict_modifiers_t 138 { 139 top_dict_modifiers_t (const cff1_sub_table_info_t &info_, 140 const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) 141 : info (info_), 142 nameSIDs (nameSIDs_) 143 {} 144 145 const cff1_sub_table_info_t &info; 146 const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; 147 }; 148 149 struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dict_val_t> 150 { 151 bool serialize (hb_serialize_context_t *c, 152 const cff1_top_dict_val_t &opstr, 153 const top_dict_modifiers_t &mod) const 154 { 155 TRACE_SERIALIZE (this); 156 157 op_code_t op = opstr.op; 158 switch (op) 159 { 160 case OpCode_charset: 161 if (mod.info.charset_link) 162 return_trace (FontDict::serialize_link4_op(c, op, mod.info.charset_link, whence_t::Absolute)); 163 else 164 goto fall_back; 165 166 case OpCode_Encoding: 167 if (mod.info.encoding_link) 168 return_trace (FontDict::serialize_link4_op(c, op, mod.info.encoding_link, whence_t::Absolute)); 169 else 170 goto fall_back; 171 172 case OpCode_Private: 173 return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) && 174 Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute)); 175 176 case OpCode_version: 177 case OpCode_Notice: 178 case OpCode_Copyright: 179 case OpCode_FullName: 180 case OpCode_FamilyName: 181 case OpCode_Weight: 182 case OpCode_PostScript: 183 case OpCode_BaseFontName: 184 case OpCode_FontName: 185 return_trace (FontDict::serialize_int2_op (c, op, mod.nameSIDs[name_dict_values_t::name_op_to_index (op)])); 186 187 case OpCode_ROS: 188 { 189 /* for registry & ordering, reassigned SIDs are serialized 190 * for supplement, the original byte string is copied along with the op code */ 191 op_str_t supp_op; 192 supp_op.op = op; 193 if ( unlikely (!(opstr.length >= opstr.last_arg_offset + 3))) 194 return_trace (false); 195 supp_op.ptr = opstr.ptr + opstr.last_arg_offset; 196 supp_op.length = opstr.length - opstr.last_arg_offset; 197 return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) && 198 UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && 199 copy_opstr (c, supp_op)); 200 } 201 fall_back: 202 default: 203 return_trace (cff_top_dict_op_serializer_t<cff1_top_dict_val_t>::serialize (c, opstr, mod.info)); 204 } 205 return_trace (true); 206 } 207 208 }; 209 210 struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t 211 { 212 bool serialize (hb_serialize_context_t *c, 213 const op_str_t &opstr, 214 const cff1_font_dict_values_mod_t &mod) const 215 { 216 TRACE_SERIALIZE (this); 217 218 if (opstr.op == OpCode_FontName) 219 return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName)); 220 else 221 return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); 222 } 223 224 private: 225 typedef cff_font_dict_op_serializer_t SUPER; 226 }; 227 228 struct cff1_cs_opset_flatten_t : cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> 229 { 230 static void flush_args_and_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) 231 { 232 if (env.arg_start > 0) 233 flush_width (env, param); 234 235 switch (op) 236 { 237 case OpCode_hstem: 238 case OpCode_hstemhm: 239 case OpCode_vstem: 240 case OpCode_vstemhm: 241 case OpCode_hintmask: 242 case OpCode_cntrmask: 243 case OpCode_dotsection: 244 if (param.drop_hints) 245 { 246 env.clear_args (); 247 return; 248 } 249 HB_FALLTHROUGH; 250 251 default: 252 SUPER::flush_args_and_op (op, env, param); 253 break; 254 } 255 } 256 static void flush_args (cff1_cs_interp_env_t &env, flatten_param_t& param) 257 { 258 str_encoder_t encoder (param.flatStr); 259 for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++) 260 encoder.encode_num_cs (env.eval_arg (i)); 261 SUPER::flush_args (env, param); 262 } 263 264 static void flush_op (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) 265 { 266 str_encoder_t encoder (param.flatStr); 267 encoder.encode_op (op); 268 } 269 270 static void flush_width (cff1_cs_interp_env_t &env, flatten_param_t& param) 271 { 272 assert (env.has_width); 273 str_encoder_t encoder (param.flatStr); 274 encoder.encode_num_cs (env.width); 275 } 276 277 static void flush_hintmask (op_code_t op, cff1_cs_interp_env_t &env, flatten_param_t& param) 278 { 279 SUPER::flush_hintmask (op, env, param); 280 if (!param.drop_hints) 281 { 282 str_encoder_t encoder (param.flatStr); 283 for (unsigned int i = 0; i < env.hintmask_size; i++) 284 encoder.encode_byte (env.str_ref[i]); 285 } 286 } 287 288 private: 289 typedef cff1_cs_opset_t<cff1_cs_opset_flatten_t, flatten_param_t> SUPER; 290 }; 291 292 struct range_list_t : hb_vector_t<code_pair_t> 293 { 294 /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ 295 bool complete (unsigned int last_glyph) 296 { 297 hb_codepoint_t all_glyphs = 0; 298 unsigned count = this->length; 299 for (unsigned int i = count; i; i--) 300 { 301 code_pair_t &pair = arrayZ[i - 1]; 302 unsigned int nLeft = last_glyph - pair.glyph - 1; 303 all_glyphs |= nLeft; 304 last_glyph = pair.glyph; 305 pair.glyph = nLeft; 306 } 307 bool two_byte = all_glyphs >= 0x100; 308 return two_byte; 309 } 310 }; 311 312 struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> 313 { 314 static void process_op (op_code_t op, cff1_cs_interp_env_t &env, subr_subset_param_t& param) 315 { 316 switch (op) { 317 318 case OpCode_return: 319 param.current_parsed_str->add_op (op, env.str_ref); 320 param.current_parsed_str->set_parsed (); 321 env.return_from_subr (); 322 param.set_current_str (env, false); 323 break; 324 325 case OpCode_endchar: 326 param.current_parsed_str->add_op (op, env.str_ref); 327 param.current_parsed_str->set_parsed (); 328 SUPER::process_op (op, env, param); 329 break; 330 331 case OpCode_callsubr: 332 process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure); 333 break; 334 335 case OpCode_callgsubr: 336 process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure); 337 break; 338 339 default: 340 SUPER::process_op (op, env, param); 341 param.current_parsed_str->add_op (op, env.str_ref); 342 break; 343 } 344 } 345 346 protected: 347 static void process_call_subr (op_code_t op, cs_type_t type, 348 cff1_cs_interp_env_t &env, subr_subset_param_t& param, 349 cff1_biased_subrs_t& subrs, hb_set_t *closure) 350 { 351 byte_str_ref_t str_ref = env.str_ref; 352 env.call_subr (subrs, type); 353 param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); 354 closure->add (env.context.subr_num); 355 param.set_current_str (env, true); 356 } 357 358 private: 359 typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; 360 }; 361 362 struct cff1_private_dict_op_serializer_t : op_serializer_t 363 { 364 cff1_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_) 365 : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {} 366 367 bool serialize (hb_serialize_context_t *c, 368 const op_str_t &opstr, 369 objidx_t subrs_link) const 370 { 371 TRACE_SERIALIZE (this); 372 373 if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) 374 return_trace (true); 375 376 if (opstr.op == OpCode_Subrs) 377 { 378 if (desubroutinize || !subrs_link) 379 return_trace (true); 380 else 381 return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link)); 382 } 383 384 return_trace (copy_opstr (c, opstr)); 385 } 386 387 protected: 388 const bool desubroutinize; 389 const bool drop_hints; 390 }; 391 392 struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, OpCode_endchar> 393 { 394 cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) 395 : subr_subsetter_t (acc_, plan_) {} 396 397 static void complete_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) 398 { 399 /* insert width at the beginning of the charstring as necessary */ 400 if (env.has_width) 401 charstring.set_prefix (env.width); 402 403 /* subroutines/charstring left on the call stack are legally left unmarked 404 * unmarked when a subroutine terminates with endchar. mark them. 405 */ 406 param.current_parsed_str->set_parsed (); 407 for (unsigned int i = 0; i < env.callStack.get_count (); i++) 408 { 409 parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); 410 if (likely (parsed_str)) 411 parsed_str->set_parsed (); 412 else 413 env.set_error (); 414 } 415 } 416 }; 417 418 namespace OT { 419 struct cff1_subset_plan 420 { 421 cff1_subset_plan () 422 { 423 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) 424 topDictModSIDs[i] = CFF_UNDEF_SID; 425 } 426 427 void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) 428 { 429 const Encoding *encoding = acc.encoding; 430 unsigned int size0, size1; 431 unsigned code, last_code = CFF_UNDEF_CODE - 1; 432 hb_vector_t<hb_codepoint_t> supp_codes; 433 434 if (unlikely (!subset_enc_code_ranges.resize (0))) 435 { 436 plan->check_success (false); 437 return; 438 } 439 440 supp_codes.init (); 441 442 code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; 443 subset_enc_num_codes = plan->num_output_glyphs () - 1; 444 unsigned int glyph; 445 auto it = hb_iter (plan->new_to_old_gid_list); 446 if (it->first == 0) it++; 447 auto _ = *it; 448 for (glyph = 1; glyph < num_glyphs; glyph++) 449 { 450 hb_codepoint_t old_glyph; 451 if (glyph == _.first) 452 { 453 old_glyph = _.second; 454 _ = *++it; 455 } 456 else 457 { 458 /* Retain the SID for the old missing glyph ID */ 459 old_glyph = glyph; 460 } 461 code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache); 462 if (code == CFF_UNDEF_CODE) 463 { 464 subset_enc_num_codes = glyph - 1; 465 break; 466 } 467 468 if (code != last_code + 1) 469 subset_enc_code_ranges.push (code_pair_t {code, glyph}); 470 last_code = code; 471 472 if (encoding != &Null (Encoding)) 473 { 474 hb_codepoint_t sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); 475 encoding->get_supplement_codes (sid, supp_codes); 476 for (unsigned int i = 0; i < supp_codes.length; i++) 477 subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid}); 478 } 479 } 480 supp_codes.fini (); 481 482 subset_enc_code_ranges.complete (glyph); 483 484 assert (subset_enc_num_codes <= 0xFF); 485 size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes; 486 size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.length; 487 488 if (size0 < size1) 489 subset_enc_format = 0; 490 else 491 subset_enc_format = 1; 492 } 493 494 bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) 495 { 496 unsigned int size0, size_ranges; 497 unsigned last_sid = CFF_UNDEF_CODE - 1; 498 499 if (unlikely (!subset_charset_ranges.resize (0))) 500 { 501 plan->check_success (false); 502 return false; 503 } 504 505 code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID}; 506 507 unsigned num_glyphs = plan->num_output_glyphs (); 508 509 if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs, 510 acc.num_charset_entries)))) 511 { 512 plan->check_success (false); 513 return false; 514 } 515 516 glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ? 517 acc.cff_accelerator->glyph_to_sid_map.get_acquire () : 518 nullptr; 519 bool created_map = false; 520 if (!glyph_to_sid_map && acc.cff_accelerator) 521 { 522 created_map = true; 523 glyph_to_sid_map = acc.create_glyph_to_sid_map (); 524 } 525 526 auto it = hb_iter (plan->new_to_old_gid_list); 527 if (it->first == 0) it++; 528 auto _ = *it; 529 bool not_is_cid = !acc.is_CID (); 530 bool skip = !not_is_cid && glyph_to_sid_map; 531 if (not_is_cid) 532 sidmap.alloc (num_glyphs); 533 for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++) 534 { 535 hb_codepoint_t old_glyph; 536 if (glyph == _.first) 537 { 538 old_glyph = _.second; 539 _ = *++it; 540 } 541 else 542 { 543 /* Retain the SID for the old missing glyph ID */ 544 old_glyph = glyph; 545 } 546 unsigned sid = glyph_to_sid_map ? 547 glyph_to_sid_map->arrayZ[old_glyph].code : 548 acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache); 549 550 if (not_is_cid) 551 sid = sidmap.add (sid); 552 553 if (sid != last_sid + 1) 554 subset_charset_ranges.push (code_pair_t {sid, glyph}); 555 556 if (glyph == old_glyph && skip) 557 { 558 glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph); 559 sid += glyph - old_glyph; 560 } 561 last_sid = sid; 562 } 563 564 if (created_map) 565 { 566 if ((!plan->accelerator && acc.cff_accelerator) || 567 !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map)) 568 { 569 glyph_to_sid_map->~glyph_to_sid_map_t (); 570 hb_free (glyph_to_sid_map); 571 } 572 } 573 574 bool two_byte = subset_charset_ranges.complete (num_glyphs); 575 576 size0 = Charset0::get_size (plan->num_output_glyphs ()); 577 if (!two_byte) 578 size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length); 579 else 580 size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length); 581 582 if (size0 < size_ranges) 583 subset_charset_format = 0; 584 else if (!two_byte) 585 subset_charset_format = 1; 586 else 587 subset_charset_format = 2; 588 589 return true; 590 } 591 592 bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) 593 { 594 for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) 595 { 596 unsigned int sid = acc.topDict.nameSIDs[i]; 597 if (sid != CFF_UNDEF_SID) 598 { 599 topDictModSIDs[i] = sidmap.add (sid); 600 } 601 } 602 603 if (acc.fdArray != &Null (CFF1FDArray)) 604 for (unsigned int i = 0; i < orig_fdcount; i++) 605 if (fdmap.has (i)) 606 (void)sidmap.add (acc.fontDicts[i].fontName); 607 608 return true; 609 } 610 611 bool create (const OT::cff1::accelerator_subset_t &acc, 612 hb_subset_plan_t *plan) 613 { 614 /* make sure notdef is first */ 615 hb_codepoint_t old_glyph; 616 if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; 617 618 num_glyphs = plan->num_output_glyphs (); 619 orig_fdcount = acc.fdCount; 620 drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING; 621 desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE; 622 623 #ifdef HB_EXPERIMENTAL_API 624 min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0; 625 #else 626 min_charstrings_off_size = 0; 627 #endif 628 629 subset_charset = !acc.is_predef_charset (); 630 if (!subset_charset) 631 /* check whether the subset renumbers any glyph IDs */ 632 for (const auto &_ : plan->new_to_old_gid_list) 633 { 634 if (_.first != _.second) 635 { 636 subset_charset = true; 637 break; 638 } 639 } 640 641 subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); 642 643 /* top dict INDEX */ 644 { 645 /* Add encoding/charset to a (copy of) top dict as necessary */ 646 topdict_mod.init (&acc.topDict); 647 bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding)); 648 bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset)); 649 if (need_to_add_enc || need_to_add_set) 650 { 651 if (need_to_add_enc) 652 topdict_mod.add_op (OpCode_Encoding); 653 if (need_to_add_set) 654 topdict_mod.add_op (OpCode_charset); 655 } 656 } 657 658 /* Determine re-mapping of font index as fdmap among other info */ 659 if (acc.fdSelect != &Null (CFF1FDSelect)) 660 { 661 if (unlikely (!hb_plan_subset_cff_fdselect (plan, 662 orig_fdcount, 663 *acc.fdSelect, 664 subset_fdcount, 665 info.fd_select.size, 666 subset_fdselect_format, 667 subset_fdselect_ranges, 668 fdmap))) 669 return false; 670 } 671 else 672 fdmap.identity (1); 673 674 /* remove unused SIDs & reassign SIDs */ 675 { 676 /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */ 677 if (unlikely (!collect_sids_in_dicts (acc))) 678 return false; 679 if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ 680 return false; 681 682 if (subset_charset && !plan_subset_charset (acc, plan)) 683 return false; 684 685 topdict_mod.reassignSIDs (sidmap); 686 } 687 688 if (desubroutinize) 689 { 690 /* Flatten global & local subrs */ 691 subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar> 692 flattener(acc, plan); 693 if (!flattener.flatten (subset_charstrings)) 694 return false; 695 } 696 else 697 { 698 cff1_subr_subsetter_t subr_subsetter (acc, plan); 699 700 /* Subset subrs: collect used subroutines, leaving all unused ones behind */ 701 if (!subr_subsetter.subset ()) 702 return false; 703 704 /* encode charstrings, global subrs, local subrs with new subroutine numbers */ 705 if (!subr_subsetter.encode_charstrings (subset_charstrings)) 706 return false; 707 708 if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) 709 return false; 710 711 /* local subrs */ 712 if (!subset_localsubrs.resize (orig_fdcount)) 713 return false; 714 for (unsigned int fd = 0; fd < orig_fdcount; fd++) 715 { 716 subset_localsubrs[fd].init (); 717 if (fdmap.has (fd)) 718 { 719 if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) 720 return false; 721 } 722 } 723 } 724 725 /* Encoding */ 726 if (subset_encoding) 727 plan_subset_encoding (acc, plan); 728 729 /* private dicts & local subrs */ 730 if (!acc.is_CID ()) 731 fontdicts_mod.push (cff1_font_dict_values_mod_t ()); 732 else 733 { 734 + hb_iter (acc.fontDicts) 735 | hb_filter ([&] (const cff1_font_dict_values_t &_) 736 { return fdmap.has (&_ - &acc.fontDicts[0]); } ) 737 | hb_map ([&] (const cff1_font_dict_values_t &_) 738 { 739 cff1_font_dict_values_mod_t mod; 740 mod.init (&_, sidmap[_.fontName]); 741 return mod; 742 }) 743 | hb_sink (fontdicts_mod) 744 ; 745 } 746 747 return !plan->in_error () && 748 (subset_charstrings.length == plan->num_output_glyphs ()) && 749 (fontdicts_mod.length == subset_fdcount); 750 } 751 752 cff1_top_dict_values_mod_t topdict_mod; 753 cff1_sub_table_info_t info; 754 755 unsigned int num_glyphs; 756 unsigned int orig_fdcount = 0; 757 unsigned int subset_fdcount = 1; 758 unsigned int subset_fdselect_format = 0; 759 hb_vector_t<code_pair_t> subset_fdselect_ranges; 760 761 /* font dict index remap table from fullset FDArray to subset FDArray. 762 * set to CFF_UNDEF_CODE if excluded from subset */ 763 hb_inc_bimap_t fdmap; 764 765 str_buff_vec_t subset_charstrings; 766 str_buff_vec_t subset_globalsubrs; 767 hb_vector_t<str_buff_vec_t> subset_localsubrs; 768 hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod; 769 770 bool drop_hints = false; 771 772 bool gid_renum; 773 bool subset_encoding; 774 uint8_t subset_enc_format; 775 unsigned int subset_enc_num_codes; 776 range_list_t subset_enc_code_ranges; 777 hb_vector_t<code_pair_t> subset_enc_supp_codes; 778 779 uint8_t subset_charset_format; 780 range_list_t subset_charset_ranges; 781 bool subset_charset; 782 783 remap_sid_t sidmap; 784 unsigned int topDictModSIDs[name_dict_values_t::ValCount]; 785 786 bool desubroutinize = false; 787 788 unsigned min_charstrings_off_size = 0; 789 }; 790 } // namespace OT 791 792 static bool _serialize_cff1_charstrings (hb_serialize_context_t *c, 793 struct OT::cff1_subset_plan &plan, 794 const OT::cff1::accelerator_subset_t &acc) 795 { 796 c->push<CFF1CharStrings> (); 797 798 unsigned data_size = 0; 799 unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size); 800 if (unlikely (!c->start_zerocopy (total_size))) 801 return false; 802 803 auto *cs = c->start_embed<CFF1CharStrings> (); 804 if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size))) { 805 c->pop_discard (); 806 return false; 807 } 808 809 plan.info.char_strings_link = c->pop_pack (false); 810 return true; 811 } 812 813 bool 814 OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c, 815 struct OT::cff1_subset_plan &plan) const 816 { 817 /* push charstrings onto the object stack first which will ensure it packs as the last 818 object in the table. Keeping the chastrings last satisfies the requirements for patching 819 via IFTB. If this ordering needs to be changed in the future, charstrings should be left 820 at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */ 821 if (!_serialize_cff1_charstrings(c, plan, *this)) 822 return false; 823 824 /* private dicts & local subrs */ 825 for (int i = (int) privateDicts.length; --i >= 0 ;) 826 { 827 if (plan.fdmap.has (i)) 828 { 829 objidx_t subrs_link = 0; 830 if (plan.subset_localsubrs[i].length > 0) 831 { 832 auto *dest = c->push <CFF1Subrs> (); 833 if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) 834 subrs_link = c->pop_pack (); 835 else 836 { 837 c->pop_discard (); 838 return false; 839 } 840 } 841 842 auto *pd = c->push<PrivateDict> (); 843 cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); 844 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ 845 if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link))) 846 { 847 unsigned fd = plan.fdmap[i]; 848 plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); 849 plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack (); 850 } 851 else 852 { 853 c->pop_discard (); 854 return false; 855 } 856 } 857 } 858 859 if (!is_CID ()) 860 plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; 861 862 /* FDArray (FD Index) */ 863 if (fdArray != &Null (CFF1FDArray)) 864 { 865 auto *fda = c->push<CFF1FDArray> (); 866 cff1_font_dict_op_serializer_t fontSzr; 867 auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); 868 if (likely (fda->serialize (c, it, fontSzr))) 869 plan.info.fd_array_link = c->pop_pack (false); 870 else 871 { 872 c->pop_discard (); 873 return false; 874 } 875 } 876 877 /* FDSelect */ 878 if (fdSelect != &Null (CFF1FDSelect)) 879 { 880 c->push (); 881 if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount, 882 plan.subset_fdselect_format, plan.info.fd_select.size, 883 plan.subset_fdselect_ranges))) 884 plan.info.fd_select.link = c->pop_pack (); 885 else 886 { 887 c->pop_discard (); 888 return false; 889 } 890 } 891 892 /* Charset */ 893 if (plan.subset_charset) 894 { 895 auto *dest = c->push<Charset> (); 896 if (likely (dest->serialize (c, 897 plan.subset_charset_format, 898 plan.num_glyphs, 899 plan.subset_charset_ranges))) 900 plan.info.charset_link = c->pop_pack (); 901 else 902 { 903 c->pop_discard (); 904 return false; 905 } 906 } 907 908 /* Encoding */ 909 if (plan.subset_encoding) 910 { 911 auto *dest = c->push<Encoding> (); 912 if (likely (dest->serialize (c, 913 plan.subset_enc_format, 914 plan.subset_enc_num_codes, 915 plan.subset_enc_code_ranges, 916 plan.subset_enc_supp_codes))) 917 plan.info.encoding_link = c->pop_pack (); 918 else 919 { 920 c->pop_discard (); 921 return false; 922 } 923 } 924 925 /* global subrs */ 926 { 927 auto *dest = c->push <CFF1Subrs> (); 928 if (likely (dest->serialize (c, plan.subset_globalsubrs))) 929 c->pop_pack (false); 930 else 931 { 932 c->pop_discard (); 933 return false; 934 } 935 } 936 937 /* String INDEX */ 938 { 939 auto *dest = c->push<CFF1StringIndex> (); 940 if (likely (!plan.sidmap.in_error () && 941 dest->serialize (c, *stringIndex, plan.sidmap.vector))) 942 c->pop_pack (); 943 else 944 { 945 c->pop_discard (); 946 return false; 947 } 948 } 949 950 OT::cff1 *cff = c->allocate_min<OT::cff1> (); 951 if (unlikely (!cff)) 952 return false; 953 954 /* header */ 955 cff->version.major = 0x01; 956 cff->version.minor = 0x00; 957 cff->nameIndex = cff->min_size; 958 cff->offSize = 4; /* unused? */ 959 960 /* name INDEX */ 961 if (unlikely (!c->embed (*nameIndex))) return false; 962 963 /* top dict INDEX */ 964 { 965 /* serialize singleton TopDict */ 966 auto *top = c->push<TopDict> (); 967 cff1_top_dict_op_serializer_t topSzr; 968 unsigned top_size = 0; 969 top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); 970 if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier))) 971 { 972 top_size = c->length (); 973 c->pop_pack (false); 974 } 975 else 976 { 977 c->pop_discard (); 978 return false; 979 } 980 /* serialize INDEX header for above */ 981 auto *dest = c->start_embed<CFF1Index> (); 982 return dest->serialize_header (c, hb_iter (&top_size, 1), top_size); 983 } 984 } 985 986 bool 987 OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const 988 { 989 cff1_subset_plan cff_plan; 990 991 if (unlikely (!cff_plan.create (*this, c->plan))) 992 { 993 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); 994 return false; 995 } 996 997 return serialize (c->serializer, cff_plan); 998 } 999 1000 1001 #endif