Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / src / hb-subset-cff-common.hh
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 */