src/java.desktop/share/native/libfontmanager/harfbuzz/hb-subset-cff-common.hh
changeset 54232 7c11a7cc7c1d
equal deleted inserted replaced
54231:e4813eded7cb 54232:7c11a7cc7c1d
       
     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 */