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 head_maxp_info_t |
45 | { |
46 | head_maxp_info_t () |
47 | :xMin (0x7FFF), xMax (-0x7FFF), yMin (0x7FFF), yMax (-0x7FFF), |
48 | maxPoints (0), maxContours (0), |
49 | maxCompositePoints (0), |
50 | maxCompositeContours (0), |
51 | maxComponentElements (0), |
52 | maxComponentDepth (0), |
53 | allXMinIsLsb (true) {} |
54 | |
55 | int xMin; |
56 | int xMax; |
57 | int yMin; |
58 | int yMax; |
59 | unsigned maxPoints; |
60 | unsigned maxContours; |
61 | unsigned maxCompositePoints; |
62 | unsigned maxCompositeContours; |
63 | unsigned maxComponentElements; |
64 | unsigned maxComponentDepth; |
65 | bool allXMinIsLsb; |
66 | }; |
67 | |
68 | typedef struct head_maxp_info_t head_maxp_info_t; |
69 | |
70 | namespace OT { |
71 | struct cff1_subset_accelerator_t; |
72 | struct cff2_subset_accelerator_t; |
73 | } |
74 | |
75 | struct hb_subset_plan_t |
76 | { |
77 | HB_INTERNAL hb_subset_plan_t (hb_face_t *, |
78 | const hb_subset_input_t *input); |
79 | |
80 | HB_INTERNAL ~hb_subset_plan_t(); |
81 | |
82 | hb_object_header_t ; |
83 | |
84 | bool successful; |
85 | unsigned flags; |
86 | bool attach_accelerator_data = false; |
87 | bool force_long_loca = false; |
88 | |
89 | // The glyph subset |
90 | hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated |
91 | |
92 | // Old -> New glyph id mapping |
93 | hb_map_t *glyph_map; // Needs to be heap-allocated |
94 | hb_map_t *reverse_glyph_map; // Needs to be heap-allocated |
95 | |
96 | // Plan is only good for a specific source/dest so keep them with it |
97 | hb_face_t *source; |
98 | #ifndef HB_NO_SUBSET_CFF |
99 | // These have to be immediately after source: |
100 | hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel; |
101 | hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel; |
102 | #endif |
103 | |
104 | hb_face_t *dest; |
105 | |
106 | unsigned int _num_output_glyphs; |
107 | |
108 | bool all_axes_pinned; |
109 | bool pinned_at_default; |
110 | bool has_seac; |
111 | |
112 | // whether to insert a catch-all FeatureVariationRecord |
113 | bool gsub_insert_catch_all_feature_variation_rec; |
114 | bool gpos_insert_catch_all_feature_variation_rec; |
115 | |
116 | #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name; |
117 | #include "hb-subset-plan-member-list.hh" |
118 | #undef HB_SUBSET_PLAN_MEMBER |
119 | |
120 | //recalculated head/maxp table info after instancing |
121 | mutable head_maxp_info_t head_maxp_info; |
122 | |
123 | const hb_subset_accelerator_t* accelerator; |
124 | hb_subset_accelerator_t* inprogress_accelerator; |
125 | |
126 | public: |
127 | |
128 | template<typename T> |
129 | struct source_table_loader |
130 | { |
131 | hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan) |
132 | { |
133 | hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr); |
134 | |
135 | auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache; |
136 | if (cache |
137 | && !cache->in_error () |
138 | && cache->has (+T::tableTag)) { |
139 | return hb_blob_reference (cache->get (+T::tableTag).get ()); |
140 | } |
141 | |
142 | hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)}; |
143 | hb_blob_t* ret = hb_blob_reference (table_blob.get ()); |
144 | |
145 | if (likely (cache)) |
146 | cache->set (+T::tableTag, std::move (table_blob)); |
147 | |
148 | return ret; |
149 | } |
150 | }; |
151 | |
152 | template<typename T> |
153 | auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this)) |
154 | |
155 | bool in_error () const { return !successful; } |
156 | |
157 | bool check_success(bool success) |
158 | { |
159 | successful = (successful && success); |
160 | return successful; |
161 | } |
162 | |
163 | /* |
164 | * The set of input glyph ids which will be retained in the subset. |
165 | * Does NOT include ids kept due to retain_gids. You probably want to use |
166 | * glyph_map/reverse_glyph_map. |
167 | */ |
168 | inline const hb_set_t * |
169 | glyphset () const |
170 | { |
171 | return &_glyphset; |
172 | } |
173 | |
174 | /* |
175 | * The set of input glyph ids which will be retained in the subset. |
176 | */ |
177 | inline const hb_set_t * |
178 | glyphset_gsub () const |
179 | { |
180 | return &_glyphset_gsub; |
181 | } |
182 | |
183 | /* |
184 | * The total number of output glyphs in the final subset. |
185 | */ |
186 | inline unsigned int |
187 | num_output_glyphs () const |
188 | { |
189 | return _num_output_glyphs; |
190 | } |
191 | |
192 | inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, |
193 | hb_codepoint_t *new_gid) const |
194 | { |
195 | hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); |
196 | if (old_gid == HB_MAP_VALUE_INVALID) |
197 | return false; |
198 | |
199 | return new_gid_for_old_gid (old_gid, new_gid); |
200 | } |
201 | |
202 | inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, |
203 | hb_codepoint_t *new_gid) const |
204 | { |
205 | hb_codepoint_t gid = glyph_map->get (old_gid); |
206 | if (gid == HB_MAP_VALUE_INVALID) |
207 | return false; |
208 | |
209 | *new_gid = gid; |
210 | return true; |
211 | } |
212 | |
213 | inline bool old_gid_for_new_gid (hb_codepoint_t new_gid, |
214 | hb_codepoint_t *old_gid) const |
215 | { |
216 | hb_codepoint_t gid = reverse_glyph_map->get (new_gid); |
217 | if (gid == HB_MAP_VALUE_INVALID) |
218 | return false; |
219 | |
220 | *old_gid = gid; |
221 | return true; |
222 | } |
223 | |
224 | inline bool |
225 | add_table (hb_tag_t tag, |
226 | hb_blob_t *contents) |
227 | { |
228 | if (HB_DEBUG_SUBSET) |
229 | { |
230 | hb_blob_t *source_blob = source->reference_table (tag); |
231 | DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %u bytes, source %u bytes" , |
232 | HB_UNTAG(tag), |
233 | hb_blob_get_length (contents), |
234 | hb_blob_get_length (source_blob)); |
235 | hb_blob_destroy (source_blob); |
236 | } |
237 | return hb_face_builder_add_table (dest, tag, contents); |
238 | } |
239 | }; |
240 | |
241 | |
242 | #endif /* HB_SUBSET_PLAN_HH */ |
243 | |