• 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_) {}
42 
resetCFF::str_encoder_t43   void reset () { buff.reset (); }
44 
encode_byteCFF::str_encoder_t45   void encode_byte (unsigned char b)
46   {
47     if (likely ((signed) buff.length < buff.allocated))
48       buff.arrayZ[buff.length++] = b;
49     else
50       buff.push (b);
51   }
52 
encode_intCFF::str_encoder_t53   void encode_int (int v)
54   {
55     if ((-1131 <= v) && (v <= 1131))
56     {
57       if ((-107 <= v) && (v <= 107))
58 	encode_byte (v + 139);
59       else if (v > 0)
60       {
61 	v -= 108;
62 	encode_byte ((v >> 8) + OpCode_TwoBytePosInt0);
63 	encode_byte (v & 0xFF);
64       }
65       else
66       {
67 	v = -v - 108;
68 	encode_byte ((v >> 8) + OpCode_TwoByteNegInt0);
69 	encode_byte (v & 0xFF);
70       }
71     }
72     else
73     {
74       if (unlikely (v < -32768))
75 	v = -32768;
76       else if (unlikely (v > 32767))
77 	v = 32767;
78       encode_byte (OpCode_shortint);
79       encode_byte ((v >> 8) & 0xFF);
80       encode_byte (v & 0xFF);
81     }
82   }
83 
encode_numCFF::str_encoder_t84   void encode_num (const number_t& n)
85   {
86     if (n.in_int_range ())
87     {
88       encode_int (n.to_int ());
89     }
90     else
91     {
92       int32_t v = n.to_fixed ();
93       encode_byte (OpCode_fixedcs);
94       encode_byte ((v >> 24) & 0xFF);
95       encode_byte ((v >> 16) & 0xFF);
96       encode_byte ((v >> 8) & 0xFF);
97       encode_byte (v & 0xFF);
98     }
99   }
100 
encode_opCFF::str_encoder_t101   void encode_op (op_code_t op)
102   {
103     if (Is_OpCode_ESC (op))
104     {
105       encode_byte (OpCode_escape);
106       encode_byte (Unmake_OpCode_ESC (op));
107     }
108     else
109       encode_byte (op);
110   }
111 
copy_strCFF::str_encoder_t112   void copy_str (const unsigned char *str, unsigned length)
113   {
114     assert ((signed) (buff.length + length) <= buff.allocated);
115     hb_memcpy (buff.arrayZ + buff.length, str, length);
116     buff.length += length;
117   }
118 
in_errorCFF::str_encoder_t119   bool in_error () const { return buff.in_error (); }
120 
121   protected:
122 
123   str_buff_t &buff;
124 };
125 
126 struct cff_sub_table_info_t {
cff_sub_table_info_tCFF::cff_sub_table_info_t127   cff_sub_table_info_t ()
128     : fd_array_link (0),
129       char_strings_link (0)
130   {
131     fd_select.init ();
132   }
133 
134   table_info_t     fd_select;
135   objidx_t     	   fd_array_link;
136   objidx_t     	   char_strings_link;
137 };
138 
139 template <typename OPSTR=op_str_t>
140 struct cff_top_dict_op_serializer_t : op_serializer_t
141 {
serializeCFF::cff_top_dict_op_serializer_t142   bool serialize (hb_serialize_context_t *c,
143 		  const OPSTR &opstr,
144 		  const cff_sub_table_info_t &info) const
145   {
146     TRACE_SERIALIZE (this);
147 
148     switch (opstr.op)
149     {
150       case OpCode_CharStrings:
151 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute));
152 
153       case OpCode_FDArray:
154 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute));
155 
156       case OpCode_FDSelect:
157 	return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute));
158 
159       default:
160 	return_trace (copy_opstr (c, opstr));
161     }
162     return_trace (true);
163   }
164 };
165 
166 struct cff_font_dict_op_serializer_t : op_serializer_t
167 {
serializeCFF::cff_font_dict_op_serializer_t168   bool serialize (hb_serialize_context_t *c,
169 		  const op_str_t &opstr,
170 		  const table_info_t &privateDictInfo) const
171   {
172     TRACE_SERIALIZE (this);
173 
174     if (opstr.op == OpCode_Private)
175     {
176       /* serialize the private dict size & offset as 2-byte & 4-byte integers */
177       return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) &&
178 		    Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute));
179     }
180     else
181     {
182       unsigned char *d = c->allocate_size<unsigned char> (opstr.length);
183       if (unlikely (!d)) return_trace (false);
184       /* Faster than hb_memcpy for small strings. */
185       for (unsigned i = 0; i < opstr.length; i++)
186 	d[i] = opstr.ptr[i];
187       //hb_memcpy (d, opstr.ptr, opstr.length);
188     }
189     return_trace (true);
190   }
191 };
192 
193 struct cff_private_dict_op_serializer_t : op_serializer_t
194 {
cff_private_dict_op_serializer_tCFF::cff_private_dict_op_serializer_t195   cff_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_)
196     : desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
197 
serializeCFF::cff_private_dict_op_serializer_t198   bool serialize (hb_serialize_context_t *c,
199 		  const op_str_t &opstr,
200 		  objidx_t subrs_link) const
201   {
202     TRACE_SERIALIZE (this);
203 
204     if (drop_hints && dict_opset_t::is_hint_op (opstr.op))
205       return true;
206     if (opstr.op == OpCode_Subrs)
207     {
208       if (desubroutinize || !subrs_link)
209 	return_trace (true);
210       else
211 	return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link));
212     }
213     else
214       return_trace (copy_opstr (c, opstr));
215   }
216 
217   protected:
218   const bool  desubroutinize;
219   const bool  drop_hints;
220 };
221 
222 struct flatten_param_t
223 {
224   str_buff_t     &flatStr;
225   bool	drop_hints;
226 };
227 
228 template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
229 struct subr_flattener_t
230 {
subr_flattener_tCFF::subr_flattener_t231   subr_flattener_t (const ACC &acc_,
232 		    const hb_subset_plan_t *plan_)
233 		   : acc (acc_), plan (plan_) {}
234 
flattenCFF::subr_flattener_t235   bool flatten (str_buff_vec_t &flat_charstrings)
236   {
237     unsigned count = plan->num_output_glyphs ();
238     if (!flat_charstrings.resize (count))
239       return false;
240     for (unsigned int i = 0; i < count; i++)
241     {
242       hb_codepoint_t  glyph;
243       if (!plan->old_gid_for_new_gid (i, &glyph))
244       {
245 	/* add an endchar only charstring for a missing glyph if CFF1 */
246 	if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
247 	continue;
248       }
249       const hb_ubytes_t str = (*acc.charStrings)[glyph];
250       unsigned int fd = acc.fdSelect->get_fd (glyph);
251       if (unlikely (fd >= acc.fdCount))
252 	return false;
253       ENV env (str, acc, fd);
254       cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env);
255       flatten_param_t  param = {
256         flat_charstrings.arrayZ[i],
257         (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
258       };
259       if (unlikely (!interp.interpret (param)))
260 	return false;
261     }
262     return true;
263   }
264 
265   const ACC &acc;
266   const hb_subset_plan_t *plan;
267 };
268 
269 struct subr_closures_t
270 {
subr_closures_tCFF::subr_closures_t271   subr_closures_t (unsigned int fd_count) : global_closure (), local_closures ()
272   {
273     local_closures.resize (fd_count);
274   }
275 
resetCFF::subr_closures_t276   void reset ()
277   {
278     global_closure.clear();
279     for (unsigned int i = 0; i < local_closures.length; i++)
280       local_closures[i].clear();
281   }
282 
in_errorCFF::subr_closures_t283   bool in_error () const { return local_closures.in_error (); }
284   hb_set_t  global_closure;
285   hb_vector_t<hb_set_t> local_closures;
286 };
287 
288 struct parsed_cs_op_t : op_str_t
289 {
parsed_cs_op_tCFF::parsed_cs_op_t290   parsed_cs_op_t (unsigned int subr_num_ = 0) :
291     subr_num (subr_num_) {}
292 
is_hintingCFF::parsed_cs_op_t293   bool is_hinting () const { return hinting_flag; }
set_hintingCFF::parsed_cs_op_t294   void set_hinting ()       { hinting_flag = true; }
295 
296   /* The layout of this struct is designed to fit within the
297    * padding of op_str_t! */
298 
299   protected:
300   bool	  hinting_flag = false;
301 
302   public:
303   uint16_t subr_num;
304 };
305 
306 struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t>
307 {
parsed_cs_str_tCFF::parsed_cs_str_t308   parsed_cs_str_t () :
309     parsed (false),
310     hint_dropped (false),
311     has_prefix_ (false),
312     has_calls_ (false)
313   {
314     SUPER::init ();
315   }
316 
add_opCFF::parsed_cs_str_t317   void add_op (op_code_t op, const byte_str_ref_t& str_ref)
318   {
319     if (!is_parsed ())
320       SUPER::add_op (op, str_ref);
321   }
322 
add_call_opCFF::parsed_cs_str_t323   void add_call_op (op_code_t op, const byte_str_ref_t& str_ref, unsigned int subr_num)
324   {
325     if (!is_parsed ())
326     {
327       has_calls_ = true;
328 
329       /* Pop the subroutine number. */
330       values.pop ();
331 
332       SUPER::add_op (op, str_ref, {subr_num});
333     }
334   }
335 
set_prefixCFF::parsed_cs_str_t336   void set_prefix (const number_t &num, op_code_t op = OpCode_Invalid)
337   {
338     has_prefix_ = true;
339     prefix_op_ = op;
340     prefix_num_ = num;
341   }
342 
at_endCFF::parsed_cs_str_t343   bool at_end (unsigned int pos) const
344   {
345     return ((pos + 1 >= values.length) /* CFF2 */
346 	|| (values[pos + 1].op == OpCode_return));
347   }
348 
is_parsedCFF::parsed_cs_str_t349   bool is_parsed () const { return parsed; }
set_parsedCFF::parsed_cs_str_t350   void set_parsed ()      { parsed = true; }
351 
is_hint_droppedCFF::parsed_cs_str_t352   bool is_hint_dropped () const { return hint_dropped; }
set_hint_droppedCFF::parsed_cs_str_t353   void set_hint_dropped ()      { hint_dropped = true; }
354 
is_vsindex_droppedCFF::parsed_cs_str_t355   bool is_vsindex_dropped () const { return vsindex_dropped; }
set_vsindex_droppedCFF::parsed_cs_str_t356   void set_vsindex_dropped ()      { vsindex_dropped = true; }
357 
has_prefixCFF::parsed_cs_str_t358   bool has_prefix () const          { return has_prefix_; }
prefix_opCFF::parsed_cs_str_t359   op_code_t prefix_op () const         { return prefix_op_; }
prefix_numCFF::parsed_cs_str_t360   const number_t &prefix_num () const { return prefix_num_; }
361 
has_callsCFF::parsed_cs_str_t362   bool has_calls () const          { return has_calls_; }
363 
364   protected:
365   bool    parsed : 1;
366   bool    hint_dropped : 1;
367   bool    vsindex_dropped : 1;
368   bool    has_prefix_ : 1;
369   bool    has_calls_ : 1;
370   op_code_t	prefix_op_;
371   number_t	prefix_num_;
372 
373   private:
374   typedef parsed_values_t<parsed_cs_op_t> SUPER;
375 };
376 
377 struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
378 {
379   private:
380   typedef hb_vector_t<parsed_cs_str_t> SUPER;
381 };
382 
383 struct cff_subset_accelerator_t
384 {
createCFF::cff_subset_accelerator_t385   static cff_subset_accelerator_t* create (
386       hb_blob_t* original_blob,
387       const parsed_cs_str_vec_t& parsed_charstrings,
388       const parsed_cs_str_vec_t& parsed_global_subrs,
389       const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
390     cff_subset_accelerator_t* accel =
391         (cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
392     new (accel) cff_subset_accelerator_t (original_blob,
393                                           parsed_charstrings,
394                                           parsed_global_subrs,
395                                           parsed_local_subrs);
396     return accel;
397   }
398 
destroyCFF::cff_subset_accelerator_t399   static void destroy (void* value) {
400     if (!value) return;
401 
402     cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
403     accel->~cff_subset_accelerator_t ();
404     hb_free (accel);
405   }
406 
cff_subset_accelerator_tCFF::cff_subset_accelerator_t407   cff_subset_accelerator_t(
408       hb_blob_t* original_blob_,
409       const parsed_cs_str_vec_t& parsed_charstrings_,
410       const parsed_cs_str_vec_t& parsed_global_subrs_,
411       const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
412   {
413     parsed_charstrings = parsed_charstrings_;
414     parsed_global_subrs = parsed_global_subrs_;
415     parsed_local_subrs = parsed_local_subrs_;
416 
417     // the parsed charstrings point to memory in the original CFF table so we must hold a reference
418     // to it to keep the memory valid.
419     original_blob = hb_blob_reference (original_blob_);
420   }
421 
~cff_subset_accelerator_tCFF::cff_subset_accelerator_t422   ~cff_subset_accelerator_t() {
423     hb_blob_destroy (original_blob);
424     hb_map_destroy (glyph_to_sid_map.get_relaxed ());
425   }
426 
427   parsed_cs_str_vec_t parsed_charstrings;
428   parsed_cs_str_vec_t parsed_global_subrs;
429   hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
430   mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr;
431 
432  private:
433   hb_blob_t* original_blob;
434 };
435 
436 struct subr_subset_param_t
437 {
subr_subset_param_tCFF::subr_subset_param_t438   subr_subset_param_t (parsed_cs_str_t *parsed_charstring_,
439 		       parsed_cs_str_vec_t *parsed_global_subrs_,
440 		       parsed_cs_str_vec_t *parsed_local_subrs_,
441 		       hb_set_t *global_closure_,
442 		       hb_set_t *local_closure_,
443 		       bool drop_hints_) :
444       current_parsed_str (parsed_charstring_),
445       parsed_charstring (parsed_charstring_),
446       parsed_global_subrs (parsed_global_subrs_),
447       parsed_local_subrs (parsed_local_subrs_),
448       global_closure (global_closure_),
449       local_closure (local_closure_),
450       drop_hints (drop_hints_) {}
451 
get_parsed_str_for_contextCFF::subr_subset_param_t452   parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context)
453   {
454     switch (context.type)
455     {
456       case CSType_CharString:
457 	return parsed_charstring;
458 
459       case CSType_LocalSubr:
460 	if (likely (context.subr_num < parsed_local_subrs->length))
461 	  return &(*parsed_local_subrs)[context.subr_num];
462 	break;
463 
464       case CSType_GlobalSubr:
465 	if (likely (context.subr_num < parsed_global_subrs->length))
466 	  return &(*parsed_global_subrs)[context.subr_num];
467 	break;
468     }
469     return nullptr;
470   }
471 
472   template <typename ENV>
set_current_strCFF::subr_subset_param_t473   void set_current_str (ENV &env, bool calling)
474   {
475     parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context);
476     if (unlikely (!parsed_str))
477     {
478       env.set_error ();
479       return;
480     }
481     /* If the called subroutine is parsed partially but not completely yet,
482      * it must be because we are calling it recursively.
483      * Handle it as an error. */
484     if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
485       env.set_error ();
486     else
487     {
488       if (!parsed_str->is_parsed ())
489         parsed_str->alloc (env.str_ref.total_size () / 2);
490       current_parsed_str = parsed_str;
491     }
492   }
493 
494   parsed_cs_str_t	*current_parsed_str;
495 
496   parsed_cs_str_t	*parsed_charstring;
497   parsed_cs_str_vec_t	*parsed_global_subrs;
498   parsed_cs_str_vec_t	*parsed_local_subrs;
499   hb_set_t      *global_closure;
500   hb_set_t      *local_closure;
501   bool	  drop_hints;
502 };
503 
504 struct subr_remap_t : hb_inc_bimap_t
505 {
createCFF::subr_remap_t506   void create (const hb_set_t *closure)
507   {
508     /* create a remapping of subroutine numbers from old to new.
509      * no optimization based on usage counts. fonttools doesn't appear doing that either.
510      */
511 
512     resize (closure->get_population ());
513     hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
514     while (hb_set_next (closure, &old_num))
515       add (old_num);
516 
517     if (get_population () < 1240)
518       bias = 107;
519     else if (get_population () < 33900)
520       bias = 1131;
521     else
522       bias = 32768;
523   }
524 
biased_numCFF::subr_remap_t525   int biased_num (unsigned int old_num) const
526   {
527     hb_codepoint_t new_num = get (old_num);
528     return (int)new_num - bias;
529   }
530 
531   protected:
532   int bias;
533 };
534 
535 struct subr_remaps_t
536 {
subr_remaps_tCFF::subr_remaps_t537   subr_remaps_t (unsigned int fdCount)
538   {
539     local_remaps.resize (fdCount);
540   }
541 
in_errorCFF::subr_remaps_t542   bool in_error()
543   {
544     return local_remaps.in_error ();
545   }
546 
createCFF::subr_remaps_t547   void create (subr_closures_t& closures)
548   {
549     global_remap.create (&closures.global_closure);
550     for (unsigned int i = 0; i < local_remaps.length; i++)
551       local_remaps.arrayZ[i].create (&closures.local_closures[i]);
552   }
553 
554   subr_remap_t	       global_remap;
555   hb_vector_t<subr_remap_t>  local_remaps;
556 };
557 
558 template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
559 struct subr_subsetter_t
560 {
subr_subsetter_tCFF::subr_subsetter_t561   subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
562       : acc (acc_), plan (plan_), closures(acc_.fdCount),
563         remaps(acc_.fdCount)
564   {}
565 
566   /* Subroutine subsetting with --no-desubroutinize runs in phases:
567    *
568    * 1. execute charstrings/subroutines to determine subroutine closures
569    * 2. parse out all operators and numbers
570    * 3. mark hint operators and operands for removal if --no-hinting
571    * 4. re-encode all charstrings and subroutines with new subroutine numbers
572    *
573    * Phases #1 and #2 are done at the same time in collect_subrs ().
574    * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required),
575    * because we can't tell if a number belongs to a hint op until we see the first moveto.
576    *
577    * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
578    * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
579    */
subsetCFF::subr_subsetter_t580   bool subset (void)
581   {
582     unsigned fd_count = acc.fdCount;
583     const cff_subset_accelerator_t* cff_accelerator = nullptr;
584     if (plan->accelerator && plan->accelerator->cff_accelerator) {
585       cff_accelerator = plan->accelerator->cff_accelerator;
586       fd_count = cff_accelerator->parsed_local_subrs.length;
587     }
588 
589     if (cff_accelerator) {
590       // If we are not dropping hinting then charstrings are not modified so we can
591       // just use a reference to the cached copies.
592       cached_charstrings.resize (plan->num_output_glyphs ());
593       parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
594       parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
595     } else {
596       parsed_charstrings.resize (plan->num_output_glyphs ());
597       parsed_global_subrs_storage.resize (acc.globalSubrs->count);
598 
599       if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) return false;
600 
601       for (unsigned int i = 0; i < acc.fdCount; i++)
602       {
603         unsigned count = acc.privateDicts[i].localSubrs->count;
604         parsed_local_subrs_storage[i].resize (count);
605         if (unlikely (parsed_local_subrs_storage[i].in_error ())) return false;
606       }
607 
608       parsed_global_subrs = &parsed_global_subrs_storage;
609       parsed_local_subrs = &parsed_local_subrs_storage;
610     }
611 
612     if (unlikely (remaps.in_error()
613                   || cached_charstrings.in_error ()
614                   || parsed_charstrings.in_error ()
615                   || parsed_global_subrs->in_error ()
616                   || closures.in_error ())) {
617       return false;
618     }
619 
620     /* phase 1 & 2 */
621     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
622     {
623       hb_codepoint_t  glyph;
624       if (!plan->old_gid_for_new_gid (i, &glyph))
625         continue;
626 
627       const hb_ubytes_t str = (*acc.charStrings)[glyph];
628       unsigned int fd = acc.fdSelect->get_fd (glyph);
629       if (unlikely (fd >= acc.fdCount))
630         return false;
631 
632       if (cff_accelerator)
633       {
634         // parsed string already exists in accelerator, copy it and move
635         // on.
636         if (cached_charstrings)
637           cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph];
638         else
639           parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph];
640 
641         continue;
642       }
643 
644       ENV env (str, acc, fd);
645       cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
646 
647       parsed_charstrings[i].alloc (str.length / 2);
648       subr_subset_param_t  param (&parsed_charstrings[i],
649                                   &parsed_global_subrs_storage,
650                                   &parsed_local_subrs_storage[fd],
651                                   &closures.global_closure,
652                                   &closures.local_closures[fd],
653                                   plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
654 
655       if (unlikely (!interp.interpret (param)))
656         return false;
657 
658       /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
659       SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
660     }
661 
662     // Since parsed strings were loaded from accelerator, we still need
663     // to compute the subroutine closures which would have normally happened during
664     // parsing.
665     if (cff_accelerator &&
666         !closure_subroutines(*parsed_global_subrs,
667                              *parsed_local_subrs))
668       return false;
669 
670     if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING && !cff_accelerator) ||
671 	plan->inprogress_accelerator)
672     {
673       /* mark hint ops and arguments for drop */
674       for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
675       {
676 	hb_codepoint_t  glyph;
677 	if (!plan->old_gid_for_new_gid (i, &glyph))
678 	  continue;
679 	unsigned int fd = acc.fdSelect->get_fd (glyph);
680 	if (unlikely (fd >= acc.fdCount))
681 	  return false;
682 	subr_subset_param_t  param (&parsed_charstrings[i],
683 				    &parsed_global_subrs_storage,
684 				    &parsed_local_subrs_storage[fd],
685 				    &closures.global_closure,
686 				    &closures.local_closures[fd],
687 				    plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
688 
689 	drop_hints_param_t  drop;
690 	if (drop_hints_in_str (parsed_charstrings[i], param, drop))
691 	{
692 	  parsed_charstrings[i].set_hint_dropped ();
693 	  if (drop.vsindex_dropped)
694 	    parsed_charstrings[i].set_vsindex_dropped ();
695 	}
696       }
697 
698       /* after dropping hints recreate closures of actually used subrs */
699       if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING &&
700 	  !cff_accelerator &&
701 	  !closure_subroutines(*parsed_global_subrs, *parsed_local_subrs)) return false;
702     }
703 
704     remaps.create (closures);
705 
706     populate_subset_accelerator ();
707     return true;
708   }
709 
encode_charstringsCFF::subr_subsetter_t710   bool encode_charstrings (str_buff_vec_t &buffArray) const
711   {
712     if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
713       return false;
714     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
715     {
716       hb_codepoint_t  glyph;
717       if (!plan->old_gid_for_new_gid (i, &glyph))
718       {
719 	/* add an endchar only charstring for a missing glyph if CFF1 */
720 	if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op);
721 	continue;
722       }
723       unsigned int  fd = acc.fdSelect->get_fd (glyph);
724       if (unlikely (fd >= acc.fdCount))
725 	return false;
726       if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i])))
727 	return false;
728     }
729     return true;
730   }
731 
encode_subrsCFF::subr_subsetter_t732   bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const
733   {
734     unsigned int  count = remap.get_population ();
735 
736     if (unlikely (!buffArray.resize (count)))
737       return false;
738     for (unsigned int new_num = 0; new_num < count; new_num++)
739     {
740       hb_codepoint_t old_num = remap.backward (new_num);
741       assert (old_num != CFF_UNDEF_CODE);
742 
743       if (unlikely (!encode_str (subrs[old_num], fd, buffArray[new_num])))
744 	return false;
745     }
746     return true;
747   }
748 
encode_globalsubrsCFF::subr_subsetter_t749   bool encode_globalsubrs (str_buff_vec_t &buffArray)
750   {
751     return encode_subrs (*parsed_global_subrs, remaps.global_remap, 0, buffArray);
752   }
753 
encode_localsubrsCFF::subr_subsetter_t754   bool encode_localsubrs (unsigned int fd, str_buff_vec_t &buffArray) const
755   {
756     return encode_subrs ((*parsed_local_subrs)[fd], remaps.local_remaps[fd], fd, buffArray);
757   }
758 
759   protected:
760   struct drop_hints_param_t
761   {
drop_hints_param_tCFF::subr_subsetter_t::drop_hints_param_t762     drop_hints_param_t ()
763       : seen_moveto (false),
764 	ends_in_hint (false),
765 	all_dropped (false),
766 	vsindex_dropped (false) {}
767 
768     bool  seen_moveto;
769     bool  ends_in_hint;
770     bool  all_dropped;
771     bool  vsindex_dropped;
772   };
773 
drop_hints_in_subrCFF::subr_subsetter_t774   bool drop_hints_in_subr (parsed_cs_str_t &str, unsigned int pos,
775 			   parsed_cs_str_vec_t &subrs, unsigned int subr_num,
776 			   const subr_subset_param_t &param, drop_hints_param_t &drop)
777   {
778     drop.ends_in_hint = false;
779     bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
780 
781     /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
782      * then this entire subroutine must be a hint. drop its call. */
783     if (drop.ends_in_hint)
784     {
785       str.values[pos].set_hinting ();
786       /* if this subr call is at the end of the parent subr, propagate the flag
787        * otherwise reset the flag */
788       if (!str.at_end (pos))
789 	drop.ends_in_hint = false;
790     }
791     else if (drop.all_dropped)
792     {
793       str.values[pos].set_hinting ();
794     }
795 
796     return has_hint;
797   }
798 
799   /* returns true if it sees a hint op before the first moveto */
drop_hints_in_strCFF::subr_subsetter_t800   bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t &param, drop_hints_param_t &drop)
801   {
802     bool  seen_hint = false;
803 
804     unsigned count = str.values.length;
805     auto *values = str.values.arrayZ;
806     for (unsigned int pos = 0; pos < count; pos++)
807     {
808       bool  has_hint = false;
809       switch (values[pos].op)
810       {
811 	case OpCode_callsubr:
812 	  has_hint = drop_hints_in_subr (str, pos,
813 					*param.parsed_local_subrs, values[pos].subr_num,
814 					param, drop);
815 	  break;
816 
817 	case OpCode_callgsubr:
818 	  has_hint = drop_hints_in_subr (str, pos,
819 					*param.parsed_global_subrs, values[pos].subr_num,
820 					param, drop);
821 	  break;
822 
823 	case OpCode_rmoveto:
824 	case OpCode_hmoveto:
825 	case OpCode_vmoveto:
826 	  drop.seen_moveto = true;
827 	  break;
828 
829 	case OpCode_hintmask:
830 	case OpCode_cntrmask:
831 	  if (drop.seen_moveto)
832 	  {
833 	    values[pos].set_hinting ();
834 	    break;
835 	  }
836 	  HB_FALLTHROUGH;
837 
838 	case OpCode_hstemhm:
839 	case OpCode_vstemhm:
840 	case OpCode_hstem:
841 	case OpCode_vstem:
842 	  has_hint = true;
843 	  values[pos].set_hinting ();
844 	  if (str.at_end (pos))
845 	    drop.ends_in_hint = true;
846 	  break;
847 
848 	case OpCode_dotsection:
849 	  values[pos].set_hinting ();
850 	  break;
851 
852 	default:
853 	  /* NONE */
854 	  break;
855       }
856       if (has_hint)
857       {
858 	for (int i = pos - 1; i >= 0; i--)
859 	{
860 	  parsed_cs_op_t  &csop = values[(unsigned)i];
861 	  if (csop.is_hinting ())
862 	    break;
863 	  csop.set_hinting ();
864 	  if (csop.op == OpCode_vsindexcs)
865 	    drop.vsindex_dropped = true;
866 	}
867 	seen_hint |= has_hint;
868       }
869     }
870 
871     /* Raise all_dropped flag if all operators except return are dropped from a subr.
872      * It may happen even after seeing the first moveto if a subr contains
873      * only (usually one) hintmask operator, then calls to this subr can be dropped.
874      */
875     drop.all_dropped = true;
876     for (unsigned int pos = 0; pos < count; pos++)
877     {
878       parsed_cs_op_t  &csop = values[pos];
879       if (csop.op == OpCode_return)
880 	break;
881       if (!csop.is_hinting ())
882       {
883 	drop.all_dropped = false;
884 	break;
885       }
886     }
887 
888     return seen_hint;
889   }
890 
closure_subroutinesCFF::subr_subsetter_t891   bool closure_subroutines (const parsed_cs_str_vec_t& global_subrs,
892                             const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
893   {
894     closures.reset ();
895     for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
896     {
897       hb_codepoint_t  glyph;
898       if (!plan->old_gid_for_new_gid (i, &glyph))
899         continue;
900       unsigned int fd = acc.fdSelect->get_fd (glyph);
901       if (unlikely (fd >= acc.fdCount))
902         return false;
903 
904       // Note: const cast is safe here because the collect_subr_refs_in_str only performs a
905       //       closure and does not modify any of the charstrings.
906       subr_subset_param_t  param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)),
907                                   const_cast<parsed_cs_str_vec_t*> (&global_subrs),
908                                   const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
909                                   &closures.global_closure,
910                                   &closures.local_closures[fd],
911                                   plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
912       collect_subr_refs_in_str (get_parsed_charstring (i), param);
913     }
914 
915     return true;
916   }
917 
collect_subr_refs_in_subrCFF::subr_subsetter_t918   void collect_subr_refs_in_subr (unsigned int subr_num, parsed_cs_str_vec_t &subrs,
919 				  hb_set_t *closure,
920 				  const subr_subset_param_t &param)
921   {
922     if (closure->has (subr_num))
923       return;
924     closure->add (subr_num);
925     collect_subr_refs_in_str (subrs[subr_num], param);
926   }
927 
collect_subr_refs_in_strCFF::subr_subsetter_t928   void collect_subr_refs_in_str (const parsed_cs_str_t &str,
929                                  const subr_subset_param_t &param)
930   {
931     if (!str.has_calls ())
932       return;
933 
934     for (auto &opstr : str.values)
935     {
936       if (!param.drop_hints || !opstr.is_hinting ())
937       {
938 	switch (opstr.op)
939 	{
940 	  case OpCode_callsubr:
941 	    collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_local_subrs,
942 				       param.local_closure, param);
943 	    break;
944 
945 	  case OpCode_callgsubr:
946 	    collect_subr_refs_in_subr (opstr.subr_num, *param.parsed_global_subrs,
947 				       param.global_closure, param);
948 	    break;
949 
950 	  default: break;
951 	}
952       }
953     }
954   }
955 
encode_strCFF::subr_subsetter_t956   bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const
957   {
958     str_encoder_t  encoder (buff);
959     encoder.reset ();
960     bool hinting = !(plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
961     /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
962      * re-insert it at the beginning of charstreing */
963     if (str.has_prefix () && !hinting && str.is_hint_dropped ())
964     {
965       encoder.encode_num (str.prefix_num ());
966       if (str.prefix_op () != OpCode_Invalid)
967 	encoder.encode_op (str.prefix_op ());
968     }
969 
970     unsigned size = 0;
971     for (auto &opstr : str.values)
972     {
973       size += opstr.length;
974       if (opstr.op == OpCode_callsubr || opstr.op == OpCode_callgsubr)
975         size += 3;
976     }
977     if (!buff.alloc (buff.length + size))
978       return false;
979 
980     for (auto &opstr : str.values)
981     {
982       if (hinting || !opstr.is_hinting ())
983       {
984 	switch (opstr.op)
985 	{
986 	  case OpCode_callsubr:
987 	    encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
988 	    encoder.copy_str (opstr.ptr, opstr.length);
989 	    break;
990 
991 	  case OpCode_callgsubr:
992 	    encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
993 	    encoder.copy_str (opstr.ptr, opstr.length);
994 	    break;
995 
996 	  default:
997 	    encoder.copy_str (opstr.ptr, opstr.length);
998 	    break;
999 	}
1000       }
1001     }
1002     return !encoder.in_error ();
1003   }
1004 
compact_parsed_stringsCFF::subr_subsetter_t1005   void compact_parsed_strings () const
1006   {
1007     for (auto &cs : parsed_charstrings)
1008       compact_string (cs);
1009     for (auto &cs : parsed_global_subrs_storage)
1010       compact_string (cs);
1011     for (auto &vec : parsed_local_subrs_storage)
1012       for (auto &cs : vec)
1013 	compact_string (cs);
1014   }
1015 
compact_stringCFF::subr_subsetter_t1016   static void compact_string (parsed_cs_str_t &str)
1017   {
1018     unsigned count = str.values.length;
1019     if (unlikely (!count)) return;
1020     auto &opstr = str.values.arrayZ;
1021     unsigned j = 0;
1022     for (unsigned i = 1; i < count; i++)
1023     {
1024       /* See if we can combine op j and op i. */
1025       bool combine =
1026         (opstr[j].op != OpCode_callsubr && opstr[j].op != OpCode_callgsubr) &&
1027         (opstr[i].op != OpCode_callsubr && opstr[i].op != OpCode_callgsubr) &&
1028         (opstr[j].is_hinting () == opstr[i].is_hinting ()) &&
1029         (opstr[j].ptr + opstr[j].length == opstr[i].ptr) &&
1030         (opstr[j].length + opstr[i].length <= 255);
1031 
1032       if (combine)
1033       {
1034 	opstr[j].length += opstr[i].length;
1035 	opstr[j].op = OpCode_Invalid;
1036       }
1037       else
1038       {
1039 	opstr[++j] = opstr[i];
1040       }
1041     }
1042     str.values.shrink (j + 1);
1043   }
1044 
populate_subset_acceleratorCFF::subr_subsetter_t1045   void populate_subset_accelerator () const
1046   {
1047     if (!plan->inprogress_accelerator) return;
1048 
1049     compact_parsed_strings ();
1050 
1051     plan->inprogress_accelerator->cff_accelerator =
1052         cff_subset_accelerator_t::create(acc.blob,
1053                                          parsed_charstrings,
1054                                          parsed_global_subrs_storage,
1055                                          parsed_local_subrs_storage);
1056     plan->inprogress_accelerator->destroy_cff_accelerator =
1057         cff_subset_accelerator_t::destroy;
1058 
1059   }
1060 
get_parsed_charstringCFF::subr_subsetter_t1061   const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
1062   {
1063     if (cached_charstrings) return *(cached_charstrings[i]);
1064     return parsed_charstrings[i];
1065   }
1066 
1067   protected:
1068   const ACC			&acc;
1069   const hb_subset_plan_t	*plan;
1070 
1071   subr_closures_t		closures;
1072 
1073   hb_vector_t<const parsed_cs_str_t*>     cached_charstrings;
1074   const parsed_cs_str_vec_t*              parsed_global_subrs;
1075   const hb_vector_t<parsed_cs_str_vec_t>* parsed_local_subrs;
1076 
1077   subr_remaps_t			remaps;
1078 
1079   private:
1080 
1081   parsed_cs_str_vec_t		parsed_charstrings;
1082   parsed_cs_str_vec_t		parsed_global_subrs_storage;
1083   hb_vector_t<parsed_cs_str_vec_t>  parsed_local_subrs_storage;
1084   typedef typename SUBRS::count_type subr_count_type;
1085 };
1086 
1087 } /* namespace CFF */
1088 
1089 HB_INTERNAL bool
1090 hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
1091 			    unsigned int fdCount,
1092 			    const CFF::FDSelect &src, /* IN */
1093 			    unsigned int &subset_fd_count /* OUT */,
1094 			    unsigned int &subset_fdselect_size /* OUT */,
1095 			    unsigned int &subset_fdselect_format /* OUT */,
1096 			    hb_vector_t<CFF::code_pair_t> &fdselect_ranges /* OUT */,
1097 			    hb_inc_bimap_t &fdmap /* OUT */);
1098 
1099 HB_INTERNAL bool
1100 hb_serialize_cff_fdselect (hb_serialize_context_t *c,
1101 			  unsigned int num_glyphs,
1102 			  const CFF::FDSelect &src,
1103 			  unsigned int fd_count,
1104 			  unsigned int fdselect_format,
1105 			  unsigned int size,
1106 			  const hb_vector_t<CFF::code_pair_t> &fdselect_ranges);
1107 
1108 #endif /* HB_SUBSET_CFF_COMMON_HH */
1109