/src/harfbuzz/src/hb-subset-plan.hh
Line  | Count  | Source  | 
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 os2_info_t { | 
45  |  |   hb_codepoint_t min_cmap_codepoint;  | 
46  |  |   hb_codepoint_t max_cmap_codepoint;  | 
47  |  | };  | 
48  |  |  | 
49  |  | typedef struct os2_info_t os2_info_t;  | 
50  |  |  | 
51  |  | struct head_maxp_info_t  | 
52  |  | { | 
53  |  |   head_maxp_info_t ()  | 
54  |  |       :xMin (0x7FFF), xMax (-0x7FFF), yMin (0x7FFF), yMax (-0x7FFF),  | 
55  |  |       maxPoints (0), maxContours (0),  | 
56  |  |       maxCompositePoints (0),  | 
57  |  |       maxCompositeContours (0),  | 
58  |  |       maxComponentElements (0),  | 
59  |  |       maxComponentDepth (0),  | 
60  | 0  |       allXMinIsLsb (true) {} | 
61  |  |  | 
62  |  |   int xMin;  | 
63  |  |   int xMax;  | 
64  |  |   int yMin;  | 
65  |  |   int yMax;  | 
66  |  |   unsigned maxPoints;  | 
67  |  |   unsigned maxContours;  | 
68  |  |   unsigned maxCompositePoints;  | 
69  |  |   unsigned maxCompositeContours;  | 
70  |  |   unsigned maxComponentElements;  | 
71  |  |   unsigned maxComponentDepth;  | 
72  |  |   bool allXMinIsLsb;  | 
73  |  | };  | 
74  |  |  | 
75  |  | typedef struct head_maxp_info_t head_maxp_info_t;  | 
76  |  |  | 
77  |  | struct contour_point_t  | 
78  |  | { | 
79  |  |   void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)  | 
80  | 0  |   { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } | 
81  |  |  | 
82  |  |   void transform (const float (&matrix)[4])  | 
83  | 0  |   { | 
84  | 0  |     float x_ = x * matrix[0] + y * matrix[2];  | 
85  | 0  |     y  = x * matrix[1] + y * matrix[3];  | 
86  | 0  |     x  = x_;  | 
87  | 0  |   }  | 
88  |  |  | 
89  |  |   void add_delta (float delta_x, float delta_y)  | 
90  | 0  |   { | 
91  | 0  |     x += delta_x;  | 
92  | 0  |     y += delta_y;  | 
93  | 0  |   }  | 
94  |  |  | 
95  |  |   HB_ALWAYS_INLINE  | 
96  | 0  |   void translate (const contour_point_t &p) { x += p.x; y += p.y; } | 
97  |  |  | 
98  |  |   float x;  | 
99  |  |   float y;  | 
100  |  |   uint8_t flag;  | 
101  |  |   bool is_end_point;  | 
102  |  | };  | 
103  |  |  | 
104  |  | struct contour_point_vector_t : hb_vector_t<contour_point_t>  | 
105  |  | { | 
106  |  |   bool add_deltas (hb_array_t<const float> deltas_x,  | 
107  |  |                    hb_array_t<const float> deltas_y,  | 
108  |  |                    hb_array_t<const bool> indices)  | 
109  | 0  |   { | 
110  | 0  |     if (indices.length != deltas_x.length ||  | 
111  | 0  |         indices.length != deltas_y.length)  | 
112  | 0  |       return false;  | 
113  | 0  | 
  | 
114  | 0  |     for (unsigned i = 0; i < indices.length; i++)  | 
115  | 0  |     { | 
116  | 0  |       if (!indices.arrayZ[i]) continue;  | 
117  | 0  |       arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);  | 
118  | 0  |     }  | 
119  | 0  |     return true;  | 
120  | 0  |   }  | 
121  |  | };  | 
122  |  |  | 
123  |  | namespace OT { | 
124  |  |   struct cff1_subset_accelerator_t;  | 
125  |  |   struct cff2_subset_accelerator_t;  | 
126  |  | }  | 
127  |  |  | 
128  |  | struct hb_subset_plan_t  | 
129  |  | { | 
130  |  |   HB_INTERNAL hb_subset_plan_t (hb_face_t *,  | 
131  |  |         const hb_subset_input_t *input);  | 
132  |  |  | 
133  |  |   HB_INTERNAL ~hb_subset_plan_t();  | 
134  |  |  | 
135  |  |   hb_object_header_t header;  | 
136  |  |  | 
137  |  |   bool successful;  | 
138  |  |   unsigned flags;  | 
139  |  |   bool attach_accelerator_data = false;  | 
140  |  |   bool force_long_loca = false;  | 
141  |  |  | 
142  |  |   // The glyph subset  | 
143  |  |   hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated  | 
144  |  |  | 
145  |  |   // Old -> New glyph id mapping  | 
146  |  |   hb_map_t *glyph_map; // Needs to be heap-allocated  | 
147  |  |   hb_map_t *reverse_glyph_map; // Needs to be heap-allocated  | 
148  |  |  | 
149  |  |   // Plan is only good for a specific source/dest so keep them with it  | 
150  |  |   hb_face_t *source;  | 
151  |  | #ifndef HB_NO_SUBSET_CFF  | 
152  |  |   // These have to be immediately after source:  | 
153  |  |   hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;  | 
154  |  |   hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;  | 
155  |  | #endif  | 
156  |  |  | 
157  |  |   hb_face_t *dest;  | 
158  |  |  | 
159  |  |   unsigned int _num_output_glyphs;  | 
160  |  |  | 
161  |  |   bool all_axes_pinned;  | 
162  |  |   bool pinned_at_default;  | 
163  |  |   bool has_seac;  | 
164  |  |  | 
165  |  |   // whether to insert a catch-all FeatureVariationRecord  | 
166  |  |   bool gsub_insert_catch_all_feature_variation_rec;  | 
167  |  |   bool gpos_insert_catch_all_feature_variation_rec;  | 
168  |  |  | 
169  |  |   // whether GDEF ItemVariationStore is retained  | 
170  |  |   mutable bool has_gdef_varstore;  | 
171  |  |  | 
172  |  | #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;  | 
173  |  | #include "hb-subset-plan-member-list.hh"  | 
174  |  | #undef HB_SUBSET_PLAN_MEMBER  | 
175  |  |  | 
176  |  |   //recalculated head/maxp table info after instancing  | 
177  |  |   mutable head_maxp_info_t head_maxp_info;  | 
178  |  |  | 
179  |  |   os2_info_t os2_info;  | 
180  |  |  | 
181  |  |   const hb_subset_accelerator_t* accelerator;  | 
182  |  |   hb_subset_accelerator_t* inprogress_accelerator;  | 
183  |  |  | 
184  |  |  public:  | 
185  |  |  | 
186  |  |   template<typename T>  | 
187  |  |   struct source_table_loader  | 
188  |  |   { | 
189  |  |     hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan)  | 
190  |  |     { | 
191  |  |       hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr);  | 
192  |  |  | 
193  |  |       auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache;  | 
194  |  |       if (cache  | 
195  |  |     && !cache->in_error ()  | 
196  |  |     && cache->has (+T::tableTag)) { | 
197  |  |   return hb_blob_reference (cache->get (+T::tableTag).get ());  | 
198  |  |       }  | 
199  |  |  | 
200  |  |       hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)}; | 
201  |  |       hb_blob_t* ret = hb_blob_reference (table_blob.get ());  | 
202  |  |  | 
203  |  |       if (likely (cache))  | 
204  |  |   cache->set (+T::tableTag, std::move (table_blob));  | 
205  |  |  | 
206  |  |       return ret;  | 
207  |  |     }  | 
208  |  |   };  | 
209  |  |  | 
210  |  |   template<typename T>  | 
211  |  |   auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this)) | 
212  |  |  | 
213  | 0  |   bool in_error () const { return !successful; } | 
214  |  |  | 
215  |  |   bool check_success(bool success)  | 
216  | 0  |   { | 
217  | 0  |     successful = (successful && success);  | 
218  | 0  |     return successful;  | 
219  | 0  |   }  | 
220  |  |  | 
221  |  |   /*  | 
222  |  |    * The set of input glyph ids which will be retained in the subset.  | 
223  |  |    * Does NOT include ids kept due to retain_gids. You probably want to use  | 
224  |  |    * glyph_map/reverse_glyph_map.  | 
225  |  |    */  | 
226  |  |   inline const hb_set_t *  | 
227  |  |   glyphset () const  | 
228  | 0  |   { | 
229  | 0  |     return &_glyphset;  | 
230  | 0  |   }  | 
231  |  |  | 
232  |  |   /*  | 
233  |  |    * The set of input glyph ids which will be retained in the subset.  | 
234  |  |    */  | 
235  |  |   inline const hb_set_t *  | 
236  |  |   glyphset_gsub () const  | 
237  | 0  |   { | 
238  | 0  |     return &_glyphset_gsub;  | 
239  | 0  |   }  | 
240  |  |  | 
241  |  |   /*  | 
242  |  |    * The total number of output glyphs in the final subset.  | 
243  |  |    */  | 
244  |  |   inline unsigned int  | 
245  |  |   num_output_glyphs () const  | 
246  | 0  |   { | 
247  | 0  |     return _num_output_glyphs;  | 
248  | 0  |   }  | 
249  |  |  | 
250  |  |   inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,  | 
251  |  |              hb_codepoint_t *new_gid) const  | 
252  | 0  |   { | 
253  | 0  |     hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);  | 
254  | 0  |     if (old_gid == HB_MAP_VALUE_INVALID)  | 
255  | 0  |       return false;  | 
256  | 0  | 
  | 
