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_SUBSET_CFF_COMMON_HH
  28 #define HB_SUBSET_CFF_COMMON_HH
  29 
  30 #include "hb.hh"
  31 
  32 #include "hb-subset-plan.hh"
  33 #include "hb-cff-interp-cs-common.hh"
  34 
  35 namespace CFF {
  36 
  37 /* Used for writing a temporary charstring */
  38 struct str_encoder_t
  39 {
  40   str_encoder_t (str_buff_t &buff_)
  41     : buff (buff_), error (false) {}
  42 
  43   void reset () { buff.resize (0); }
  44 
  45   void encode_byte (unsigned char b)
  46   {
  47     if (unlikely (buff.push (b) == &Crap(unsigned char)))
  48       set_error ();
  49   }
  50 
  51   void encode_int (int v)
  52   {
  53     if ((-1131 <= v) && (v <= 1131))
  54     {
  55       if ((-107 <= v) && (v <= 107))
  56         encode_byte (v + 139);
  57       else if (v > 0)
  58       {
  59         v -= 108;
  60         encode_byte ((v >> 8) + OpCode_TwoBytePosInt0);
  61         encode_byte (v & 0xFF);
  62       }
  63       else
  64       {
  65         v = -v - 108;
  66         encode_byte ((v >> 8) + OpCode_TwoByteNegInt0);
  67         encode_byte (v & 0xFF);
  68       }
  69     }
  70     else
  71     {
  72       if (unlikely (v < -32768))
  73         v = -32768;
  74       else if (unlikely (v > 32767))
  75         v = 32767;
  76       encode_byte (OpCode_shortint);
  77       encode_byte ((v >> 8) & 0xFF);
  78       encode_byte (v & 0xFF);
  79     }
  80   }
  81 
  82   void encode_num (const number_t& n)
  83   {
  84     if (n.in_int_range ())
  85     {
  86       encode_int (n.to_int ());
  87     }
  88     else
  89     {
  90       int32_t v = n.to_fixed ();
  91       encode_byte (OpCode_fixedcs);
  92       encode_byte ((v >> 24) & 0xFF);
  93       encode_byte ((v >> 16) & 0xFF);
  94       encode_byte ((v >> 8) & 0xFF);
  95       encode_byte (v & 0xFF);
  96     }
  97   }
  98 
  99   void encode_op (op_code_t op)
 100   {
 101     if (Is_OpCode_ESC (op))
 102     {
 103       encode_byte (OpCode_escape);
 104       encode_byte (Unmake_OpCode_ESC (op));
 105     }
 106     else
 107       encode_byte (op);
 108   }
 109 
 110   void copy_str (const byte_str_t &str)
 111   {
 112     unsigned int  offset = buff.length;
 113     buff.resize (offset + str.length);
 114     if (unlikely (buff.length < offset + str.length))
 115     {
 116       set_error ();
 117       return;
 118     }
 119     memcpy (&buff[offset], &str[0], str.length);
 120   }
 121 
 122   bool is_error () const { return error; }
 123 
 124   protected:
 125   void set_error () { error = true; }
 126 
 127   str_buff_t &buff;
 128   bool    error;
 129 };
 130 
 131 struct cff_sub_table_offsets_t {
 132   cff_sub_table_offsets_t () : privateDictsOffset (0)
 133   {
 134     topDictInfo.init ();
 135     FDSelectInfo.init ();
 136     FDArrayInfo.init ();
 137     charStringsInfo.init ();
 138     globalSubrsInfo.init ();
 139     localSubrsInfos.init ();
 140   }
 141 
 142   ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); }
 143 
 144   table_info_t     topDictInfo;
 145   table_info_t     FDSelectInfo;
 146   table_info_t     FDArrayInfo;
 147   table_info_t     charStringsInfo;
 148   unsigned int  privateDictsOffset;
 149   table_info_t     globalSubrsInfo;
 150   hb_vector_t<table_info_t>  localSubrsInfos;
 151 };
 152 
 153 template <typename OPSTR=op_str_t>
 154 struct cff_top_dict_op_serializer_t : op_serializer_t
 155 {
 156   bool serialize (hb_serialize_context_t *c,
 157                   const OPSTR &opstr,
 158                   const cff_sub_table_offsets_t &offsets) const
 159   {
 160     TRACE_SERIALIZE (this);
 161 
 162     switch (opstr.op)
 163     {
 164       case OpCode_CharStrings:
 165         return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
 166 
 167       case OpCode_FDArray:
 168         return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
 169 
 170       case OpCode_FDSelect:
 171         return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
 172 
 173       default:
 174         return_trace (copy_opstr (c, opstr));
 175     }
 176     return_trace (true);
 177   }
 178 
 179   unsigned int calculate_serialized_size (const OPSTR &opstr) const
 180   {
 181     switch (opstr.op)
 182     {
 183       case OpCode_CharStrings:
 184       case OpCode_FDArray:
 185       case OpCode_FDSelect:
 186         return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
 187 
 188       default:
 189         return opstr.str.length;
 190     }
 191   }
 192 };
 193 
 194 struct cff_font_dict_op_serializer_t : op_serializer_t
 195 {
 196   bool serialize (hb_serialize_context_t *c,
 197                   const op_str_t &opstr,
 198                   const table_info_t &privateDictInfo) const
 199   {
 200     TRACE_SERIALIZE (this);
 201 
 202     if (opstr.op == OpCode_Private)
 203     {
 204       /* serialize the private dict size & offset as 2-byte & 4-byte integers */
 205       if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) ||
 206                     !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
 207         return_trace (false);
 208 
 209       /* serialize the opcode */
 210       HBUINT8 *p = c->allocate_size<HBUINT8> (1);
 211       if (unlikely (p == nullptr)) return_trace (false);
 212       p->set (OpCode_Private);
 213 
 214       return_trace (true);
 215     }
 216     else
 217     {
 218       HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
 219       if (unlikely (d == nullptr)) return_trace (false);
 220       memcpy (d, &opstr.str[0], opstr.str.length);
 221     }
 222     return_trace (true);
 223   }
 224 
 225   unsigned int calculate_serialized_size (const op_str_t &opstr) const
 226   {
 227     if (opstr.op == OpCode_Private)
 228       return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
 229     else
 230       return opstr.str.length;
 231   }
 232 };
 233 
 234 struct cff_private_dict_op_serializer_t : op_serializer_t
 235 {
 236   cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
 237     : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
 238 
 239   bool serialize (hb_serialize_context_t *c,
 240                   const op_str_t &opstr,
 241                   const unsigned int subrsOffset) const
 242   {
 243     TRACE_SERIALIZE (this);
 244 
 245     if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
 246       return true;
 247     if (opstr.op == OpCode_Subrs)
 248     {
 249       if (desubroutinize || (subrsOffset == 0))
 250         return_trace (true);
 251       else
 252         return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset));
 253     }
 254     else
 255       return_trace (copy_opstr (c, opstr));
 256   }
 257 
 258   unsigned int calculate_serialized_size (const op_str_t &opstr,
 259                                           bool has_localsubr=true) const
 260   {
 261     if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
 262       return 0;
 263     if (opstr.op == OpCode_Subrs)
 264     {
 265       if (desubroutinize || !has_localsubr)
 266         return 0;
 267       else
 268         return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op);
 269     }
 270     else
 271       return opstr.str.length;
 272   }
 273 
 274   protected:
 275   const bool  desubroutinize;
 276   const bool  drop_hints;
 277 };
 278 
 279 struct flatten_param_t
 280 {
 281   str_buff_t     &flatStr;
 282   bool  drop_hints;
 283 };
 284 
 285 template <typename ACC, typename ENV, typename OPSET>
 286 struct subr_flattener_t
 287 {
 288   subr_flattener_t (const ACC &acc_,
 289                     const hb_vector_t<hb_codepoint_t> &glyphs_,
 290                     bool drop_hints_) : acc (acc_), glyphs (glyphs_),
 291                                         drop_hints (drop_hints_) {}
 292 
 293   bool flatten (str_buff_vec_t &flat_charstrings)
 294   {
 295     if (!flat_charstrings.resize (glyphs.length))
 296       return false;
 297     for (unsigned int i = 0; i < glyphs.length; i++)
 298       flat_charstrings[i].init ();
 299     for (unsigned int i = 0; i < glyphs.length; i++)
 300     {
 301       hb_codepoint_t  glyph = glyphs[i];
 302       const byte_str_t str = (*acc.charStrings)[glyph];
 303       unsigned int fd = acc.fdSelect->get_fd (glyph);
 304       if (unlikely (fd >= acc.fdCount))
 305         return false;
 306       cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
 307       interp.env.init (str, acc, fd);
 308       flatten_param_t  param = { flat_charstrings[i], drop_hints };
 309       if (unlikely (!interp.interpret (param)))
 310         return false;
 311     }
 312     return true;
 313   }
 314 
 315   const ACC &acc;
 316   const hb_vector_t<hb_codepoint_t> &glyphs;
 317   bool  drop_hints;
 318 };
 319 
 320 struct subr_closures_t
 321 {
 322   subr_closures_t () : valid (false), global_closure (nullptr)
 323   { local_closures.init (); }
 324 
 325   void init (unsigned int fd_count)
 326   {
 327     valid = true;
 328     global_closure = hb_set_create ();
 329     if (global_closure == hb_set_get_empty ())
 330       valid = false;
 331     if (!local_closures.resize (fd_count))
 332       valid = false;
 333 
 334     for (unsigned int i = 0; i < local_closures.length; i++)
 335     {
 336       local_closures[i] = hb_set_create ();
 337       if (local_closures[i] == hb_set_get_empty ())
 338         valid = false;
 339     }
 340   }
 341 
 342   void fini ()
 343   {
 344     hb_set_destroy (global_closure);
 345     for (unsigned int i = 0; i < local_closures.length; i++)
 346       hb_set_destroy (local_closures[i]);
 347     local_closures.fini ();
 348   }
 349 
 350   void reset ()
 351   {
 352     hb_set_clear (global_closure);
 353     for (unsigned int i = 0; i < local_closures.length; i++)
 354       hb_set_clear (local_closures[i]);
 355   }
 356 
 357   bool is_valid () const { return valid; }
 358   bool  valid;
 359   hb_set_t  *global_closure;
 360   hb_vector_t<hb_set_t *> local_closures;
 361 };
 362 
 363 struct parsed_cs_op_t : op_str_t
 364 {
 365   void init (unsigned int subr_num_ = 0)
 366   {
 367     op_str_t::init ();
 368     subr_num = subr_num_;
 369     drop_flag = false;
 370     keep_flag = false;
 371     skip_flag = false;
 372   }
 373 
 374   void fini () { op_str_t::fini (); }
 375 
 376   bool for_drop () const { return drop_flag; }
 377   void set_drop ()       { if (!for_keep ()) drop_flag = true; }
 378 
 379   bool for_keep () const { return keep_flag; }
 380   void set_keep ()       { keep_flag = true; }
 381 
 382   bool for_skip () const { return skip_flag; }
 383   void set_skip ()       { skip_flag = true; }
 384 
 385   unsigned int  subr_num;
 386 
 387   protected:
 388   bool    drop_flag : 1;
 389   bool    keep_flag : 1;
 390   bool    skip_flag : 1;
 391 };
 392 
 393 struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
 394 {
 395   void init ()
 396   {
 397     SUPER::init ();
 398     parsed = false;
 399     hint_dropped = false;
 400     has_prefix_ = false;
 401   }
 402 
 403   void add_op (op_code_t op, const byte_str_ref_t& str_ref)
 404   {
 405     if (!is_parsed ())
 406       SUPER::add_op (op, str_ref);
 407   }
 408 
 409   void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num)
 410   {
 411     if (!is_parsed ())
 412     {
 413       unsigned int parsed_len = get_count ();
 414       if (likely (parsed_len > 0))
 415         values[parsed_len-1].set_skip ();
 416 
 417       parsed_cs_op_t val;
 418       val.init (subr_num);
 419       SUPER::add_op (op, str_ref, val);
 420     }
 421   }
 422 
 423   void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid)
 424   {
 425     has_prefix_ = true;
 426     prefix_op_ = op;
 427     prefix_num_ = num;
 428   }
 429 
 430   bool at_end (unsigned int pos) const
 431   {
 432     return ((pos + 1 >= values.length) /* CFF2 */
 433         || (values[pos + 1].op == OpCode_return));
 434   }
 435 
 436   bool is_parsed () const { return parsed; }
 437   void set_parsed ()      { parsed = true; }
 438 
 439   bool is_hint_dropped () const { return hint_dropped; }
 440   void set_hint_dropped ()      { hint_dropped = true; }
 441 
 442   bool is_vsindex_dropped () const { return vsindex_dropped; }
 443   void set_vsindex_dropped ()      { vsindex_dropped = true; }
 444 
 445   bool has_prefix () const          { return has_prefix_; }
 446   op_code_t prefix_op () const         { return prefix_op_; }
 447   const number_t &prefix_num () const { return prefix_num_; }
 448 
 449   protected:
 450   bool    parsed;
 451   bool    hint_dropped;
 452   bool    vsindex_dropped;
 453   bool    has_prefix_;
 454   op_code_t     prefix_op_;
 455   number_t      prefix_num_;
 456 
 457   private:
 458   typedef parsed_values_t<parsed_cs_op_t> SUPER;
 459 };
 460 
 461 struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
 462 {
 463   void init (unsigned int len_ = 0)
 464   {
 465     SUPER::init ();
 466     resize (len_);
 467     for (unsigned int i = 0; i < length; i++)
 468       (*this)[i].init ();
 469   }
 470   void fini () { SUPER::fini_deep (); }
 471 
 472   private:
 473   typedef hb_vector_t<parsed_cs_str_t> SUPER;
 474 };
 475 
 476 struct subr_subset_param_t
 477 {
 478   void init (parsed_cs_str_t *parsed_charstring_,
 479              parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_,
 480              hb_set_t *global_closure_, hb_set_t *local_closure_,
 481              bool drop_hints_)
 482   {
 483     parsed_charstring = parsed_charstring_;
 484     current_parsed_str = parsed_charstring;
 485     parsed_global_subrs = parsed_global_subrs_;
 486     parsed_local_subrs = parsed_local_subrs_;
 487     global_closure = global_closure_;
 488     local_closure = local_closure_;
 489     drop_hints = drop_hints_;
 490   }
 491 
 492   parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context)
 493   {
 494     switch (context.type)
 495     {
 496       case CSType_CharString:
 497         return parsed_charstring;
 498 
 499       case CSType_LocalSubr:
 500         if (likely (context.subr_num < parsed_local_subrs->length))
 501           return &(*parsed_local_subrs)[context.subr_num];
 502         break;
 503 
 504       case CSType_GlobalSubr:
 505         if (likely (context.subr_num < parsed_global_subrs->length))
 506           return &(*parsed_global_subrs)[context.subr_num];
 507         break;
 508     }
 509     return nullptr;
 510   }
 511 
 512   template <typename ENV>
 513   void set_current_str (ENV &env, bool calling)
 514   {
 515     parsed_cs_str_t  *parsed_str = get_parsed_str_for_context (env.context);
 516     if (likely (parsed_str != nullptr))
 517     {
 518       /* If the called subroutine is parsed partially but not completely yet,
 519        * it must be because we are calling it recursively.
 520        * Handle it as an error. */
 521       if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
 522         env.set_error ();
 523       else
 524         current_parsed_str = parsed_str;
 525     }
 526     else
 527       env.set_error ();
 528   }
 529 
 530   parsed_cs_str_t       *current_parsed_str;
 531 
 532   parsed_cs_str_t       *parsed_charstring;
 533   parsed_cs_str_vec_t   *parsed_global_subrs;
 534   parsed_cs_str_vec_t   *parsed_local_subrs;
 535   hb_set_t      *global_closure;
 536   hb_set_t      *local_closure;
 537   bool    drop_hints;
 538 };
 539 
 540 struct subr_remap_t : remap_t
 541 {
 542   void create (hb_set_t *closure)
 543   {
 544     /* create a remapping of subroutine numbers from old to new.
 545      * no optimization based on usage counts. fonttools doesn't appear doing that either.
 546      */
 547     reset (closure->get_max () + 1);
 548     for (hb_codepoint_t old_num = 0; old_num < length; old_num++)
 549     {
 550       if (hb_set_has (closure, old_num))
 551         add (old_num);
 552     }
 553 
 554     if (get_count () < 1240)
 555       bias = 107;
 556     else if (get_count () < 33900)
 557       bias = 1131;
 558     else
 559       bias = 32768;
 560   }
 561 
 562   hb_codepoint_t operator[] (unsigned int old_num) const
 563   {
 564     if (old_num >= length)
 565       return CFF_UNDEF_CODE;
 566     else
 567       return remap_t::operator[] (old_num);
 568   }
 569 
 570   int biased_num (unsigned int old_num) const
 571   {
 572     hb_codepoint_t new_num = (*this)[old_num];
 573     return (int)new_num - bias;
 574   }
 575 
 576   protected:
 577   int bias;
 578 };
 579 
 580 struct subr_remap_ts
 581 {
 582   subr_remap_ts ()
 583   {
 584     global_remap.init ();
 585     local_remaps.init ();
 586   }
 587 
 588   ~subr_remap_ts () { fini (); }
 589 
 590   void init (unsigned int fdCount)
 591   {
 592     local_remaps.resize (fdCount);
 593     for (unsigned int i = 0; i < fdCount; i++)
 594       local_remaps[i].init ();
 595   }
 596 
 597   void create (subr_closures_t& closures)
 598   {
 599     global_remap.create (closures.global_closure);
 600     for (unsigned int i = 0; i < local_remaps.length; i++)
 601       local_remaps[i].create (closures.local_closures[i]);
 602   }
 603 
 604   void fini ()
 605   {
 606     global_remap.fini ();
 607     local_remaps.fini_deep ();
 608   }
 609 
 610   subr_remap_t         global_remap;
 611   hb_vector_t<subr_remap_t>  local_remaps;
 612 };
 613 
 614 template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET>
 615 struct subr_subsetter_t
 616 {
 617   subr_subsetter_t ()
 618   {
 619     parsed_charstrings.init ();
 620     parsed_global_subrs.init ();
 621     parsed_local_subrs.init ();
 622   }
 623 
 624   ~subr_subsetter_t ()
 625   {
 626     closures.fini ();
 627     remaps.fini ();
 628     parsed_charstrings.fini_deep ();
 629     parsed_global_subrs.fini_deep ();
 630     parsed_local_subrs.fini_deep ();
 631   }
 632 
 633   /* Subroutine subsetting with --no-desubroutinize runs in phases:
 634    *
 635    * 1. execute charstrings/subroutines to determine subroutine closures
 636    * 2. parse out all operators and numbers
 637    * 3. mark hint operators and operands for removal if --no-hinting
 638    * 4. re-encode all charstrings and subroutines with new subroutine numbers
 639    *
 640    * Phases #1 and #2 are done at the same time in collect_subrs ().
 641    * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required),
 642    * because we can't tell if a number belongs to a hint op until we see the first moveto.
 643    *
 644    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
 645    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
 646    */
 647   bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints)
 648   {
 649     closures.init (acc.fdCount);
 650     remaps.init (acc.fdCount);
 651 
 652     parsed_charstrings.init (glyphs.length);
 653     parsed_global_subrs.init (acc.globalSubrs->count);
 654     parsed_local_subrs.resize (acc.fdCount);
 655     for (unsigned int i = 0; i < acc.fdCount; i++)
 656     {
 657       parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
 658     }
 659     if (unlikely (!closures.valid))
 660       return false;
 661 
 662     /* phase 1 & 2 */
 663     for (unsigned int i = 0; i < glyphs.length; i++)
 664     {
 665       hb_codepoint_t  glyph = glyphs[i];
 666       const byte_str_t str = (*acc.charStrings)[glyph];
 667       unsigned int fd = acc.fdSelect->get_fd (glyph);
 668       if (unlikely (fd >= acc.fdCount))
 669         return false;
 670 
 671       cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
 672       interp.env.init (str, acc, fd);
 673 
 674       subr_subset_param_t  param;
 675       param.init (&parsed_charstrings[i],
 676                   &parsed_global_subrs,  &parsed_local_subrs[fd],
 677                   closures.global_closure, closures.local_closures[fd],
 678                   drop_hints);
 679 
 680       if (unlikely (!interp.interpret (param)))
 681         return false;
 682 
 683       /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
 684       SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]);
 685     }
 686 
 687     if (drop_hints)
 688     {
 689       /* mark hint ops and arguments for drop */
 690       for (unsigned int i = 0; i < glyphs.length; i++)
 691       {
 692         unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
 693         if (unlikely (fd >= acc.fdCount))
 694           return false;
 695         subr_subset_param_t  param;
 696         param.init (&parsed_charstrings[i],
 697                     &parsed_global_subrs,  &parsed_local_subrs[fd],
 698                     closures.global_closure, closures.local_closures[fd],
 699                     drop_hints);
 700 
 701         drop_hints_param_t  drop;
 702         if (drop_hints_in_str (parsed_charstrings[i], param, drop))
 703         {
 704           parsed_charstrings[i].set_hint_dropped ();
 705           if (drop.vsindex_dropped)
 706             parsed_charstrings[i].set_vsindex_dropped ();
 707         }
 708       }
 709 
 710       /* after dropping hints recreate closures of actually used subrs */
 711       closures.reset ();
 712       for (unsigned int i = 0; i < glyphs.length; i++)
 713       {
 714         unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
 715         if (unlikely (fd >= acc.fdCount))
 716           return false;
 717         subr_subset_param_t  param;
 718         param.init (&parsed_charstrings[i],
 719                     &parsed_global_subrs,  &parsed_local_subrs[fd],
 720                     closures.global_closure, closures.local_closures[fd],
 721                     drop_hints);
 722         collect_subr_refs_in_str (parsed_charstrings[i], param);
 723       }
 724     }
 725 
 726     remaps.create (closures);
 727 
 728     return true;
 729   }
 730 
 731   bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, str_buff_vec_t &buffArray) const
 732   {
 733     if (unlikely (!buffArray.resize (glyphs.length)))
 734       return false;
 735     for (unsigned int i = 0; i < glyphs.length; i++)
 736     {
 737       unsigned int  fd = acc.fdSelect->get_fd (glyphs[i]);
 738       if (unlikely (fd >= acc.fdCount))
 739         return false;
 740       if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
 741         return false;
 742     }
 743     return true;
 744   }
 745 
 746   bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
 747   {
 748     unsigned int  count = remap.get_count ();
 749 
 750     if (unlikely (!buffArray.resize (count)))
 751       return false;
 752     for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
 753     {
 754       hb_codepoint_t new_num = remap[old_num];
 755       if (new_num != CFF_UNDEF_CODE)
 756       {
 757         if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
 758           return false;
 759       }
 760     }
 761     return true;
 762   }
 763 
 764   bool encode_globalsubrs (str_buff_vec_t &buffArray)
 765   {
 766     return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray);
 767   }
 768 
 769   bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
 770   {
 771     return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray);
 772   }
 773 
 774   protected:
 775   struct drop_hints_param_t
 776   {
 777     drop_hints_param_t ()
 778       : seen_moveto (false),
 779         ends_in_hint (false),
 780         vsindex_dropped (false) {}
 781 
 782     bool  seen_moveto;
 783     bool  ends_in_hint;
 784     bool  vsindex_dropped;
 785   };
 786 
 787   bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos,
 788                            parsed_cs_str_vec_t &subrs, unsigned int subr_num,
 789                            const subr_subset_param_t &param, drop_hints_param_t &drop)
 790   {
 791     drop.ends_in_hint = false;
 792     bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
 793 
 794     /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto),
 795      * then this entire subroutine must be a hint. drop its call. */
 796     if (drop.ends_in_hint)
 797     {
 798       str.values[pos].set_drop ();
 799       /* if this subr call is at the end of the parent subr, propagate the flag
 800        * otherwise reset the flag */
 801       if (!str.at_end (pos))
 802         drop.ends_in_hint = false;
 803     }
 804 
 805     return has_hint;
 806   }
 807 
 808   /* returns true if it sees a hint op before the first moveto */
 809   bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param, drop_hints_param_t &drop)
 810   {
 811     bool  seen_hint = false;
 812 
 813     for (unsigned int pos = 0; pos < str.values.length; pos++)
 814     {
 815       bool  has_hint = false;
 816       switch (str.values[pos].op)
 817       {
 818         case OpCode_callsubr:
 819           has_hint = drop_hints_in_subr (str, pos,
 820                                         *param.parsed_local_subrs, str.values[pos].subr_num,
 821                                         param, drop);
 822 
 823           break;
 824 
 825         case OpCode_callgsubr:
 826           has_hint = drop_hints_in_subr (str, pos,
 827                                         *param.parsed_global_subrs, str.values[pos].subr_num,
 828                                         param, drop);
 829           break;
 830 
 831         case OpCode_rmoveto:
 832         case OpCode_hmoveto:
 833         case OpCode_vmoveto:
 834           drop.seen_moveto = true;
 835           break;
 836 
 837         case OpCode_hintmask:
 838         case OpCode_cntrmask:
 839           if (drop.seen_moveto)
 840           {
 841             str.values[pos].set_drop ();
 842             break;
 843           }
 844           HB_FALLTHROUGH;
 845 
 846         case OpCode_hstemhm:
 847         case OpCode_vstemhm:
 848         case OpCode_hstem:
 849         case OpCode_vstem:
 850           has_hint = true;
 851           str.values[pos].set_drop ();
 852           if (str.at_end (pos))
 853             drop.ends_in_hint = true;
 854           break;
 855 
 856         case OpCode_dotsection:
 857           str.values[pos].set_drop ();
 858           break;
 859 
 860         default:
 861           /* NONE */
 862           break;
 863       }
 864       if (has_hint)
 865       {
 866         for (int i = pos - 1; i >= 0; i--)
 867         {
 868           parsed_cs_op_t  &csop = str.values[(unsigned)i];
 869           if (csop.for_drop ())
 870             break;
 871           csop.set_drop ();
 872           if (csop.op == OpCode_vsindexcs)
 873             drop.vsindex_dropped = true;
 874         }
 875         seen_hint |= has_hint;
 876       }
 877     }
 878 
 879     return seen_hint;
 880   }
 881 
 882   void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
 883                                   unsigned int subr_num, parsed_cs_str_vec_t &subrs,
 884                                   hb_set_t *closure,
 885                                   const subr_subset_param_t &param)
 886   {
 887     hb_set_add (closure, subr_num);
 888     collect_subr_refs_in_str (subrs[subr_num], param);
 889   }
 890 
 891   void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param)
 892   {
 893     for (unsigned int pos = 0; pos < str.values.length; pos++)
 894     {
 895       if (!str.values[pos].for_drop ())
 896       {
 897         switch (str.values[pos].op)
 898         {
 899           case OpCode_callsubr:
 900             collect_subr_refs_in_subr (str, pos,
 901                                        str.values[pos].subr_num, *param.parsed_local_subrs,
 902                                        param.local_closure, param);
 903             break;
 904 
 905           case OpCode_callgsubr:
 906             collect_subr_refs_in_subr (str, pos,
 907                                        str.values[pos].subr_num, *param.parsed_global_subrs,
 908                                        param.global_closure, param);
 909             break;
 910 
 911           default: break;
 912         }
 913       }
 914     }
 915   }
 916 
 917   bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
 918   {
 919     buff.init ();
 920     str_encoder_t  encoder (buff);
 921     encoder.reset ();
 922     /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
 923      * re-insert it at the beginning of charstreing */
 924     if (str.has_prefix () && str.is_hint_dropped ())
 925     {
 926       encoder.encode_num (str.prefix_num ());
 927       if (str.prefix_op () != OpCode_Invalid)
 928         encoder.encode_op (str.prefix_op ());
 929     }
 930     for (unsigned int i = 0; i < str.get_count(); i++)
 931     {
 932       const parsed_cs_op_t  &opstr = str.values[i];
 933       if (!opstr.for_drop () && !opstr.for_skip ())
 934       {
 935         switch (opstr.op)
 936         {
 937           case OpCode_callsubr:
 938             encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
 939             encoder.encode_op (OpCode_callsubr);
 940             break;
 941 
 942           case OpCode_callgsubr:
 943             encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
 944             encoder.encode_op (OpCode_callgsubr);
 945             break;
 946 
 947           default:
 948             encoder.copy_str (opstr.str);
 949             break;
 950         }
 951       }
 952     }
 953     return !encoder.is_error ();
 954   }
 955 
 956   protected:
 957   subr_closures_t             closures;
 958 
 959   parsed_cs_str_vec_t          parsed_charstrings;
 960   parsed_cs_str_vec_t          parsed_global_subrs;
 961   hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs;
 962 
 963   subr_remap_ts         remaps;
 964 
 965   private:
 966   typedef typename SUBRS::count_type subr_count_type;
 967 };
 968 
 969 } /* namespace CFF */
 970 
 971 HB_INTERNAL bool
 972 hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
 973                             unsigned int fdCount,
 974                             const CFF::FDSelect &src, /* IN */
 975                             unsigned int &subset_fd_count /* OUT */,
 976                             unsigned int &subset_fdselect_size /* OUT */,
 977                             unsigned int &subset_fdselect_format /* OUT */,
 978                             hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
 979                             CFF::remap_t &fdmap /* OUT */);
 980 
 981 HB_INTERNAL bool
 982 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
 983                           unsigned int num_glyphs,
 984                           const CFF::FDSelect &src,
 985                           unsigned int fd_count,
 986                           unsigned int fdselect_format,
 987                           unsigned int size,
 988                           const hb_vector_t<CFF::code_pair_t> &fdselect_ranges);
 989 
 990 #endif /* HB_SUBSET_CFF_COMMON_HH */