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-open-type.hh" 28 #include "hb-ot-cff2-table.hh" 29 #include "hb-set.h" 30 #include "hb-subset-cff2.hh" 31 #include "hb-subset-plan.hh" 32 #include "hb-subset-cff-common.hh" 33 #include "hb-cff2-interp-cs.hh" 34 35 using namespace CFF; 36 37 struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t 38 { 39 cff2_sub_table_offsets_t () 40 : cff_sub_table_offsets_t (), 41 varStoreOffset (0) 42 {} 43 44 unsigned int varStoreOffset; 45 }; 46 47 struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> 48 { 49 bool serialize (hb_serialize_context_t *c, 50 const op_str_t &opstr, 51 const cff2_sub_table_offsets_t &offsets) const 52 { 53 TRACE_SERIALIZE (this); 54 55 switch (opstr.op) 56 { 57 case OpCode_vstore: 58 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); 59 60 default: 61 return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets)); 62 } 63 } 64 65 unsigned int calculate_serialized_size (const op_str_t &opstr) const 66 { 67 switch (opstr.op) 68 { 69 case OpCode_vstore: 70 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); 71 72 default: 73 return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr); 74 } 75 } 76 }; 77 78 struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> 79 { 80 static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) 81 { 82 switch (op) 83 { 84 case OpCode_return: 85 case OpCode_endchar: 86 /* dummy opcodes in CFF2. ignore */ 87 break; 88 89 case OpCode_hstem: 90 case OpCode_hstemhm: 91 case OpCode_vstem: 92 case OpCode_vstemhm: 93 case OpCode_hintmask: 94 case OpCode_cntrmask: 95 if (param.drop_hints) 96 { 97 env.clear_args (); 98 return; 99 } 100 HB_FALLTHROUGH; 101 102 default: 103 SUPER::flush_args_and_op (op, env, param); 104 break; 105 } 106 } 107 108 static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param) 109 { 110 for (unsigned int i = 0; i < env.argStack.get_count ();) 111 { 112 const blend_arg_t &arg = env.argStack[i]; 113 if (arg.blending ()) 114 { 115 if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues)))) 116 { 117 env.set_error (); 118 return; 119 } 120 flatten_blends (arg, i, env, param); 121 i += arg.numValues; 122 } 123 else 124 { 125 str_encoder_t encoder (param.flatStr); 126 encoder.encode_num (arg); 127 i++; 128 } 129 } 130 SUPER::flush_args (env, param); 131 } 132 133 static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param) 134 { 135 /* flatten the default values */ 136 str_encoder_t encoder (param.flatStr); 137 for (unsigned int j = 0; j < arg.numValues; j++) 138 { 139 const blend_arg_t &arg1 = env.argStack[i + j]; 140 if (unlikely (!((arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) && 141 (arg1.deltas.length == env.get_region_count ()))))) 142 { 143 env.set_error (); 144 return; 145 } 146 encoder.encode_num (arg1); 147 } 148 /* flatten deltas for each value */ 149 for (unsigned int j = 0; j < arg.numValues; j++) 150 { 151 const blend_arg_t &arg1 = env.argStack[i + j]; 152 for (unsigned int k = 0; k < arg1.deltas.length; k++) 153 encoder.encode_num (arg1.deltas[k]); 154 } 155 /* flatten the number of values followed by blend operator */ 156 encoder.encode_int (arg.numValues); 157 encoder.encode_op (OpCode_blendcs); 158 } 159 160 static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) 161 { 162 switch (op) 163 { 164 case OpCode_return: 165 case OpCode_endchar: 166 return; 167 default: 168 str_encoder_t encoder (param.flatStr); 169 encoder.encode_op (op); 170 } 171 } 172 173 private: 174 typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER; 175 typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET; 176 }; 177 178 struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> 179 { 180 static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) 181 { 182 switch (op) { 183 184 case OpCode_return: 185 param.current_parsed_str->set_parsed (); 186 env.returnFromSubr (); 187 param.set_current_str (env, false); 188 break; 189 190 case OpCode_endchar: 191 param.current_parsed_str->set_parsed (); 192 SUPER::process_op (op, env, param); 193 break; 194 195 case OpCode_callsubr: 196 process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure); 197 break; 198 199 case OpCode_callgsubr: 200 process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure); 201 break; 202 203 default: 204 SUPER::process_op (op, env, param); 205 param.current_parsed_str->add_op (op, env.str_ref); 206 break; 207 } 208 } 209 210 protected: 211 static void process_call_subr (op_code_t op, cs_type_t type, 212 cff2_cs_interp_env_t &env, subr_subset_param_t& param, 213 cff2_biased_subrs_t& subrs, hb_set_t *closure) 214 { 215 byte_str_ref_t str_ref = env.str_ref; 216 env.callSubr (subrs, type); 217 param.current_parsed_str->add_call_op (op, str_ref, env.context.subr_num); 218 hb_set_add (closure, env.context.subr_num); 219 param.set_current_str (env, true); 220 } 221 222 private: 223 typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; 224 }; 225 226 struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t> 227 { 228 static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) 229 { 230 /* vsindex is inserted at the beginning of the charstring as necessary */ 231 if (env.seen_vsindex ()) 232 { 233 number_t ivs; 234 ivs.set_int ((int)env.get_ivs ()); 235 charstring.set_prefix (ivs, OpCode_vsindexcs); 236 } 237 } 238 }; 239 240 struct cff2_subset_plan { 241 cff2_subset_plan () 242 : final_size (0), 243 orig_fdcount (0), 244 subset_fdcount(1), 245 subset_fdselect_format (0), 246 drop_hints (false), 247 desubroutinize (false) 248 { 249 subset_fdselect_ranges.init (); 250 fdmap.init (); 251 subset_charstrings.init (); 252 subset_globalsubrs.init (); 253 subset_localsubrs.init (); 254 privateDictInfos.init (); 255 } 256 257 ~cff2_subset_plan () 258 { 259 subset_fdselect_ranges.fini (); 260 fdmap.fini (); 261 subset_charstrings.fini_deep (); 262 subset_globalsubrs.fini_deep (); 263 subset_localsubrs.fini_deep (); 264 privateDictInfos.fini (); 265 } 266 267 bool create (const OT::cff2::accelerator_subset_t &acc, 268 hb_subset_plan_t *plan) 269 { 270 final_size = 0; 271 orig_fdcount = acc.fdArray->count; 272 273 drop_hints = plan->drop_hints; 274 desubroutinize = plan->desubroutinize; 275 276 /* CFF2 header */ 277 final_size += OT::cff2::static_size; 278 279 /* top dict */ 280 { 281 cff2_top_dict_op_serializer_t topSzr; 282 offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr); 283 final_size += offsets.topDictInfo.size; 284 } 285 286 if (desubroutinize) 287 { 288 /* Flatten global & local subrs */ 289 subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t> 290 flattener(acc, plan->glyphs, plan->drop_hints); 291 if (!flattener.flatten (subset_charstrings)) 292 return false; 293 294 /* no global/local subroutines */ 295 offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0); 296 } 297 else 298 { 299 /* Subset subrs: collect used subroutines, leaving all unused ones behind */ 300 if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) 301 return false; 302 303 /* encode charstrings, global subrs, local subrs with new subroutine numbers */ 304 if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) 305 return false; 306 307 if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) 308 return false; 309 310 /* global subrs */ 311 unsigned int dataSize = subset_globalsubrs.total_size (); 312 offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); 313 offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); 314 315 /* local subrs */ 316 if (!offsets.localSubrsInfos.resize (orig_fdcount)) 317 return false; 318 if (!subset_localsubrs.resize (orig_fdcount)) 319 return false; 320 for (unsigned int fd = 0; fd < orig_fdcount; fd++) 321 { 322 subset_localsubrs[fd].init (); 323 offsets.localSubrsInfos[fd].init (); 324 if (fdmap.includes (fd)) 325 { 326 if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) 327 return false; 328 329 unsigned int dataSize = subset_localsubrs[fd].total_size (); 330 if (dataSize > 0) 331 { 332 offsets.localSubrsInfos[fd].offset = final_size; 333 offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); 334 offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); 335 } 336 } 337 } 338 } 339 340 /* global subrs */ 341 offsets.globalSubrsInfo.offset = final_size; 342 final_size += offsets.globalSubrsInfo.size; 343 344 /* variation store */ 345 if (acc.varStore != &Null(CFF2VariationStore)) 346 { 347 offsets.varStoreOffset = final_size; 348 final_size += acc.varStore->get_size (); 349 } 350 351 /* FDSelect */ 352 if (acc.fdSelect != &Null(CFF2FDSelect)) 353 { 354 offsets.FDSelectInfo.offset = final_size; 355 if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, 356 orig_fdcount, 357 *(const FDSelect *)acc.fdSelect, 358 subset_fdcount, 359 offsets.FDSelectInfo.size, 360 subset_fdselect_format, 361 subset_fdselect_ranges, 362 fdmap))) 363 return false; 364 365 final_size += offsets.FDSelectInfo.size; 366 } 367 else 368 fdmap.identity (1); 369 370 /* FDArray (FDIndex) */ 371 { 372 offsets.FDArrayInfo.offset = final_size; 373 cff_font_dict_op_serializer_t fontSzr; 374 unsigned int dictsSize = 0; 375 for (unsigned int i = 0; i < acc.fontDicts.length; i++) 376 if (fdmap.includes (i)) 377 dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); 378 379 offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); 380 final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); 381 } 382 383 /* CharStrings */ 384 { 385 offsets.charStringsInfo.offset = final_size; 386 unsigned int dataSize = subset_charstrings.total_size (); 387 offsets.charStringsInfo.offSize = calcOffSize (dataSize); 388 final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); 389 } 390 391 /* private dicts & local subrs */ 392 offsets.privateDictsOffset = final_size; 393 for (unsigned int i = 0; i < orig_fdcount; i++) 394 { 395 if (fdmap.includes (i)) 396 { 397 bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; 398 cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints); 399 unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); 400 table_info_t privInfo = { final_size, priv_size, 0 }; 401 privateDictInfos.push (privInfo); 402 final_size += privInfo.size; 403 404 if (!plan->desubroutinize && has_localsubrs) 405 { 406 offsets.localSubrsInfos[i].offset = final_size; 407 final_size += offsets.localSubrsInfos[i].size; 408 } 409 } 410 } 411 412 return true; 413 } 414 415 unsigned int get_final_size () const { return final_size; } 416 417 unsigned int final_size; 418 cff2_sub_table_offsets_t offsets; 419 420 unsigned int orig_fdcount; 421 unsigned int subset_fdcount; 422 unsigned int subset_fdselect_format; 423 hb_vector_t<code_pair_t> subset_fdselect_ranges; 424 425 remap_t fdmap; 426 427 str_buff_vec_t subset_charstrings; 428 str_buff_vec_t subset_globalsubrs; 429 hb_vector_t<str_buff_vec_t> subset_localsubrs; 430 hb_vector_t<table_info_t> privateDictInfos; 431 432 bool drop_hints; 433 bool desubroutinize; 434 cff2_subr_subsetter_t subr_subsetter; 435 }; 436 437 static inline bool _write_cff2 (const cff2_subset_plan &plan, 438 const OT::cff2::accelerator_subset_t &acc, 439 const hb_vector_t<hb_codepoint_t>& glyphs, 440 unsigned int dest_sz, 441 void *dest) 442 { 443 hb_serialize_context_t c (dest, dest_sz); 444 445 OT::cff2 *cff2 = c.start_serialize<OT::cff2> (); 446 if (unlikely (!c.extend_min (*cff2))) 447 return false; 448 449 /* header */ 450 cff2->version.major.set (0x02); 451 cff2->version.minor.set (0x00); 452 cff2->topDict.set (OT::cff2::static_size); 453 454 /* top dict */ 455 { 456 assert (cff2->topDict == (unsigned) (c.head - c.start)); 457 cff2->topDictSize.set (plan.offsets.topDictInfo.size); 458 TopDict &dict = cff2 + cff2->topDict; 459 cff2_top_dict_op_serializer_t topSzr; 460 if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets))) 461 { 462 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict"); 463 return false; 464 } 465 } 466 467 /* global subrs */ 468 { 469 assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start)); 470 CFF2Subrs *dest = c.start_embed <CFF2Subrs> (); 471 if (unlikely (dest == nullptr)) return false; 472 if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) 473 { 474 DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); 475 return false; 476 } 477 } 478 479 /* variation store */ 480 if (acc.varStore != &Null(CFF2VariationStore)) 481 { 482 assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start)); 483 CFF2VariationStore *dest = c.start_embed<CFF2VariationStore> (); 484 if (unlikely (!dest->serialize (&c, acc.varStore))) 485 { 486 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store"); 487 return false; 488 } 489 } 490 491 /* FDSelect */ 492 if (acc.fdSelect != &Null(CFF2FDSelect)) 493 { 494 assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); 495 496 if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, 497 plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, 498 plan.subset_fdselect_ranges))) 499 { 500 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); 501 return false; 502 } 503 } 504 505 /* FDArray (FD Index) */ 506 { 507 assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); 508 CFF2FDArray *fda = c.start_embed<CFF2FDArray> (); 509 if (unlikely (fda == nullptr)) return false; 510 cff_font_dict_op_serializer_t fontSzr; 511 if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, 512 acc.fontDicts, plan.subset_fdcount, plan.fdmap, 513 fontSzr, plan.privateDictInfos))) 514 { 515 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray"); 516 return false; 517 } 518 } 519 520 /* CharStrings */ 521 { 522 assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); 523 CFF2CharStrings *cs = c.start_embed<CFF2CharStrings> (); 524 if (unlikely (cs == nullptr)) return false; 525 if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) 526 { 527 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings"); 528 return false; 529 } 530 } 531 532 /* private dicts & local subrs */ 533 assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start)); 534 for (unsigned int i = 0; i < acc.privateDicts.length; i++) 535 { 536 if (plan.fdmap.includes (i)) 537 { 538 PrivateDict *pd = c.start_embed<PrivateDict> (); 539 if (unlikely (pd == nullptr)) return false; 540 unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size; 541 bool result; 542 cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); 543 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ 544 unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; 545 result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); 546 if (unlikely (!result)) 547 { 548 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); 549 return false; 550 } 551 if (plan.offsets.localSubrsInfos[i].size > 0) 552 { 553 CFF2Subrs *dest = c.start_embed <CFF2Subrs> (); 554 if (unlikely (dest == nullptr)) return false; 555 if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) 556 { 557 DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); 558 return false; 559 } 560 } 561 } 562 } 563 564 assert (c.head == c.end); 565 c.end_serialize (); 566 567 return true; 568 } 569 570 static bool 571 _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, 572 const char *data, 573 hb_subset_plan_t *plan, 574 hb_blob_t **prime /* OUT */) 575 { 576 cff2_subset_plan cff2_plan; 577 578 if (unlikely (!cff2_plan.create (acc, plan))) 579 { 580 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan."); 581 return false; 582 } 583 584 unsigned int cff2_prime_size = cff2_plan.get_final_size (); 585 char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); 586 587 if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs, 588 cff2_prime_size, cff2_prime_data))) { 589 DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); 590 free (cff2_prime_data); 591 return false; 592 } 593 594 *prime = hb_blob_create (cff2_prime_data, 595 cff2_prime_size, 596 HB_MEMORY_MODE_READONLY, 597 cff2_prime_data, 598 free); 599 return true; 600 } 601 602 /** 603 * hb_subset_cff2: 604 * Subsets the CFF2 table according to a provided plan. 605 * 606 * Return value: subsetted cff2 table. 607 **/ 608 bool 609 hb_subset_cff2 (hb_subset_plan_t *plan, 610 hb_blob_t **prime /* OUT */) 611 { 612 hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table<CFF::cff2> (plan->source); 613 const char *data = hb_blob_get_data(cff2_blob, nullptr); 614 615 OT::cff2::accelerator_subset_t acc; 616 acc.init(plan->source); 617 bool result = likely (acc.is_valid ()) && 618 _hb_subset_cff2 (acc, data, plan, prime); 619 620 hb_blob_destroy (cff2_blob); 621 acc.fini (); 622 623 return result; 624 }