257  | 0  |     return new_gid_for_old_gid (old_gid, new_gid);  | 
258  | 0  |   }  | 
259  |  |  | 
260  |  |   inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,  | 
261  |  |            hb_codepoint_t *new_gid) const  | 
262  | 0  |   { | 
263  | 0  |     hb_codepoint_t gid = glyph_map->get (old_gid);  | 
264  | 0  |     if (gid == HB_MAP_VALUE_INVALID)  | 
265  | 0  |       return false;  | 
266  | 0  | 
  | 
267  | 0  |     *new_gid = gid;  | 
268  | 0  |     return true;  | 
269  | 0  |   }  | 
270  |  |  | 
271  |  |   inline bool old_gid_for_new_gid (hb_codepoint_t  new_gid,  | 
272  |  |            hb_codepoint_t *old_gid) const  | 
273  | 0  |   { | 
274  | 0  |     hb_codepoint_t gid = reverse_glyph_map->get (new_gid);  | 
275  | 0  |     if (gid == HB_MAP_VALUE_INVALID)  | 
276  | 0  |       return false;  | 
277  | 0  | 
  | 
278  | 0  |     *old_gid = gid;  | 
279  | 0  |     return true;  | 
280  | 0  |   }  | 
281  |  |  | 
282  |  |   inline bool  | 
283  |  |   add_table (hb_tag_t tag,  | 
284  |  |        hb_blob_t *contents)  | 
285  | 0  |   { | 
286  | 0  |     if (HB_DEBUG_SUBSET)  | 
287  | 0  |     { | 
288  | 0  |       hb_blob_t *source_blob = source->reference_table (tag);  | 
289  | 0  |       DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %u bytes, source %u bytes",  | 
290  | 0  |     HB_UNTAG(tag),  | 
291  | 0  |     hb_blob_get_length (contents),  | 
292  | 0  |     hb_blob_get_length (source_blob));  | 
293  | 0  |       hb_blob_destroy (source_blob);  | 
294  | 0  |     }  | 
295  | 0  |     return hb_face_builder_add_table (dest, tag, contents);  | 
296  | 0  |   }  | 
297  |  | };  | 
298  |  |  | 
299  |  | // hb-subset-plan implementation is split into multiple files to keep  | 
300  |  | // compile times more reasonable:  | 
301  |  | // - hb-subset-plan.cc  | 
302  |  | // - hb-subset-plan-layout.cc  | 
303  |  | // - hb-subset-plan-var.cc  | 
304  |  | //  | 
305  |  | // The functions below are those needed to connect the split files  | 
306  |  | // above together.  | 
307  |  | HB_INTERNAL void  | 
308  |  | remap_indexes (const hb_set_t *indexes,  | 
309  |  |                hb_map_t       *mapping /* OUT */);  | 
310  |  |  | 
311  |  |  | 
312  |  | #ifndef HB_NO_VAR  | 
313  |  | template<typename ItemVarStore>  | 
314  |  | HB_INTERNAL void  | 
315  |  | remap_variation_indices (const ItemVarStore &var_store,  | 
316  |  |                          const hb_set_t &variation_indices,  | 
317  |  |                          const hb_vector_t<int>& normalized_coords,  | 
318  |  |                          bool calculate_delta, /* not pinned at default */  | 
319  |  |                          bool no_variations, /* all axes pinned */  | 
320  |  |                          hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */);  | 
321  |  |  | 
322  |  |  | 
323  |  | template<typename DeltaSetIndexMap>  | 
324  |  | HB_INTERNAL void  | 
325  |  | remap_colrv1_delta_set_index_indices (const DeltaSetIndexMap &index_map,  | 
326  |  |                                       const hb_set_t &delta_set_idxes,  | 
327  |  |                                       hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map, /* IN/OUT */  | 
328  |  |                                       hb_map_t &new_deltaset_idx_varidx_map /* OUT */);  | 
329  |  |  | 
330  |  |  | 
331  |  | HB_INTERNAL void  | 
332  |  | generate_varstore_inner_maps (const hb_set_t& varidx_set,  | 
333  |  |                               unsigned subtable_count,  | 
334  |  |                               hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */);  | 
335  |  |  | 
336  |  | HB_INTERNAL void  | 
337  |  | normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan);  | 
338  |  |  | 
339  |  | HB_INTERNAL void  | 
340  |  | update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan);  | 
341  |  |  | 
342  |  | HB_INTERNAL bool  | 
343  |  | get_instance_glyphs_contour_points (hb_subset_plan_t *plan);  | 
344  |  |  | 
345  |  | #ifndef HB_NO_BASE  | 
346  |  | HB_INTERNAL void  | 
347  |  | collect_base_variation_indices (hb_subset_plan_t* plan);  | 
348  |  | #endif  | 
349  |  | #endif  | 
350  |  |  | 
351  |  | #ifndef HB_NO_SUBSET_LAYOUT  | 
352  |  | typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;  | 
353  |  |  | 
354  |  | HB_INTERNAL void  | 
355  |  | remap_used_mark_sets (hb_subset_plan_t *plan,  | 
356  |  |                       hb_map_t& used_mark_sets_map);  | 
357  |  |  | 
358  |  | HB_INTERNAL void  | 
359  |  | layout_nameid_closure (hb_subset_plan_t* plan,  | 
360  |  |                        hb_set_t* drop_tables);  | 
361  |  |  | 
362  |  | HB_INTERNAL void  | 
363  |  | layout_populate_gids_to_retain (hb_subset_plan_t* plan,  | 
364  |  |                                 hb_set_t* drop_tables);  | 
365  |  |  | 
366  |  | HB_INTERNAL void  | 
367  |  | collect_layout_variation_indices (hb_subset_plan_t* plan);  | 
368  |  | #endif  | 
369  |  |  | 
370  |  |  | 
371  |  | #endif /* HB_SUBSET_PLAN_HH */  |