• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
str_encoder_tCFF::str_encoder_t40   str_encoder_t (str_buff_t &buff_)
41     : buff (buff_), error (false) {}
42 
resetCFF::str_encoder_t43   void reset () { buff.resize (0); }
44 
encode_byteCFF::str_encoder_t45   void encode_byte (unsigned char b)
46   {
47     if (unlikely (buff.push (b) == &Crap (unsigned char)))
48       set_error ();
49   }
50 
encode_intCFF::str_encoder_t51   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 
encode_numCFF::str_encoder_t82   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 
encode_opCFF::str_encoder_t99   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 
copy_strCFF::str_encoder_t110   void copy_str (const byte_str_t &str)
111   {
112     unsigned int  offset = buff.length;
113     if (unlikely (!buff.resize (offset + str.length)))
114     {
115       set_error ();
116       return;
117     }
118     if (unlikely (buff.length < offset + str.length))
119     {
120       set_error ();
121       return;
122     }
123     memcpy (&buff[offset], &str[0], str.length);
124   }
125 
is_errorCFF::str_encoder_t126   bool is_error () const { return error; }
127 
128   protected:
set_errorCFF::str_encoder_t129   void set_error () { error = true; }
130 
131   str_buff_t &buff;
132   bool    error;
133 };
134 
135 struct cff_sub_table_info_t {
cff_sub_table_info_tCFF::cff_sub_table_info_t136   cff_sub_table_info_t ()
137     : fd_array_link (0),
138       char_strings_link (0)
139   {
140     fd_select.init ();
141   }
142 
143   table_info_t     fd_select;
144   objidx_t     	   fd_array_link;
145   objidx_t     	   char_strings_link;
146 };
147 
148 template <typename OPSTR=op_str_t>
149 struct cff_top_dict_op_serializer_t : op_serializer_t
150 {
serializeCFF::cff_top_dict_op_serializer_t151   bool serialize (hb_serialize_context_t *c,
152 		  const OPSTR &opstr,
153 		  const cff_sub_table_info_t &info) const
154   {
155     TRACE_SERIALIZE (this);
156 
157     switch (opstr.op)
158     {
159       case OpCode_CharStrings:
160 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
161 
162       case OpCode_FDArray:
163 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
164 
165       case OpCode_FDSelect:
166 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
167 
168       default:
169 	return_trace (copy_opstr (c, opstr));
170     }
171     return_trace (true);
172   }
173 };
174 
175 struct cff_font_dict_op_serializer_t : op_serializer_t
176 {
serializeCFF::cff_font_dict_op_serializer_t177   bool serialize (hb_serialize_context_t *c,
178 		  const op_str_t &opstr,
179 		  const table_info_t &privateDictInfo) const
180   {
181     TRACE_SERIALIZE (this);
182 
183     if (opstr.op == OpCode_Private)
184     {
185       /* serialize the private dict size & offset as 2-byte & 4-byte integers */
186       return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) &&
187 		    Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute));
188     }
189     else
190     {
191       HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
192       if (unlikely (!d)) return_trace (false);
193       memcpy (d, &opstr.str[0], opstr.str.length);
194     }
195     return_trace (true);
196   }
197 };
198 
199 struct cff_private_dict_op_serializer_t : op_serializer_t
200 {
cff_private_dict_op_serializer_tCFF::cff_private_dict_op_serializer_t201   cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
202     : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
203 
serializeCFF::cff_private_dict_op_serializer_t204   bool serialize (hb_serialize_context_t *c,
205 		  const op_str_t &opstr,
206 		  objidx_t subrs_link) const
207   {
208     TRACE_SERIALIZE (this);
209 
210     if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
211       return true;
212     if (opstr.op == OpCode_Subrs)
213     {
214       if (desubroutinize || !subrs_link)
215 	return_trace (true);
216       else
217 	return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
218     }
219     else
220       return_trace (copy_opstr (c, opstr));
221   }
222 
223   protected:
224   const bool  desubroutinize;
225   const bool  drop_hints;
226 };
227 
228 struct flatten_param_t
229 {
230   str_buff_t     &flatStr;
231   bool	drop_hints;
232 };
233 
234 template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
235 struct subr_flattener_t
236 {
subr_flattener_tCFF::subr_flattener_t237   subr_flattener_t (const ACC &acc_,
238 		    const hb_subset_plan_t *plan_)
239 		   : acc (acc_), plan (plan_) {}
240 
flattenCFF::subr_flattener_t241   bool flatten (str_buff_vec_t &flat_charstrings)
242   {
243     if (!flat_charstrings.resize (plan->num_output_glyphs ()))
244       return false;
245     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
246       flat_charstrings[i].init ();
247     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
248     {
249       hb_codepoint_t  glyph;
250       if (!plan->old_gid_for_new_gid (i, &glyph))
251       {
252 	/* add an endchar only charstring for a missing glyph if CFF1 */
253 	if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
254 	continue;
255       }
256       const byte_str_t str = (*acc.charStrings)[glyph];
257       unsigned int fd = acc.fdSelect->get_fd (glyph);
258       if (unlikely (fd >= acc.fdCount))
259 	return false;
260       cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
261       interp.env.init (str, acc, fd);
262       flatten_param_t  param = {
263         flat_charstrings[i],
264         (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
265       };
266       if (unlikely (!interp.interpret (param)))
267 	return false;
268     }
269     return true;
270   }
271 
272   const ACC &acc;
273   const hb_subset_plan_t *plan;
274 };
275 
276 struct subr_closures_t
277 {
subr_closures_tCFF::subr_closures_t278   subr_closures_t () : valid (false), global_closure (nullptr)
279   { local_closures.init (); }
280 
initCFF::subr_closures_t281   void init (unsigned int fd_count)
282   {
283     valid = true;
284     global_closure = hb_set_create ();
285     if (global_closure == hb_set_get_empty ())
286       valid = false;
287     if (!local_closures.resize (fd_count))
288       valid = false;
289 
290     for (unsigned int i = 0; i < local_closures.length; i++)
291     {
292       local_closures[i] = hb_set_create ();
293       if (local_closures[i] == hb_set_get_empty ())
294 	valid = false;
295     }
296   }
297 
finiCFF::subr_closures_t298   void fini ()
299   {
300     hb_set_destroy (global_closure);
301     for (unsigned int i = 0; i < local_closures.length; i++)
302       hb_set_destroy (local_closures[i]);
303     local_closures.fini ();
304   }
305 
resetCFF::subr_closures_t306   void reset ()
307   {
308     hb_set_clear (global_closure);
309     for (unsigned int i = 0; i < local_closures.length; i++)
310       hb_set_clear (local_closures[i]);
311   }
312 
is_validCFF::subr_closures_t313   bool is_valid () const { return valid; }
314   bool  valid;
315   hb_set_t  *global_closure;
316   hb_vector_t<hb_set_t *> local_closures;
317 };
318 
319 struct parsed_cs_op_t : op_str_t
320 {
initCFF::parsed_cs_op_t321   void init (unsigned int subr_num_ = 0)
322   {
323     op_str_t::init ();
324     subr_num = subr_num_;
325     drop_flag = false;
326     keep_flag = false;
327     skip_flag = false;
328   }
329 
finiCFF::parsed_cs_op_t330   void fini () { op_str_t::fini (); }
331 
for_dropCFF::parsed_cs_op_t332   bool for_drop () const { return drop_flag; }
set_dropCFF::parsed_cs_op_t333   void set_drop ()       { if (!for_keep ()) drop_flag = true; }
334 
for_keepCFF::parsed_cs_op_t335   bool for_keep () const { return keep_flag; }
set_keepCFF::parsed_cs_op_t336   void set_keep ()       { keep_flag = true; }
337 
for_skipCFF::parsed_cs_op_t338   bool for_skip () const { return skip_flag; }
set_skipCFF::parsed_cs_op_t339   void set_skip ()       { skip_flag = true; }
340 
341   unsigned int  subr_num;
342 
343   protected:
344   bool	  drop_flag : 1;
345   bool	  keep_flag : 1;
346   bool	  skip_flag : 1;
347 };
348 
349 struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
350 {
initCFF::parsed_cs_str_t351   void init ()
352   {
353     SUPER::init ();
354     parsed = false;
355     hint_dropped = false;
356     has_prefix_ = false;
357   }
358 
add_opCFF::parsed_cs_str_t359   void add_op (op_code_t op, const byte_str_ref_t& str_ref)
360   {
361     if (!is_parsed ())
362       SUPER::add_op (op, str_ref);
363   }
364 
add_call_opCFF::parsed_cs_str_t365   void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num)
366   {
367     if (!is_parsed ())
368     {
369       unsigned int parsed_len = get_count ();
370       if (likely (parsed_len > 0))
371 	values[parsed_len-1].set_skip ();
372 
373       parsed_cs_op_t val;
374       val.init (subr_num);
375       SUPER::add_op (op, str_ref, val);
376     }
377   }
378 
set_prefixCFF::parsed_cs_str_t379   void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid)
380   {
381     has_prefix_ = true;
382     prefix_op_ = op;
383     prefix_num_ = num;
384   }
385 
at_endCFF::parsed_cs_str_t386   bool at_end (unsigned int pos) const
387   {
388     return ((pos + 1 >= values.length) /* CFF2 */
389 	|| (values[pos + 1].op == OpCode_return));
390   }
391 
is_parsedCFF::parsed_cs_str_t392   bool is_parsed () const { return parsed; }
set_parsedCFF::parsed_cs_str_t393   void set_parsed ()      { parsed = true; }
394 
is_hint_droppedCFF::parsed_cs_str_t395   bool is_hint_dropped () const { return hint_dropped; }
set_hint_droppedCFF::parsed_cs_str_t396   void set_hint_dropped ()      { hint_dropped = true; }
397 
is_vsindex_droppedCFF::parsed_cs_str_t398   bool is_vsindex_dropped () const { return vsindex_dropped; }
set_vsindex_droppedCFF::parsed_cs_str_t399   void set_vsindex_dropped ()      { vsindex_dropped = true; }
400 
has_prefixCFF::parsed_cs_str_t401   bool has_prefix () const          { return has_prefix_; }
prefix_opCFF::parsed_cs_str_t402   op_code_t prefix_op () const         { return prefix_op_; }
prefix_numCFF::parsed_cs_str_t403   const number_t &prefix_num () const { return prefix_num_; }
404 
405   protected:
406   bool    parsed;
407   bool    hint_dropped;
408   bool    vsindex_dropped;
409   bool    has_prefix_;
410   op_code_t	prefix_op_;
411   number_t	prefix_num_;
412 
413   private:
414   typedef parsed_values_t<parsed_cs_op_t> SUPER;
415 };
416 
417 struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
418 {
initCFF::parsed_cs_str_vec_t419   void init (unsigned int len_ = 0)
420   {
421     SUPER::init ();
422     if (unlikely (!resize (len_)))
423       return;
424     for (unsigned int i = 0; i < length; i++)
425       (*this)[i].init ();
426   }
finiCFF::parsed_cs_str_vec_t427   void fini () { SUPER::fini_deep (); }
428 
429   private:
430   typedef hb_vector_t<parsed_cs_str_t> SUPER;
431 };
432 
433 struct subr_subset_param_t
434 {
initCFF::subr_subset_param_t435   void init (parsed_cs_str_t *parsed_charstring_,
436 	     parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_,
437 	     hb_set_t *global_closure_, hb_set_t *local_closure_,
438 	     bool drop_hints_)
439   {
440     parsed_charstring = parsed_charstring_;
441     current_parsed_str = parsed_charstring;
442     parsed_global_subrs = parsed_global_subrs_;
443     parsed_local_subrs = parsed_local_subrs_;
444     global_closure = global_closure_;
445     local_closure = local_closure_;
446     drop_hints = drop_hints_;
447   }
448 
get_parsed_str_for_contextCFF::subr_subset_param_t449   parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context)
450   {
451     switch (context.type)
452     {
453       case CSType_CharString:
454 	return parsed_charstring;
455 
456       case CSType_LocalSubr:
457 	if (likely (context.subr_num < parsed_local_subrs->length))
458 	  return &(*parsed_local_subrs)[context.subr_num];
459 	break;
460 
461       case CSType_GlobalSubr:
462 	if (likely (context.subr_num < parsed_global_subrs->length))
463 	  return &(*parsed_global_subrs)[context.subr_num];
464 	break;
465     }
466     return nullptr;
467   }
468 
469   template <typename ENV>
set_current_strCFF::subr_subset_param_t470   void set_current_str (ENV &env, bool calling)
471   {
472     parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
473     if (unlikely (!parsed_str))
474     {
475       env.set_error ();
476       return;
477     }
478     /* If the called subroutine is parsed partially but not completely yet,
479      * it must be because we are calling it recursively.
480      * Handle it as an error. */
481     if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
482       env.set_error ();
483     else
484       current_parsed_str = parsed_str;
485   }
486 
487   parsed_cs_str_t	*current_parsed_str;
488 
489   parsed_cs_str_t	*parsed_charstring;
490   parsed_cs_str_vec_t	*parsed_global_subrs;
491   parsed_cs_str_vec_t	*parsed_local_subrs;
492   hb_set_t      *global_closure;
493   hb_set_t      *local_closure;
494   bool	  drop_hints;
495 };
496 
497 struct subr_remap_t : hb_inc_bimap_t
498 {
createCFF::subr_remap_t499   void create (hb_set_t *closure)
500   {
501     /* create a remapping of subroutine numbers from old to new.
502      * no optimization based on usage counts. fonttools doesn't appear doing that either.
503      */
504 
505     hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
506     while (hb_set_next (closure, &old_num))
507       add (old_num);
508 
509     if (get_population () < 1240)
510       bias = 107;
511     else if (get_population () < 33900)
512       bias = 1131;
513     else
514       bias = 32768;
515   }
516 
biased_numCFF::subr_remap_t517   int biased_num (unsigned int old_num) const
518   {
519     hb_codepoint_t new_num = get (old_num);
520     return (int)new_num - bias;
521   }
522 
523   protected:
524   int bias;
525 };
526 
527 struct subr_remaps_t
528 {
subr_remaps_tCFF::subr_remaps_t529   subr_remaps_t ()
530   {
531     global_remap.init ();
532     local_remaps.init ();
533   }
534 
~subr_remaps_tCFF::subr_remaps_t535   ~subr_remaps_t () { fini (); }
536 
initCFF::subr_remaps_t537   void init (unsigned int fdCount)
538   {
539     if (unlikely (!local_remaps.resize (fdCount))) return;
540     for (unsigned int i = 0; i < fdCount; i++)
541       local_remaps[i].init ();
542   }
543 
in_errorCFF::subr_remaps_t544   bool in_error()
545   {
546     return local_remaps.in_error ();
547   }
548 
createCFF::subr_remaps_t549   void create (subr_closures_t& closures)
550   {
551     global_remap.create (closures.global_closure);
552     for (unsigned int i = 0; i < local_remaps.length; i++)
553       local_remaps[i].create (closures.local_closures[i]);
554   }
555 
finiCFF::subr_remaps_t556   void fini ()
557   {
558     global_remap.fini ();
559     local_remaps.fini_deep ();
560   }
561 
562   subr_remap_t	       global_remap;
563   hb_vector_t<subr_remap_t>  local_remaps;
564 };
565 
566 template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
567 struct subr_subsetter_t
568 {
subr_subsetter_tCFF::subr_subsetter_t569   subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
570     : acc (acc_), plan (plan_)
571   {
572     parsed_charstrings.init ();
573     parsed_global_subrs.init ();
574     parsed_local_subrs.init ();
575   }
576 
~subr_subsetter_tCFF::subr_subsetter_t577   ~subr_subsetter_t ()
578   {
579     closures.fini ();
580     remaps.fini ();
581     parsed_charstrings.fini_deep ();
582     parsed_global_subrs.fini_deep ();
583     parsed_local_subrs.fini_deep ();
584   }
585 
586   /* Subroutine subsetting with --no-desubroutinize runs in phases:
587    *
588    * 1. execute charstrings/subroutines to determine subroutine closures
589    * 2. parse out all operators and numbers
590    * 3. mark hint operators and operands for removal if --no-hinting
591    * 4. re-encode all charstrings and subroutines with new subroutine numbers
592    *
593    * Phases #1 and #2 are done at the same time in collect_subrs ().
594    * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required),
595    * because we can't tell if a number belongs to a hint op until we see the first moveto.
596    *
597    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
598    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
599    */
subsetCFF::subr_subsetter_t600   bool subset (void)
601   {
602     closures.init (acc.fdCount);
603     remaps.init (acc.fdCount);
604 
605     parsed_charstrings.init (plan->num_output_glyphs ());
606     parsed_global_subrs.init (acc.globalSubrs->count);
607 
608     if (unlikely (remaps.in_error()
609                   || parsed_charstrings.in_error ()
610                   || parsed_global_subrs.in_error ())) {
611       return false;
612     }
613 
614     if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
615 
616     for (unsigned int i = 0; i < acc.fdCount; i++)
617     {
618       parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
619       if (unlikely (parsed_local_subrs[i].in_error ())) return false;
620     }
621     if (unlikely (!closures.valid))
622       return false;
623 
624     /* phase 1 & 2 */
625     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
626     {
627       hb_codepoint_t  glyph;
628       if (!plan->old_gid_for_new_gid (i, &glyph))
629 	continue;
630       const byte_str_t str = (*acc.charStrings)[glyph];
631       unsigned int fd = acc.fdSelect->get_fd (glyph);
632       if (unlikely (fd >= acc.fdCount))
633 	return false;
634 
635       cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp;
636       interp.env.init (str, acc, fd);
637 
638       subr_subset_param_t  param;
639       param.init (&parsed_charstrings[i],
640 		  &parsed_global_subrs,  &parsed_local_subrs[fd],
641 		  closures.global_closure, closures.local_closures[fd],
642 		  plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
643 
644       if (unlikely (!interp.interpret (param)))
645 	return false;
646 
647       /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
648       SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
649     }
650 
651     if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
652     {
653       /* mark hint ops and arguments for drop */
654       for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
655       {
656 	hb_codepoint_t  glyph;
657 	if (!plan->old_gid_for_new_gid (i, &glyph))
658 	  continue;
659 	unsigned int fd = acc.fdSelect->get_fd (glyph);
660 	if (unlikely (fd >= acc.fdCount))
661 	  return false;
662 	subr_subset_param_t  param;
663 	param.init (&parsed_charstrings[i],
664 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
665 		    closures.global_closure, closures.local_closures[fd],
666                     plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
667 
668 	drop_hints_param_t  drop;
669 	if (drop_hints_in_str (parsed_charstrings[i], param, drop))
670 	{
671 	  parsed_charstrings[i].set_hint_dropped ();
672 	  if (drop.vsindex_dropped)
673 	    parsed_charstrings[i].set_vsindex_dropped ();
674 	}
675       }
676 
677       /* after dropping hints recreate closures of actually used subrs */
678       closures.reset ();
679       for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
680       {
681 	hb_codepoint_t  glyph;
682 	if (!plan->old_gid_for_new_gid (i, &glyph))
683 	  continue;
684 	unsigned int fd = acc.fdSelect->get_fd (glyph);
685 	if (unlikely (fd >= acc.fdCount))
686 	  return false;
687 	subr_subset_param_t  param;
688 	param.init (&parsed_charstrings[i],
689 		    &parsed_global_subrs,  &parsed_local_subrs[fd],
690 		    closures.global_closure, closures.local_closures[fd],
691                     plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
692 	collect_subr_refs_in_str (parsed_charstrings[i], param);
693       }
694     }
695 
696     remaps.create (closures);
697 
698     return true;
699   }
700 
encode_charstringsCFF::subr_subsetter_t701   bool encode_charstrings (str_buff_vec_t &buffArray) const
702   {
703     if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
704       return false;
705     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
706     {
707       hb_codepoint_t  glyph;
708       if (!plan->old_gid_for_new_gid (i, &glyph))
709       {
710 	/* add an endchar only charstring for a missing glyph if CFF1 */
711 	if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
712 	continue;
713       }
714       unsigned int  fd = acc.fdSelect->get_fd (glyph);
715       if (unlikely (fd >= acc.fdCount))
716 	return false;
717       if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
718 	return false;
719     }
720     return true;
721   }
722 
encode_subrsCFF::subr_subsetter_t723   bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
724   {
725     unsigned int  count = remap.get_population ();
726 
727     if (unlikely (!buffArray.resize (count)))
728       return false;
729     for (unsigned int old_num = 0; old_num < subrs.length; old_num++)
730     {
731       hb_codepoint_t new_num = remap[old_num];
732       if (new_num != CFF_UNDEF_CODE)
733       {
734 	if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
735 	  return false;
736       }
737     }
738     return true;
739   }
740 
encode_globalsubrsCFF::subr_subsetter_t741   bool encode_globalsubrs (str_buff_vec_t &buffArray)
742   {
743     return encode_subrs (parsed_global_subrs, remaps.global_remap, 0, buffArray);
744   }
745 
encode_localsubrsCFF::subr_subsetter_t746   bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
747   {
748     return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], fd, buffArray);
749   }
750 
751   protected:
752   struct drop_hints_param_t
753   {
drop_hints_param_tCFF::subr_subsetter_t::drop_hints_param_t754     drop_hints_param_t ()
755       : seen_moveto (false),
756 	ends_in_hint (false),
757 	all_dropped (false),
758 	vsindex_dropped (false) {}
759 
760     bool  seen_moveto;
761     bool  ends_in_hint;
762     bool  all_dropped;
763     bool  vsindex_dropped;
764   };
765 
drop_hints_in_subrCFF::subr_subsetter_t766   bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos,
767 			   parsed_cs_str_vec_t &subrs, unsigned int subr_num,
768 			   const subr_subset_param_t &param, drop_hints_param_t &drop)
769   {
770     drop.ends_in_hint = false;
771     bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
772 
773     /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
774      * then this entire subroutine must be a hint. drop its call. */
775     if (drop.ends_in_hint)
776     {
777       str.values[pos].set_drop ();
778       /* if this subr call is at the end of the parent subr, propagate the flag
779        * otherwise reset the flag */
780       if (!str.at_end (pos))
781 	drop.ends_in_hint = false;
782     }
783     else if (drop.all_dropped)
784     {
785       str.values[pos].set_drop ();
786     }
787 
788     return has_hint;
789   }
790 
791   /* returns true if it sees a hint op before the first moveto */
drop_hints_in_strCFF::subr_subsetter_t792   bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param, drop_hints_param_t &drop)
793   {
794     bool  seen_hint = false;
795 
796     for (unsigned int pos = 0; pos < str.values.length; pos++)
797     {
798       bool  has_hint = false;
799       switch (str.values[pos].op)
800       {
801 	case OpCode_callsubr:
802 	  has_hint = drop_hints_in_subr (str, pos,
803 					*param.parsed_local_subrs, str.values[pos].subr_num,
804 					param, drop);
805 	  break;
806 
807 	case OpCode_callgsubr:
808 	  has_hint = drop_hints_in_subr (str, pos,
809 					*param.parsed_global_subrs, str.values[pos].subr_num,
810 					param, drop);
811 	  break;
812 
813 	case OpCode_rmoveto:
814 	case OpCode_hmoveto:
815 	case OpCode_vmoveto:
816 	  drop.seen_moveto = true;
817 	  break;
818 
819 	case OpCode_hintmask:
820 	case OpCode_cntrmask:
821 	  if (drop.seen_moveto)
822 	  {
823 	    str.values[pos].set_drop ();
824 	    break;
825 	  }
826 	  HB_FALLTHROUGH;
827 
828 	case OpCode_hstemhm:
829 	case OpCode_vstemhm:
830 	case OpCode_hstem:
831 	case OpCode_vstem:
832 	  has_hint = true;
833 	  str.values[pos].set_drop ();
834 	  if (str.at_end (pos))
835 	    drop.ends_in_hint = true;
836 	  break;
837 
838 	case OpCode_dotsection:
839 	  str.values[pos].set_drop ();
840 	  break;
841 
842 	default:
843 	  /* NONE */
844 	  break;
845       }
846       if (has_hint)
847       {
848 	for (int i = pos - 1; i >= 0; i--)
849 	{
850 	  parsed_cs_op_t  &csop = str.values[(unsigned)i];
851 	  if (csop.for_drop ())
852 	    break;
853 	  csop.set_drop ();
854 	  if (csop.op == OpCode_vsindexcs)
855 	    drop.vsindex_dropped = true;
856 	}
857 	seen_hint |= has_hint;
858       }
859     }
860 
861     /* Raise all_dropped flag if all operators except return are dropped from a subr.
862      * It may happen even after seeing the first moveto if a subr contains
863      * only (usually one) hintmask operator, then calls to this subr can be dropped.
864      */
865     drop.all_dropped = true;
866     for (unsigned int pos = 0; pos < str.values.length; pos++)
867     {
868       parsed_cs_op_t  &csop = str.values[pos];
869       if (csop.op == OpCode_return)
870 	break;
871       if (!csop.for_drop ())
872       {
873 	drop.all_dropped = false;
874 	break;
875       }
876     }
877 
878     return seen_hint;
879   }
880 
collect_subr_refs_in_subrCFF::subr_subsetter_t881   void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
882 				  unsigned int subr_num, parsed_cs_str_vec_t &subrs,
883 				  hb_set_t *closure,
884 				  const subr_subset_param_t &param)
885   {
886     closure->add (subr_num);
887     collect_subr_refs_in_str (subrs[subr_num], param);
888   }
889 
collect_subr_refs_in_strCFF::subr_subsetter_t890   void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param)
891   {
892     for (unsigned int pos = 0; pos < str.values.length; pos++)
893     {
894       if (!str.values[pos].for_drop ())
895       {
896 	switch (str.values[pos].op)
897 	{
898 	  case OpCode_callsubr:
899 	    collect_subr_refs_in_subr (str, pos,
900 				       str.values[pos].subr_num, *param.parsed_local_subrs,
901 				       param.local_closure, param);
902 	    break;
903 
904 	  case OpCode_callgsubr:
905 	    collect_subr_refs_in_subr (str, pos,
906 				       str.values[pos].subr_num, *param.parsed_global_subrs,
907 				       param.global_closure, param);
908 	    break;
909 
910 	  default: break;
911 	}
912       }
913     }
914   }
915 
encode_strCFF::subr_subsetter_t916   bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
917   {
918     buff.init ();
919     str_encoder_t  encoder (buff);
920     encoder.reset ();
921     /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
922      * re-insert it at the beginning of charstreing */
923     if (str.has_prefix () && str.is_hint_dropped ())
924     {
925       encoder.encode_num (str.prefix_num ());
926       if (str.prefix_op () != OpCode_Invalid)
927 	encoder.encode_op (str.prefix_op ());
928     }
929     for (unsigned int i = 0; i < str.get_count(); i++)
930     {
931       const parsed_cs_op_t  &opstr = str.values[i];
932       if (!opstr.for_drop () && !opstr.for_skip ())
933       {
934 	switch (opstr.op)
935 	{
936 	  case OpCode_callsubr:
937 	    encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
938 	    encoder.encode_op (OpCode_callsubr);
939 	    break;
940 
941 	  case OpCode_callgsubr:
942 	    encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
943 	    encoder.encode_op (OpCode_callgsubr);
944 	    break;
945 
946 	  default:
947 	    encoder.copy_str (opstr.str);
948 	    break;
949 	}
950       }
951     }
952     return !encoder.is_error ();
953   }
954 
955   protected:
956   const ACC			&acc;
957   const hb_subset_plan_t	*plan;
958 
959   subr_closures_t		closures;
960 
961   parsed_cs_str_vec_t		parsed_charstrings;
962   parsed_cs_str_vec_t		parsed_global_subrs;
963   hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs;
964 
965   subr_remaps_t			remaps;
966 
967   private:
968   typedef typename SUBRS::count_type subr_count_type;
969 };
970 
971 } /* namespace CFF */
972 
973 HB_INTERNAL bool
974 hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
975 			    unsigned int fdCount,
976 			    const CFF::FDSelect &src, /* IN */
977 			    unsigned int &subset_fd_count /* OUT */,
978 			    unsigned int &subset_fdselect_size /* OUT */,
979 			    unsigned int &subset_fdselect_format /* OUT */,
980 			    hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
981 			    hb_inc_bimap_t &fdmap /* OUT */);
982 
983 HB_INTERNAL bool
984 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
985 			  unsigned int num_glyphs,
986 			  const CFF::FDSelect &src,
987 			  unsigned int fd_count,
988 			  unsigned int fdselect_format,
989 			  unsigned int size,
990 			  const hb_vector_t<CFF::code_pair_t> &fdselect_ranges);
991 
992 #endif /* HB_SUBSET_CFF_COMMON_HH */
993