tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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