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
40namespace OT {
41struct Feature;
42}
43
44struct 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
68typedef struct head_maxp_info_t head_maxp_info_t;
69
70namespace OT {
71 struct cff1_subset_accelerator_t;
72 struct cff2_subset_accelerator_t;
73}
74
75struct 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 header;
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