• 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 #ifndef HB_SUBSET_PLAN_HH
28 #define HB_SUBSET_PLAN_HH
29 
30 #include "hb.hh"
31 
32 #include "hb-subset.h"
33 #include "hb-subset-input.hh"
34 #include "hb-subset-accelerator.hh"
35 
36 #include "hb-map.hh"
37 #include "hb-bimap.hh"
38 #include "hb-set.hh"
39 
40 namespace OT {
41 struct Feature;
42 }
43 
44 struct hb_subset_plan_t
45 {
hb_subset_plan_thb_subset_plan_t46   hb_subset_plan_t ()
47   {}
48 
~hb_subset_plan_thb_subset_plan_t49   ~hb_subset_plan_t()
50   {
51     hb_set_destroy (unicodes);
52     hb_set_destroy (name_ids);
53     hb_set_destroy (name_languages);
54     hb_set_destroy (layout_features);
55     hb_set_destroy (layout_scripts);
56     hb_set_destroy (glyphs_requested);
57     hb_set_destroy (drop_tables);
58     hb_set_destroy (no_subset_tables);
59     hb_face_destroy (source);
60     hb_face_destroy (dest);
61     hb_map_destroy (codepoint_to_glyph);
62     hb_map_destroy (glyph_map);
63     hb_map_destroy (reverse_glyph_map);
64     hb_map_destroy (glyph_map_gsub);
65     hb_set_destroy (_glyphset);
66     hb_set_destroy (_glyphset_gsub);
67     hb_set_destroy (_glyphset_mathed);
68     hb_set_destroy (_glyphset_colred);
69     hb_map_destroy (gsub_lookups);
70     hb_map_destroy (gpos_lookups);
71     hb_map_destroy (gsub_features);
72     hb_map_destroy (gpos_features);
73     hb_map_destroy (colrv1_layers);
74     hb_map_destroy (colr_palettes);
75     hb_map_destroy (axes_index_map);
76     hb_map_destroy (axes_old_index_tag_map);
77 
78     hb_hashmap_destroy (gsub_langsys);
79     hb_hashmap_destroy (gpos_langsys);
80     hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
81     hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
82     hb_hashmap_destroy (gsub_feature_substitutes_map);
83     hb_hashmap_destroy (gpos_feature_substitutes_map);
84     hb_hashmap_destroy (axes_location);
85     hb_hashmap_destroy (sanitized_table_cache);
86     hb_hashmap_destroy (hmtx_map);
87     hb_hashmap_destroy (vmtx_map);
88     hb_hashmap_destroy (layout_variation_idx_delta_map);
89 
90 #ifdef HB_EXPERIMENTAL_API
91     if (name_table_overrides)
92     {
93       for (auto _ : *name_table_overrides)
94         _.second.fini ();
95     }
96     hb_hashmap_destroy (name_table_overrides);
97 #endif
98 
99     if (inprogress_accelerator)
100       hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
101 
102     if (user_axes_location)
103     {
104       hb_object_destroy (user_axes_location);
105       hb_free (user_axes_location);
106     }
107   }
108 
109   hb_object_header_t header;
110 
111   bool successful;
112   unsigned flags;
113   bool attach_accelerator_data = false;
114   bool force_long_loca = false;
115 
116   // For each cp that we'd like to retain maps to the corresponding gid.
117   hb_set_t *unicodes;
118   hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
119 
120   // name_ids we would like to retain
121   hb_set_t *name_ids;
122 
123   // name_languages we would like to retain
124   hb_set_t *name_languages;
125 
126   //layout features which will be preserved
127   hb_set_t *layout_features;
128 
129   // layout scripts which will be preserved.
130   hb_set_t *layout_scripts;
131 
132   //glyph ids requested to retain
133   hb_set_t *glyphs_requested;
134 
135   // Tables which should not be processed, just pass them through.
136   hb_set_t *no_subset_tables;
137 
138   // Tables which should be dropped.
139   hb_set_t *drop_tables;
140 
141   // The glyph subset
142   hb_map_t *codepoint_to_glyph;
143 
144   // Old -> New glyph id mapping
145   hb_map_t *glyph_map;
146   hb_map_t *reverse_glyph_map;
147   hb_map_t *glyph_map_gsub;
148 
149   // Plan is only good for a specific source/dest so keep them with it
150   hb_face_t *source;
151   hb_face_t *dest;
152 
153   unsigned int _num_output_glyphs;
154   hb_set_t *_glyphset;
155   hb_set_t *_glyphset_gsub;
156   hb_set_t *_glyphset_mathed;
157   hb_set_t *_glyphset_colred;
158 
159   //active lookups we'd like to retain
160   hb_map_t *gsub_lookups;
161   hb_map_t *gpos_lookups;
162 
163   //active langsys we'd like to retain
164   hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gsub_langsys;
165   hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gpos_langsys;
166 
167   //active features after removing redundant langsys and prune_features
168   hb_map_t *gsub_features;
169   hb_map_t *gpos_features;
170 
171   //active feature variation records/condition index with variations
172   hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
173   hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
174 
175   //feature index-> address of substituation feature table mapping with
176   //variations
177   hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
178   hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
179 
180   //active layers/palettes we'd like to retain
181   hb_map_t *colrv1_layers;
182   hb_map_t *colr_palettes;
183 
184   //Old layout item variation index -> (New varidx, delta) mapping
185   hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
186 
187   //gdef varstore retained varidx mapping
188   hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps;
189 
190   hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>>* sanitized_table_cache;
191   //normalized axes location map
192   hb_hashmap_t<hb_tag_t, int> *axes_location;
193   //user specified axes location map
194   hb_hashmap_t<hb_tag_t, float> *user_axes_location;
195   //retained old axis index -> new axis index mapping in fvar axis array
196   hb_map_t *axes_index_map;
197   //axis_index->axis_tag mapping in fvar axis array
198   hb_map_t *axes_old_index_tag_map;
199   bool all_axes_pinned;
200   bool pinned_at_default;
201   bool has_seac;
202 
203   //hmtx metrics map: new gid->(advance, lsb)
204   hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *hmtx_map;
205   //vmtx metrics map: new gid->(advance, lsb)
206   hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
207 
208 #ifdef HB_EXPERIMENTAL_API
209   // name table overrides map: hb_ot_name_record_ids_t-> name string new value or
210   // None to indicate should remove
211   hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides;
212 #endif
213 
214   const hb_subset_accelerator_t* accelerator;
215   hb_subset_accelerator_t* inprogress_accelerator;
216 
217  public:
218 
219   template<typename T>
source_tablehb_subset_plan_t220   hb_blob_ptr_t<T> source_table()
221   {
222     hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
223 
224     auto *cache = accelerator ? &accelerator->sanitized_table_cache : sanitized_table_cache;
225     if (cache
226         && !cache->in_error ()
227         && cache->has (+T::tableTag)) {
228       return hb_blob_reference (cache->get (+T::tableTag).get ());
229     }
230 
231     hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
232     hb_blob_t* ret = hb_blob_reference (table_blob.get ());
233 
234     if (likely (cache))
235       cache->set (+T::tableTag, std::move (table_blob));
236 
237     return ret;
238   }
239 
in_errorhb_subset_plan_t240   bool in_error () const { return !successful; }
241 
check_successhb_subset_plan_t242   bool check_success(bool success)
243   {
244     successful = (successful && success);
245     return successful;
246   }
247 
248   /*
249    * The set of input glyph ids which will be retained in the subset.
250    * Does NOT include ids kept due to retain_gids. You probably want to use
251    * glyph_map/reverse_glyph_map.
252    */
253   inline const hb_set_t *
glyphsethb_subset_plan_t254   glyphset () const
255   {
256     return _glyphset;
257   }
258 
259   /*
260    * The set of input glyph ids which will be retained in the subset.
261    */
262   inline const hb_set_t *
glyphset_gsubhb_subset_plan_t263   glyphset_gsub () const
264   {
265     return _glyphset_gsub;
266   }
267 
268   /*
269    * The total number of output glyphs in the final subset.
270    */
271   inline unsigned int
num_output_glyphshb_subset_plan_t272   num_output_glyphs () const
273   {
274     return _num_output_glyphs;
275   }
276 
277   /*
278    * Given an output gid , returns true if that glyph id is an empty
279    * glyph (ie. it's a gid that we are dropping all data for).
280    */
is_empty_glyphhb_subset_plan_t281   inline bool is_empty_glyph (hb_codepoint_t gid) const
282   {
283     return !_glyphset->has (gid);
284   }
285 
new_gid_for_codepointhb_subset_plan_t286   inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
287 				     hb_codepoint_t *new_gid) const
288   {
289     hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
290     if (old_gid == HB_MAP_VALUE_INVALID)
291       return false;
292 
293     return new_gid_for_old_gid (old_gid, new_gid);
294   }
295 
new_gid_for_old_gidhb_subset_plan_t296   inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
297 				   hb_codepoint_t *new_gid) const
298   {
299     hb_codepoint_t gid = glyph_map->get (old_gid);
300     if (gid == HB_MAP_VALUE_INVALID)
301       return false;
302 
303     *new_gid = gid;
304     return true;
305   }
306 
old_gid_for_new_gidhb_subset_plan_t307   inline bool old_gid_for_new_gid (hb_codepoint_t  new_gid,
308 				   hb_codepoint_t *old_gid) const
309   {
310     hb_codepoint_t gid = reverse_glyph_map->get (new_gid);
311     if (gid == HB_MAP_VALUE_INVALID)
312       return false;
313 
314     *old_gid = gid;
315     return true;
316   }
317 
318   inline bool
add_tablehb_subset_plan_t319   add_table (hb_tag_t tag,
320 	     hb_blob_t *contents)
321   {
322     if (HB_DEBUG_SUBSET)
323     {
324       hb_blob_t *source_blob = source->reference_table (tag);
325       DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes",
326 		HB_UNTAG(tag),
327 		hb_blob_get_length (contents),
328 		hb_blob_get_length (source_blob));
329       hb_blob_destroy (source_blob);
330     }
331     return hb_face_builder_add_table (dest, tag, contents);
332   }
333 };
334 
335 #endif /* HB_SUBSET_PLAN_HH */
336