• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018  Google, 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  * Google Author(s): Garret Rieger, Roderick Sheeter
25  */
26 
27 #include "hb-subset-plan.hh"
28 #include "hb-subset-accelerator.hh"
29 #include "hb-map.hh"
30 #include "hb-multimap.hh"
31 #include "hb-set.hh"
32 
33 #include "hb-ot-cmap-table.hh"
34 #include "hb-ot-glyf-table.hh"
35 #include "hb-ot-layout-gdef-table.hh"
36 #include "hb-ot-layout-gpos-table.hh"
37 #include "hb-ot-layout-gsub-table.hh"
38 #include "hb-ot-cff1-table.hh"
39 #include "hb-ot-cff2-table.hh"
40 #include "OT/Color/COLR/COLR.hh"
41 #include "OT/Color/COLR/colrv1-closure.hh"
42 #include "OT/Color/CPAL/CPAL.hh"
43 #include "hb-ot-var-fvar-table.hh"
44 #include "hb-ot-var-avar-table.hh"
45 #include "hb-ot-stat-table.hh"
46 #include "hb-ot-math-table.hh"
47 
48 using OT::Layout::GSUB;
49 using OT::Layout::GPOS;
50 
51 
~hb_subset_accelerator_t()52 hb_subset_accelerator_t::~hb_subset_accelerator_t ()
53 {
54   if (cmap_cache && destroy_cmap_cache)
55     destroy_cmap_cache ((void*) cmap_cache);
56 
57 #ifndef HB_NO_SUBSET_CFF
58   cff1_accel.fini ();
59   cff2_accel.fini ();
60 #endif
61   hb_face_destroy (source);
62 }
63 
64 
65 typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
66 #ifndef HB_NO_SUBSET_CFF
67 static inline bool
_add_cff_seac_components(const OT::cff1::accelerator_subset_t & cff,hb_codepoint_t gid,hb_set_t * gids_to_retain)68 _add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
69 			  hb_codepoint_t gid,
70 			  hb_set_t *gids_to_retain)
71 {
72   hb_codepoint_t base_gid, accent_gid;
73   if (cff.get_seac_components (gid, &base_gid, &accent_gid))
74   {
75     gids_to_retain->add (base_gid);
76     gids_to_retain->add (accent_gid);
77     return true;
78   }
79   return false;
80 }
81 #endif
82 
83 static void
_remap_palette_indexes(const hb_set_t * palette_indexes,hb_map_t * mapping)84 _remap_palette_indexes (const hb_set_t *palette_indexes,
85 			hb_map_t       *mapping /* OUT */)
86 {
87   unsigned new_idx = 0;
88   for (unsigned palette_index : palette_indexes->iter ())
89   {
90     if (palette_index == 0xFFFF)
91     {
92       mapping->set (palette_index, palette_index);
93       continue;
94     }
95     mapping->set (palette_index, new_idx);
96     new_idx++;
97   }
98 }
99 
100 static void
_remap_indexes(const hb_set_t * indexes,hb_map_t * mapping)101 _remap_indexes (const hb_set_t *indexes,
102 		hb_map_t       *mapping /* OUT */)
103 {
104   for (auto _ : + hb_enumerate (indexes->iter ()))
105     mapping->set (_.second, _.first);
106 
107 }
108 
109 #ifndef HB_NO_SUBSET_LAYOUT
110 
111 /*
112  * Removes all tags from 'tags' that are not in filter. Additionally eliminates any duplicates.
113  * Returns true if anything was removed (not including duplicates).
114  */
_filter_tag_list(hb_vector_t<hb_tag_t> * tags,const hb_set_t * filter)115 static bool _filter_tag_list(hb_vector_t<hb_tag_t>* tags, /* IN/OUT */
116                              const hb_set_t* filter)
117 {
118   hb_vector_t<hb_tag_t> out;
119   out.alloc (tags->get_size() + 1); // +1 is to allocate room for the null terminator.
120 
121   bool removed = false;
122   hb_set_t visited;
123 
124   for (hb_tag_t tag : *tags)
125   {
126     if (!tag) continue;
127     if (visited.has (tag)) continue;
128 
129     if (!filter->has (tag))
130     {
131       removed = true;
132       continue;
133     }
134 
135     visited.add (tag);
136     out.push (tag);
137   }
138 
139   // The collect function needs a null element to signal end of the array.
140   out.push (HB_TAG_NONE);
141 
142   hb_swap (out, *tags);
143   return removed;
144 }
145 
146 template <typename T>
_collect_layout_indices(hb_subset_plan_t * plan,const T & table,hb_set_t * lookup_indices,hb_set_t * feature_indices,hb_hashmap_t<unsigned,hb::shared_ptr<hb_set_t>> * feature_record_cond_idx_map,hb_hashmap_t<unsigned,const OT::Feature * > * feature_substitutes_map,bool & insert_catch_all_feature_variation_record)147 static void _collect_layout_indices (hb_subset_plan_t     *plan,
148                                      const T&              table,
149                                      hb_set_t		  *lookup_indices, /* OUT */
150                                      hb_set_t		  *feature_indices, /* OUT */
151                                      hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
152                                      hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
153                                      bool& insert_catch_all_feature_variation_record)
154 {
155   unsigned num_features = table.get_feature_count ();
156   hb_vector_t<hb_tag_t> features;
157   if (!plan->check_success (features.resize (num_features))) return;
158   table.get_feature_tags (0, &num_features, features.arrayZ);
159   bool retain_all_features = !_filter_tag_list (&features, &plan->layout_features);
160 
161   unsigned num_scripts = table.get_script_count ();
162   hb_vector_t<hb_tag_t> scripts;
163   if (!plan->check_success (scripts.resize (num_scripts))) return;
164   table.get_script_tags (0, &num_scripts, scripts.arrayZ);
165   bool retain_all_scripts = !_filter_tag_list (&scripts, &plan->layout_scripts);
166 
167   if (!plan->check_success (!features.in_error ()) || !features
168       || !plan->check_success (!scripts.in_error ()) || !scripts)
169     return;
170 
171   hb_ot_layout_collect_features (plan->source,
172                                  T::tableTag,
173                                  retain_all_scripts ? nullptr : scripts.arrayZ,
174                                  nullptr,
175                                  retain_all_features ? nullptr : features.arrayZ,
176                                  feature_indices);
177 
178 #ifndef HB_NO_VAR
179   // collect feature substitutes with variations
180   if (!plan->user_axes_location.is_empty ())
181   {
182     hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
183     OT::hb_collect_feature_substitutes_with_var_context_t c =
184     {
185       &plan->axes_old_index_tag_map,
186       &plan->axes_location,
187       feature_record_cond_idx_map,
188       feature_substitutes_map,
189       insert_catch_all_feature_variation_record,
190       feature_indices,
191       false,
192       false,
193       false,
194       0,
195       &conditionset_map
196     };
197     table.collect_feature_substitutes_with_variations (&c);
198   }
199 #endif
200 
201   for (unsigned feature_index : *feature_indices)
202   {
203     const OT::Feature* f = &(table.get_feature (feature_index));
204     const OT::Feature **p = nullptr;
205     if (feature_substitutes_map->has (feature_index, &p))
206       f = *p;
207 
208     f->add_lookup_indexes_to (lookup_indices);
209   }
210 
211   // If all axes are pinned then all feature variations will be dropped so there's no need
212   // to collect lookups from them.
213   if (!plan->all_axes_pinned)
214   {
215     // TODO(qxliu76): this collection doesn't work correctly for feature variations that are dropped
216     //                but not applied. The collection will collect and retain the lookup indices
217     //                associated with those dropped but not activated rules. Since partial instancing
218     //                isn't yet supported this isn't an issue yet but will need to be fixed for
219     //                partial instancing.
220     table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
221   }
222 }
223 
224 
225 static inline void
_GSUBGPOS_find_duplicate_features(const OT::GSUBGPOS & g,const hb_map_t * lookup_indices,const hb_set_t * feature_indices,const hb_hashmap_t<unsigned,const OT::Feature * > * feature_substitutes_map,hb_map_t * duplicate_feature_map)226 _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
227 				   const hb_map_t *lookup_indices,
228 				   const hb_set_t *feature_indices,
229 				   const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
230 				   hb_map_t *duplicate_feature_map /* OUT */)
231 {
232   if (feature_indices->is_empty ()) return;
233   hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features;
234   //find out duplicate features after subset
235   for (unsigned i : feature_indices->iter ())
236   {
237     hb_tag_t t = g.get_feature_tag (i);
238     if (t == HB_MAP_VALUE_INVALID) continue;
239     if (!unique_features.has (t))
240     {
241       if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
242 	return;
243       if (unique_features.has (t))
244 	unique_features.get (t)->add (i);
245       duplicate_feature_map->set (i, i);
246       continue;
247     }
248 
249     bool found = false;
250 
251     hb_set_t* same_tag_features = unique_features.get (t);
252     for (unsigned other_f_index : same_tag_features->iter ())
253     {
254       const OT::Feature* f = &(g.get_feature (i));
255       const OT::Feature **p = nullptr;
256       if (feature_substitutes_map->has (i, &p))
257         f = *p;
258 
259       const OT::Feature* other_f = &(g.get_feature (other_f_index));
260       if (feature_substitutes_map->has (other_f_index, &p))
261         other_f = *p;
262 
263       auto f_iter =
264       + hb_iter (f->lookupIndex)
265       | hb_filter (lookup_indices)
266       ;
267 
268       auto other_f_iter =
269       + hb_iter (other_f->lookupIndex)
270       | hb_filter (lookup_indices)
271       ;
272 
273       bool is_equal = true;
274       for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
275       {
276 	unsigned a = *f_iter;
277 	unsigned b = *other_f_iter;
278 	if (a != b) { is_equal = false; break; }
279       }
280 
281       if (is_equal == false || f_iter || other_f_iter) continue;
282 
283       found = true;
284       duplicate_feature_map->set (i, other_f_index);
285       break;
286     }
287 
288     if (found == false)
289     {
290       same_tag_features->add (i);
291       duplicate_feature_map->set (i, i);
292     }
293   }
294 }
295 
296 template <typename T>
297 static inline void
_closure_glyphs_lookups_features(hb_subset_plan_t * plan,hb_set_t * gids_to_retain,hb_map_t * lookups,hb_map_t * features,script_langsys_map * langsys_map,hb_hashmap_t<unsigned,hb::shared_ptr<hb_set_t>> * feature_record_cond_idx_map,hb_hashmap_t<unsigned,const OT::Feature * > * feature_substitutes_map,bool & insert_catch_all_feature_variation_record)298 _closure_glyphs_lookups_features (hb_subset_plan_t   *plan,
299 				  hb_set_t	     *gids_to_retain,
300 				  hb_map_t	     *lookups,
301 				  hb_map_t	     *features,
302 				  script_langsys_map *langsys_map,
303 				  hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
304 				  hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
305 				  bool& insert_catch_all_feature_variation_record)
306 {
307   hb_blob_ptr_t<T> table = plan->source_table<T> ();
308   hb_tag_t table_tag = table->tableTag;
309   hb_set_t lookup_indices, feature_indices;
310   _collect_layout_indices<T> (plan,
311                               *table,
312                               &lookup_indices,
313                               &feature_indices,
314                               feature_record_cond_idx_map,
315                               feature_substitutes_map,
316                               insert_catch_all_feature_variation_record);
317 
318   if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
319     hb_ot_layout_lookups_substitute_closure (plan->source,
320                                              &lookup_indices,
321 					     gids_to_retain);
322   table->closure_lookups (plan->source,
323 			  gids_to_retain,
324                           &lookup_indices);
325   _remap_indexes (&lookup_indices, lookups);
326 
327   // prune features
328   table->prune_features (lookups,
329                          plan->user_axes_location.is_empty () ? nullptr : feature_record_cond_idx_map,
330                          feature_substitutes_map,
331                          &feature_indices);
332   hb_map_t duplicate_feature_map;
333   _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
334 
335   feature_indices.clear ();
336   table->prune_langsys (&duplicate_feature_map, &plan->layout_scripts, langsys_map, &feature_indices);
337   _remap_indexes (&feature_indices, features);
338 
339   table.destroy ();
340 }
341 
342 #endif
343 
344 #ifndef HB_NO_VAR
345 static inline void
_generate_varstore_inner_maps(const hb_set_t & varidx_set,unsigned subtable_count,hb_vector_t<hb_inc_bimap_t> & inner_maps)346 _generate_varstore_inner_maps (const hb_set_t& varidx_set,
347                                unsigned subtable_count,
348                                hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */)
349 {
350   if (varidx_set.is_empty () || subtable_count == 0) return;
351 
352   if (unlikely (!inner_maps.resize (subtable_count))) return;
353   for (unsigned idx : varidx_set)
354   {
355     uint16_t major = idx >> 16;
356     uint16_t minor = idx & 0xFFFF;
357 
358     if (major >= subtable_count)
359       continue;
360     inner_maps[major].add (minor);
361   }
362 }
363 
364 static inline hb_font_t*
_get_hb_font_with_variations(const hb_subset_plan_t * plan)365 _get_hb_font_with_variations (const hb_subset_plan_t *plan)
366 {
367   hb_font_t *font = hb_font_create (plan->source);
368 
369   hb_vector_t<hb_variation_t> vars;
370   if (!vars.alloc (plan->user_axes_location.get_population ())) {
371     hb_font_destroy (font);
372     return nullptr;
373   }
374 
375   for (auto _ : plan->user_axes_location)
376   {
377     hb_variation_t var;
378     var.tag = _.first;
379     var.value = _.second.middle;
380     vars.push (var);
381   }
382 
383 #ifndef HB_NO_VAR
384   hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
385 #endif
386   return font;
387 }
388 
389 static inline void
_collect_layout_variation_indices(hb_subset_plan_t * plan)390 _collect_layout_variation_indices (hb_subset_plan_t* plan)
391 {
392   hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
393   hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
394 
395   if (!gdef->has_data ())
396   {
397     gdef.destroy ();
398     gpos.destroy ();
399     return;
400   }
401 
402   hb_set_t varidx_set;
403   OT::hb_collect_variation_indices_context_t c (&varidx_set,
404                                                 &plan->_glyphset_gsub,
405                                                 &plan->gpos_lookups);
406   gdef->collect_variation_indices (&c);
407 
408   if (hb_ot_layout_has_positioning (plan->source))
409     gpos->collect_variation_indices (&c);
410 
411   gdef->remap_layout_variation_indices (&varidx_set,
412                                         plan->normalized_coords,
413                                         !plan->pinned_at_default,
414                                         plan->all_axes_pinned,
415                                         &plan->layout_variation_idx_delta_map);
416 
417   unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
418   _generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
419 
420   gdef.destroy ();
421   gpos.destroy ();
422 }
423 #endif
424 
425 static inline void
_cmap_closure(hb_face_t * face,const hb_set_t * unicodes,hb_set_t * glyphset)426 _cmap_closure (hb_face_t	   *face,
427 	       const hb_set_t	   *unicodes,
428 	       hb_set_t		   *glyphset)
429 {
430   OT::cmap::accelerator_t cmap (face);
431   cmap.table->closure_glyphs (unicodes, glyphset);
432 }
433 
_colr_closure(hb_face_t * face,hb_map_t * layers_map,hb_map_t * palettes_map,hb_set_t * glyphs_colred)434 static void _colr_closure (hb_face_t *face,
435                            hb_map_t *layers_map,
436                            hb_map_t *palettes_map,
437                            hb_set_t *glyphs_colred)
438 {
439   OT::COLR::accelerator_t colr (face);
440   if (!colr.is_valid ()) return;
441 
442   hb_set_t palette_indices, layer_indices;
443   // Collect all glyphs referenced by COLRv0
444   hb_set_t glyphset_colrv0;
445   for (hb_codepoint_t gid : *glyphs_colred)
446     colr.closure_glyphs (gid, &glyphset_colrv0);
447 
448   glyphs_colred->union_ (glyphset_colrv0);
449 
450   //closure for COLRv1
451   colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices);
452 
453   colr.closure_V0palette_indices (glyphs_colred, &palette_indices);
454   _remap_indexes (&layer_indices, layers_map);
455   _remap_palette_indexes (&palette_indices, palettes_map);
456 }
457 
458 static inline void
_math_closure(hb_subset_plan_t * plan,hb_set_t * glyphset)459 _math_closure (hb_subset_plan_t *plan,
460                hb_set_t         *glyphset)
461 {
462   hb_blob_ptr_t<OT::MATH> math = plan->source_table<OT::MATH> ();
463   if (math->has_data ())
464     math->closure_glyphs (glyphset);
465   math.destroy ();
466 }
467 
468 
469 static inline void
_remove_invalid_gids(hb_set_t * glyphs,unsigned int num_glyphs)470 _remove_invalid_gids (hb_set_t *glyphs,
471 		      unsigned int num_glyphs)
472 {
473   glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID);
474 }
475 
476 static void
_populate_unicodes_to_retain(const hb_set_t * unicodes,const hb_set_t * glyphs,hb_subset_plan_t * plan)477 _populate_unicodes_to_retain (const hb_set_t *unicodes,
478                               const hb_set_t *glyphs,
479                               hb_subset_plan_t *plan)
480 {
481   OT::cmap::accelerator_t cmap (plan->source);
482   unsigned size_threshold = plan->source->get_num_glyphs ();
483   if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
484   {
485 
486     const hb_map_t* unicode_to_gid = nullptr;
487     if (plan->accelerator)
488       unicode_to_gid = &plan->accelerator->unicode_to_gid;
489 
490     // This is approach to collection is faster, but can only be used  if glyphs
491     // are not being explicitly added to the subset and the input unicodes set is
492     // not excessively large (eg. an inverted set).
493     plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
494     if (!unicode_to_gid) {
495       for (hb_codepoint_t cp : *unicodes)
496       {
497         hb_codepoint_t gid;
498         if (!cmap.get_nominal_glyph (cp, &gid))
499         {
500           DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
501           continue;
502         }
503 
504         plan->codepoint_to_glyph->set (cp, gid);
505         plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
506       }
507     } else {
508       // Use in memory unicode to gid map it's faster then looking up from
509       // the map. This code is mostly duplicated from above to avoid doing
510       // conditionals on the presence of the unicode_to_gid map each
511       // iteration.
512       for (hb_codepoint_t cp : *unicodes)
513       {
514         hb_codepoint_t gid = unicode_to_gid->get (cp);
515         if (gid == HB_MAP_VALUE_INVALID)
516         {
517           DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
518           continue;
519         }
520 
521         plan->codepoint_to_glyph->set (cp, gid);
522         plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
523       }
524     }
525   }
526   else
527   {
528     // This approach is slower, but can handle adding in glyphs to the subset and will match
529     // them with cmap entries.
530 
531     hb_map_t unicode_glyphid_map_storage;
532     hb_set_t cmap_unicodes_storage;
533     const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
534     const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
535 
536     if (!plan->accelerator) {
537       cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
538       plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
539                                                   + glyphs->get_population (),
540                                                   cmap_unicodes->get_population ()));
541     } else {
542       unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
543       cmap_unicodes = &plan->accelerator->unicodes;
544     }
545 
546     if (plan->accelerator &&
547 	unicodes->get_population () < cmap_unicodes->get_population () &&
548 	glyphs->get_population () < cmap_unicodes->get_population ())
549     {
550       plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
551 
552       auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
553       for (hb_codepoint_t gid : *glyphs)
554       {
555         auto unicodes = gid_to_unicodes.get (gid);
556 
557 	for (hb_codepoint_t cp : unicodes)
558 	{
559 	  plan->codepoint_to_glyph->set (cp, gid);
560 	  plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
561 	}
562       }
563       for (hb_codepoint_t cp : *unicodes)
564       {
565 	/* Don't double-add entry. */
566 	if (plan->codepoint_to_glyph->has (cp))
567 	  continue;
568 
569         hb_codepoint_t *gid;
570         if (!unicode_glyphid_map->has(cp, &gid))
571           continue;
572 
573 	plan->codepoint_to_glyph->set (cp, *gid);
574 	plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
575       }
576       plan->unicode_to_new_gid_list.qsort ();
577     }
578     else
579     {
580       plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ());
581       for (hb_codepoint_t cp : *cmap_unicodes)
582       {
583 	hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
584 	if (!unicodes->has (cp) && !glyphs->has (gid))
585 	  continue;
586 
587 	plan->codepoint_to_glyph->set (cp, gid);
588 	plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
589       }
590     }
591 
592     /* Add gids which where requested, but not mapped in cmap */
593     unsigned num_glyphs = plan->source->get_num_glyphs ();
594     hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
595     for (; glyphs->next_range (&first, &last); )
596     {
597       if (first >= num_glyphs)
598 	break;
599       if (last >= num_glyphs)
600         last = num_glyphs - 1;
601       plan->_glyphset_gsub.add_range (first, last);
602     }
603   }
604 
605   auto &arr = plan->unicode_to_new_gid_list;
606   if (arr.length)
607   {
608     plan->unicodes.add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ));
609     plan->_glyphset_gsub.add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ));
610   }
611 }
612 
613 #ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
614 #define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64
615 #endif
616 
617 static unsigned
_glyf_add_gid_and_children(const OT::glyf_accelerator_t & glyf,hb_codepoint_t gid,hb_set_t * gids_to_retain,int operation_count,unsigned depth=0)618 _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
619 			    hb_codepoint_t gid,
620 			    hb_set_t *gids_to_retain,
621 			    int operation_count,
622 			    unsigned depth = 0)
623 {
624   /* Check if is already visited */
625   if (gids_to_retain->has (gid)) return operation_count;
626 
627   gids_to_retain->add (gid);
628 
629   if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
630   if (unlikely (--operation_count < 0)) return operation_count;
631 
632   auto glyph = glyf.glyph_for_gid (gid);
633 
634   for (auto &item : glyph.get_composite_iterator ())
635     operation_count =
636       _glyf_add_gid_and_children (glyf,
637 				  item.get_gid (),
638 				  gids_to_retain,
639 				  operation_count,
640 				  depth);
641 
642 #ifndef HB_NO_VAR_COMPOSITES
643   for (auto &item : glyph.get_var_composite_iterator ())
644    {
645     operation_count =
646       _glyf_add_gid_and_children (glyf,
647 				  item.get_gid (),
648 				  gids_to_retain,
649 				  operation_count,
650 				  depth);
651    }
652 #endif
653 
654   return operation_count;
655 }
656 
657 static void
_nameid_closure(hb_subset_plan_t * plan,hb_set_t * drop_tables)658 _nameid_closure (hb_subset_plan_t* plan,
659 		 hb_set_t* drop_tables)
660 {
661 #ifndef HB_NO_STYLE
662   plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
663 #endif
664 #ifndef HB_NO_VAR
665   if (!plan->all_axes_pinned)
666     plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids);
667 #endif
668 #ifndef HB_NO_COLOR
669   if (!drop_tables->has (HB_OT_TAG_CPAL))
670     plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
671 #endif
672 
673 #ifndef HB_NO_SUBSET_LAYOUT
674   if (!drop_tables->has (HB_OT_TAG_GPOS))
675   {
676     hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
677     gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
678     gpos.destroy ();
679   }
680   if (!drop_tables->has (HB_OT_TAG_GSUB))
681   {
682     hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
683     gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
684     gsub.destroy ();
685   }
686 #endif
687 }
688 
689 static void
_populate_gids_to_retain(hb_subset_plan_t * plan,hb_set_t * drop_tables)690 _populate_gids_to_retain (hb_subset_plan_t* plan,
691 		          hb_set_t* drop_tables)
692 {
693   OT::glyf_accelerator_t glyf (plan->source);
694 #ifndef HB_NO_SUBSET_CFF
695   // Note: we cannot use inprogress_accelerator here, since it has not been
696   // created yet. So in case of preprocessed-face (and otherwise), we do an
697   // extra sanitize pass here, which is not ideal.
698   OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source);
699   const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff);
700 #endif
701 
702   plan->_glyphset_gsub.add (0); // Not-def
703 
704   _cmap_closure (plan->source, &plan->unicodes, &plan->_glyphset_gsub);
705 
706 #ifndef HB_NO_SUBSET_LAYOUT
707   if (!drop_tables->has (HB_OT_TAG_GSUB))
708     // closure all glyphs/lookups/features needed for GSUB substitutions.
709     _closure_glyphs_lookups_features<GSUB> (
710         plan,
711         &plan->_glyphset_gsub,
712         &plan->gsub_lookups,
713         &plan->gsub_features,
714         &plan->gsub_langsys,
715         &plan->gsub_feature_record_cond_idx_map,
716         &plan->gsub_feature_substitutes_map,
717         plan->gsub_insert_catch_all_feature_variation_rec);
718 
719   if (!drop_tables->has (HB_OT_TAG_GPOS))
720     _closure_glyphs_lookups_features<GPOS> (
721         plan,
722         &plan->_glyphset_gsub,
723         &plan->gpos_lookups,
724         &plan->gpos_features,
725         &plan->gpos_langsys,
726         &plan->gpos_feature_record_cond_idx_map,
727         &plan->gpos_feature_substitutes_map,
728         plan->gpos_insert_catch_all_feature_variation_rec);
729 #endif
730   _remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
731 
732   plan->_glyphset_mathed = plan->_glyphset_gsub;
733   if (!drop_tables->has (HB_OT_TAG_MATH))
734   {
735     _math_closure (plan, &plan->_glyphset_mathed);
736     _remove_invalid_gids (&plan->_glyphset_mathed, plan->source->get_num_glyphs ());
737   }
738 
739   hb_set_t cur_glyphset = plan->_glyphset_mathed;
740   if (!drop_tables->has (HB_OT_TAG_COLR))
741   {
742     _colr_closure (plan->source, &plan->colrv1_layers, &plan->colr_palettes, &cur_glyphset);
743     _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
744   }
745 
746   plan->_glyphset_colred = cur_glyphset;
747 
748   _nameid_closure (plan, drop_tables);
749   /* Populate a full set of glyphs to retain by adding all referenced
750    * composite glyphs. */
751   if (glyf.has_data ())
752     for (hb_codepoint_t gid : cur_glyphset)
753       _glyf_add_gid_and_children (glyf, gid, &plan->_glyphset,
754 				  cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH);
755   else
756     plan->_glyphset.union_ (cur_glyphset);
757 #ifndef HB_NO_SUBSET_CFF
758   if (!plan->accelerator || plan->accelerator->has_seac)
759   {
760     bool has_seac = false;
761     if (cff->is_valid ())
762       for (hb_codepoint_t gid : cur_glyphset)
763 	if (_add_cff_seac_components (*cff, gid, &plan->_glyphset))
764 	  has_seac = true;
765     plan->has_seac = has_seac;
766   }
767 #endif
768 
769   _remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ());
770 
771 #ifndef HB_NO_VAR
772   if (!drop_tables->has (HB_OT_TAG_GDEF))
773     _collect_layout_variation_indices (plan);
774 #endif
775 }
776 
777 static void
_create_glyph_map_gsub(const hb_set_t * glyph_set_gsub,const hb_map_t * glyph_map,hb_map_t * out)778 _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
779                         const hb_map_t* glyph_map,
780                         hb_map_t* out)
781 {
782   out->alloc (glyph_set_gsub->get_population ());
783   + hb_iter (glyph_set_gsub)
784   | hb_map ([&] (hb_codepoint_t gid) {
785     return hb_codepoint_pair_t (gid, glyph_map->get (gid));
786   })
787   | hb_sink (out)
788   ;
789 }
790 
791 static bool
_create_old_gid_to_new_gid_map(const hb_face_t * face,bool retain_gids,const hb_set_t * all_gids_to_retain,const hb_map_t * requested_glyph_map,hb_map_t * glyph_map,hb_map_t * reverse_glyph_map,hb_sorted_vector_t<hb_codepoint_pair_t> * new_to_old_gid_list,unsigned int * num_glyphs)792 _create_old_gid_to_new_gid_map (const hb_face_t *face,
793 				bool		 retain_gids,
794 				const hb_set_t	*all_gids_to_retain,
795                                 const hb_map_t  *requested_glyph_map,
796 				hb_map_t	*glyph_map, /* OUT */
797 				hb_map_t	*reverse_glyph_map, /* OUT */
798 				hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */,
799 				unsigned int	*num_glyphs /* OUT */)
800 {
801   unsigned pop = all_gids_to_retain->get_population ();
802   reverse_glyph_map->alloc (pop);
803   glyph_map->alloc (pop);
804   new_to_old_gid_list->alloc (pop);
805 
806   if (*requested_glyph_map)
807   {
808     hb_set_t new_gids(requested_glyph_map->values());
809     if (new_gids.get_population() != requested_glyph_map->get_population())
810     {
811       DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique.");
812       return false;
813     }
814 
815     if (retain_gids)
816     {
817       DEBUG_MSG (SUBSET, nullptr,
818         "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if "
819         "a custom glyph mapping has been provided.");
820       return false;
821     }
822 
823     hb_codepoint_t max_glyph = 0;
824     hb_set_t remaining;
825     for (auto old_gid : all_gids_to_retain->iter ())
826     {
827       if (old_gid == 0) {
828 	new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u));
829         continue;
830       }
831 
832       hb_codepoint_t* new_gid;
833       if (!requested_glyph_map->has (old_gid, &new_gid))
834       {
835         remaining.add(old_gid);
836         continue;
837       }
838 
839       if (*new_gid > max_glyph)
840         max_glyph = *new_gid;
841       new_to_old_gid_list->push (hb_pair (*new_gid, old_gid));
842     }
843     new_to_old_gid_list->qsort ();
844 
845     // Anything that wasn't mapped by the requested mapping should
846     // be placed after the requested mapping.
847     for (auto old_gid : remaining)
848       new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid));
849 
850     *num_glyphs = max_glyph + 1;
851   }
852   else if (!retain_gids)
853   {
854     + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
855     | hb_sink (new_to_old_gid_list)
856     ;
857     *num_glyphs = new_to_old_gid_list->length;
858   }
859   else
860   {
861     + hb_iter (all_gids_to_retain)
862     | hb_map ([] (hb_codepoint_t _) {
863 		return hb_codepoint_pair_t (_, _);
864 	      })
865     | hb_sink (new_to_old_gid_list)
866     ;
867 
868     hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID;
869     hb_set_previous (all_gids_to_retain, &max_glyph);
870 
871     *num_glyphs = max_glyph + 1;
872   }
873 
874   + hb_iter (new_to_old_gid_list)
875   | hb_sink (reverse_glyph_map)
876   ;
877   + hb_iter (new_to_old_gid_list)
878   | hb_map (&hb_codepoint_pair_t::reverse)
879   | hb_sink (glyph_map)
880   ;
881 
882   return true;
883 }
884 
885 #ifndef HB_NO_VAR
886 static void
_normalize_axes_location(hb_face_t * face,hb_subset_plan_t * plan)887 _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
888 {
889   if (plan->user_axes_location.is_empty ())
890     return;
891 
892   hb_array_t<const OT::AxisRecord> axes = face->table.fvar->get_axes ();
893   plan->normalized_coords.resize (axes.length);
894 
895   bool has_avar = face->table.avar->has_data ();
896   const OT::SegmentMaps *seg_maps = nullptr;
897   unsigned avar_axis_count = 0;
898   if (has_avar)
899   {
900     seg_maps = face->table.avar->get_segment_maps ();
901     avar_axis_count = face->table.avar->get_axis_count();
902   }
903 
904   bool axis_not_pinned = false;
905   unsigned old_axis_idx = 0, new_axis_idx = 0;
906   for (const auto& axis : axes)
907   {
908     hb_tag_t axis_tag = axis.get_axis_tag ();
909     plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag);
910 
911     if (!plan->user_axes_location.has (axis_tag) ||
912         !plan->user_axes_location.get (axis_tag).is_point ())
913     {
914       axis_not_pinned = true;
915       plan->axes_index_map.set (old_axis_idx, new_axis_idx);
916       plan->axis_tags.push (axis_tag);
917       new_axis_idx++;
918     }
919 
920     Triple *axis_range;
921     if (plan->user_axes_location.has (axis_tag, &axis_range))
922     {
923       plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ());
924 
925       int normalized_min = axis.normalize_axis_value (axis_range->minimum);
926       int normalized_default = axis.normalize_axis_value (axis_range->middle);
927       int normalized_max = axis.normalize_axis_value (axis_range->maximum);
928 
929       if (has_avar && old_axis_idx < avar_axis_count)
930       {
931         normalized_min = seg_maps->map (normalized_min);
932         normalized_default = seg_maps->map (normalized_default);
933         normalized_max = seg_maps->map (normalized_max);
934       }
935       plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
936                                                  static_cast<float> (normalized_default / 16384.f),
937                                                  static_cast<float> (normalized_max / 16384.f)));
938 
939       if (normalized_default != 0)
940         plan->pinned_at_default = false;
941 
942       plan->normalized_coords[old_axis_idx] = normalized_default;
943     }
944 
945     old_axis_idx++;
946 
947     if (has_avar && old_axis_idx < avar_axis_count)
948       seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
949   }
950   plan->all_axes_pinned = !axis_not_pinned;
951 }
952 
953 static void
_update_instance_metrics_map_from_cff2(hb_subset_plan_t * plan)954 _update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
955 {
956   if (!plan->normalized_coords) return;
957   OT::cff2::accelerator_t cff2 (plan->source);
958   if (!cff2.is_valid ()) return;
959 
960   hb_font_t *font = nullptr;
961   if (unlikely (!plan->check_success (font = _get_hb_font_with_variations (plan))))
962   {
963     hb_font_destroy (font);
964     return;
965   }
966 
967   hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
968   OT::hmtx_accelerator_t _hmtx (plan->source);
969   float *hvar_store_cache = nullptr;
970   if (_hmtx.has_data () && _hmtx.var_table.get_length ())
971     hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
972 
973   OT::vmtx_accelerator_t _vmtx (plan->source);
974   float *vvar_store_cache = nullptr;
975   if (_vmtx.has_data () && _vmtx.var_table.get_length ())
976     vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
977 
978   for (auto p : *plan->glyph_map)
979   {
980     hb_codepoint_t old_gid = p.first;
981     hb_codepoint_t new_gid = p.second;
982     if (!cff2.get_extents (font, old_gid, &extents)) continue;
983     bool has_bounds_info = true;
984     if (extents.x_bearing == 0 && extents.width == 0 &&
985         extents.height == 0 && extents.y_bearing == 0)
986       has_bounds_info = false;
987 
988     if (has_bounds_info)
989     {
990       plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
991       plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
992       plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
993       plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
994     }
995 
996     if (_hmtx.has_data ())
997     {
998       int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
999       if (_hmtx.var_table.get_length ())
1000         hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
1001                                                                               hvar_store_cache));
1002       int lsb = extents.x_bearing;
1003       if (!has_bounds_info)
1004       {
1005         if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
1006           continue;
1007       }
1008       plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
1009       plan->bounds_width_vec[new_gid] = extents.width;
1010     }
1011 
1012     if (_vmtx.has_data ())
1013     {
1014       int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
1015       if (_vmtx.var_table.get_length ())
1016         vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
1017                                                                               vvar_store_cache));
1018 
1019       int tsb = extents.y_bearing;
1020       if (!has_bounds_info)
1021       {
1022         if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
1023           continue;
1024       }
1025       plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
1026       plan->bounds_height_vec[new_gid] = extents.height;
1027     }
1028   }
1029   hb_font_destroy (font);
1030   if (hvar_store_cache)
1031     _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
1032   if (vvar_store_cache)
1033     _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
1034 }
1035 
1036 static bool
_get_instance_glyphs_contour_points(hb_subset_plan_t * plan)1037 _get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
1038 {
1039   /* contour_points vector only needed for updating gvar table (infer delta)
1040    * during partial instancing */
1041   if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
1042     return true;
1043 
1044   OT::glyf_accelerator_t glyf (plan->source);
1045 
1046   for (auto &_ : plan->new_to_old_gid_list)
1047   {
1048     hb_codepoint_t new_gid = _.first;
1049     contour_point_vector_t all_points;
1050     if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
1051     {
1052       if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
1053         return false;
1054       continue;
1055     }
1056 
1057     hb_codepoint_t old_gid = _.second;
1058     if (unlikely (!glyf.glyph_for_gid (old_gid).get_all_points_without_var (plan->source, all_points)))
1059       return false;
1060     if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
1061       return false;
1062   }
1063   return true;
1064 }
1065 #endif
1066 
hb_subset_plan_t(hb_face_t * face,const hb_subset_input_t * input)1067 hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
1068 				    const hb_subset_input_t *input)
1069 {
1070   successful = true;
1071   flags = input->flags;
1072 
1073   unicode_to_new_gid_list.init ();
1074 
1075   name_ids = *input->sets.name_ids;
1076   name_languages = *input->sets.name_languages;
1077   layout_features = *input->sets.layout_features;
1078   layout_scripts = *input->sets.layout_scripts;
1079   glyphs_requested = *input->sets.glyphs;
1080   drop_tables = *input->sets.drop_tables;
1081   no_subset_tables = *input->sets.no_subset_tables;
1082   source = hb_face_reference (face);
1083   dest = hb_face_builder_create ();
1084 
1085   codepoint_to_glyph = hb_map_create ();
1086   glyph_map = hb_map_create ();
1087   reverse_glyph_map = hb_map_create ();
1088 
1089   gsub_insert_catch_all_feature_variation_rec = false;
1090   gpos_insert_catch_all_feature_variation_rec = false;
1091   gdef_varstore_inner_maps.init ();
1092 
1093   user_axes_location = input->axes_location;
1094   all_axes_pinned = false;
1095   pinned_at_default = true;
1096 
1097 #ifdef HB_EXPERIMENTAL_API
1098   for (auto _ : input->name_table_overrides)
1099   {
1100     hb_bytes_t name_bytes = _.second;
1101     unsigned len = name_bytes.length;
1102     char *name_str = (char *) hb_malloc (len);
1103     if (unlikely (!check_success (name_str)))
1104       break;
1105 
1106     hb_memcpy (name_str, name_bytes.arrayZ, len);
1107     name_table_overrides.set (_.first, hb_bytes_t (name_str, len));
1108   }
1109 #endif
1110 
1111   void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
1112 
1113   attach_accelerator_data = input->attach_accelerator_data;
1114   force_long_loca = input->force_long_loca;
1115   if (accel)
1116     accelerator = (hb_subset_accelerator_t*) accel;
1117 
1118   if (unlikely (in_error ()))
1119     return;
1120 
1121 #ifndef HB_NO_VAR
1122   _normalize_axes_location (face, this);
1123 #endif
1124 
1125   _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
1126 
1127   _populate_gids_to_retain (this, input->sets.drop_tables);
1128   if (unlikely (in_error ()))
1129     return;
1130 
1131   if (!check_success(_create_old_gid_to_new_gid_map(
1132           face,
1133           input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
1134           &_glyphset,
1135           &input->glyph_map,
1136           glyph_map,
1137           reverse_glyph_map,
1138 	  &new_to_old_gid_list,
1139           &_num_output_glyphs))) {
1140     return;
1141   }
1142 
1143   _create_glyph_map_gsub (
1144       &_glyphset_gsub,
1145       glyph_map,
1146       &glyph_map_gsub);
1147 
1148   // Now that we have old to new gid map update the unicode to new gid list.
1149   for (unsigned i = 0; i < unicode_to_new_gid_list.length; i++)
1150   {
1151     // Use raw array access for performance.
1152     unicode_to_new_gid_list.arrayZ[i].second =
1153         glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
1154   }
1155 
1156   bounds_width_vec.resize (_num_output_glyphs, false);
1157   for (auto &v : bounds_width_vec)
1158     v = 0xFFFFFFFF;
1159   bounds_height_vec.resize (_num_output_glyphs, false);
1160   for (auto &v : bounds_height_vec)
1161     v = 0xFFFFFFFF;
1162 
1163   if (unlikely (in_error ()))
1164     return;
1165 
1166 #ifndef HB_NO_VAR
1167   _update_instance_metrics_map_from_cff2 (this);
1168   if (!check_success (_get_instance_glyphs_contour_points (this)))
1169       return;
1170 #endif
1171 
1172   if (attach_accelerator_data)
1173   {
1174     inprogress_accelerator =
1175       hb_subset_accelerator_t::create (source,
1176 				       *codepoint_to_glyph,
1177                                        unicodes,
1178 				       has_seac);
1179 
1180     check_success (inprogress_accelerator);
1181   }
1182 
1183 #define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ());
1184 #include "hb-subset-plan-member-list.hh"
1185 #undef HB_SUBSET_PLAN_MEMBER
1186 }
1187 
~hb_subset_plan_t()1188 hb_subset_plan_t::~hb_subset_plan_t()
1189 {
1190   hb_face_destroy (dest);
1191 
1192   hb_map_destroy (codepoint_to_glyph);
1193   hb_map_destroy (glyph_map);
1194   hb_map_destroy (reverse_glyph_map);
1195 #ifndef HB_NO_SUBSET_CFF
1196   cff1_accel.fini ();
1197   cff2_accel.fini ();
1198 #endif
1199   hb_face_destroy (source);
1200 
1201 #ifdef HB_EXPERIMENTAL_API
1202   for (auto _ : name_table_overrides.iter_ref ())
1203     _.second.fini ();
1204 #endif
1205 
1206   if (inprogress_accelerator)
1207     hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
1208 }
1209 
1210 
1211 /**
1212  * hb_subset_plan_create_or_fail:
1213  * @face: font face to create the plan for.
1214  * @input: a #hb_subset_input_t input.
1215  *
1216  * Computes a plan for subsetting the supplied face according
1217  * to a provided input. The plan describes
1218  * which tables and glyphs should be retained.
1219  *
1220  * Return value: (transfer full): New subset plan. Destroy with
1221  * hb_subset_plan_destroy(). If there is a failure creating the plan
1222  * nullptr will be returned.
1223  *
1224  * Since: 4.0.0
1225  **/
1226 hb_subset_plan_t *
hb_subset_plan_create_or_fail(hb_face_t * face,const hb_subset_input_t * input)1227 hb_subset_plan_create_or_fail (hb_face_t	 *face,
1228                                const hb_subset_input_t *input)
1229 {
1230   hb_subset_plan_t *plan;
1231   if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> (face, input))))
1232     return nullptr;
1233 
1234   if (unlikely (plan->in_error ()))
1235   {
1236     hb_subset_plan_destroy (plan);
1237     return nullptr;
1238   }
1239 
1240   return plan;
1241 }
1242 
1243 /**
1244  * hb_subset_plan_destroy:
1245  * @plan: a #hb_subset_plan_t
1246  *
1247  * Decreases the reference count on @plan, and if it reaches zero, destroys
1248  * @plan, freeing all memory.
1249  *
1250  * Since: 4.0.0
1251  **/
1252 void
hb_subset_plan_destroy(hb_subset_plan_t * plan)1253 hb_subset_plan_destroy (hb_subset_plan_t *plan)
1254 {
1255   if (!hb_object_destroy (plan)) return;
1256 
1257   hb_free (plan);
1258 }
1259 
1260 /**
1261  * hb_subset_plan_old_to_new_glyph_mapping:
1262  * @plan: a subsetting plan.
1263  *
1264  * Returns the mapping between glyphs in the original font to glyphs in the
1265  * subset that will be produced by @plan
1266  *
1267  * Return value: (transfer none):
1268  * A pointer to the #hb_map_t of the mapping.
1269  *
1270  * Since: 4.0.0
1271  **/
1272 hb_map_t *
hb_subset_plan_old_to_new_glyph_mapping(const hb_subset_plan_t * plan)1273 hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan)
1274 {
1275   return plan->glyph_map;
1276 }
1277 
1278 /**
1279  * hb_subset_plan_new_to_old_glyph_mapping:
1280  * @plan: a subsetting plan.
1281  *
1282  * Returns the mapping between glyphs in the subset that will be produced by
1283  * @plan and the glyph in the original font.
1284  *
1285  * Return value: (transfer none):
1286  * A pointer to the #hb_map_t of the mapping.
1287  *
1288  * Since: 4.0.0
1289  **/
1290 hb_map_t *
hb_subset_plan_new_to_old_glyph_mapping(const hb_subset_plan_t * plan)1291 hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan)
1292 {
1293   return plan->reverse_glyph_map;
1294 }
1295 
1296 /**
1297  * hb_subset_plan_unicode_to_old_glyph_mapping:
1298  * @plan: a subsetting plan.
1299  *
1300  * Returns the mapping between codepoints in the original font and the
1301  * associated glyph id in the original font.
1302  *
1303  * Return value: (transfer none):
1304  * A pointer to the #hb_map_t of the mapping.
1305  *
1306  * Since: 4.0.0
1307  **/
1308 hb_map_t *
hb_subset_plan_unicode_to_old_glyph_mapping(const hb_subset_plan_t * plan)1309 hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan)
1310 {
1311   return plan->codepoint_to_glyph;
1312 }
1313 
1314 /**
1315  * hb_subset_plan_reference: (skip)
1316  * @plan: a #hb_subset_plan_t object.
1317  *
1318  * Increases the reference count on @plan.
1319  *
1320  * Return value: @plan.
1321  *
1322  * Since: 4.0.0
1323  **/
1324 hb_subset_plan_t *
hb_subset_plan_reference(hb_subset_plan_t * plan)1325 hb_subset_plan_reference (hb_subset_plan_t *plan)
1326 {
1327   return hb_object_reference (plan);
1328 }
1329 
1330 /**
1331  * hb_subset_plan_set_user_data: (skip)
1332  * @plan: a #hb_subset_plan_t object.
1333  * @key: The user-data key to set
1334  * @data: A pointer to the user data
1335  * @destroy: (nullable): A callback to call when @data is not needed anymore
1336  * @replace: Whether to replace an existing data with the same key
1337  *
1338  * Attaches a user-data key/data pair to the given subset plan object.
1339  *
1340  * Return value: `true` if success, `false` otherwise
1341  *
1342  * Since: 4.0.0
1343  **/
1344 hb_bool_t
hb_subset_plan_set_user_data(hb_subset_plan_t * plan,hb_user_data_key_t * key,void * data,hb_destroy_func_t destroy,hb_bool_t replace)1345 hb_subset_plan_set_user_data (hb_subset_plan_t   *plan,
1346                               hb_user_data_key_t *key,
1347                               void               *data,
1348                               hb_destroy_func_t   destroy,
1349                               hb_bool_t	          replace)
1350 {
1351   return hb_object_set_user_data (plan, key, data, destroy, replace);
1352 }
1353 
1354 /**
1355  * hb_subset_plan_get_user_data: (skip)
1356  * @plan: a #hb_subset_plan_t object.
1357  * @key: The user-data key to query
1358  *
1359  * Fetches the user data associated with the specified key,
1360  * attached to the specified subset plan object.
1361  *
1362  * Return value: (transfer none): A pointer to the user data
1363  *
1364  * Since: 4.0.0
1365  **/
1366 void *
hb_subset_plan_get_user_data(const hb_subset_plan_t * plan,hb_user_data_key_t * key)1367 hb_subset_plan_get_user_data (const hb_subset_plan_t *plan,
1368                               hb_user_data_key_t     *key)
1369 {
1370   return hb_object_get_user_data (plan, key);
1371 }
1372