1/*
2 * Copyright © 2017 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): Behdad Esfahbod
25 */
26
27#ifndef HB_OT_VAR_HVAR_TABLE_HH
28#define HB_OT_VAR_HVAR_TABLE_HH
29
30#include "hb-ot-layout-common.hh"
31#include "hb-ot-var-common.hh"
32
33namespace OT {
34
35
36struct index_map_subset_plan_t
37{
38 enum index_map_index_t {
39 ADV_INDEX,
40 LSB_INDEX, /* dual as TSB */
41 RSB_INDEX, /* dual as BSB */
42 VORG_INDEX
43 };
44
45 void init (const DeltaSetIndexMap &index_map,
46 hb_inc_bimap_t &outer_map,
47 hb_vector_t<hb_set_t *> &inner_sets,
48 const hb_subset_plan_t *plan,
49 bool bypass_empty = true)
50 {
51 map_count = 0;
52 outer_bit_count = 0;
53 inner_bit_count = 1;
54 max_inners.init ();
55 output_map.init ();
56
57 if (bypass_empty && !index_map.get_map_count ()) return;
58
59 unsigned int last_val = (unsigned int)-1;
60 hb_codepoint_t last_gid = HB_CODEPOINT_INVALID;
61
62 outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
63 max_inners.resize (inner_sets.length);
64 for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
65
66 /* Search backwards for a map value different from the last map value */
67 auto &new_to_old_gid_list = plan->new_to_old_gid_list;
68 unsigned count = new_to_old_gid_list.length;
69 for (unsigned j = count; j; j--)
70 {
71 hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
72 hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
73
74 unsigned int v = index_map.map (old_gid);
75 if (last_gid == HB_CODEPOINT_INVALID)
76 {
77 last_val = v;
78 last_gid = gid;
79 continue;
80 }
81 if (v != last_val)
82 break;
83
84 last_gid = gid;
85 }
86
87 if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
88 map_count = last_gid + 1;
89 for (auto _ : plan->new_to_old_gid_list)
90 {
91 hb_codepoint_t gid = _.first;
92 if (gid >= map_count) break;
93
94 hb_codepoint_t old_gid = _.second;
95 unsigned int v = index_map.map (old_gid);
96 unsigned int outer = v >> 16;
97 unsigned int inner = v & 0xFFFF;
98 outer_map.add (outer);
99 if (inner > max_inners[outer]) max_inners[outer] = inner;
100 if (outer >= inner_sets.length) return;
101 inner_sets[outer]->add (inner);
102 }
103 }
104
105 void fini ()
106 {
107 max_inners.fini ();
108 output_map.fini ();
109 }
110
111 void remap (const DeltaSetIndexMap *input_map,
112 const hb_inc_bimap_t &outer_map,
113 const hb_vector_t<hb_inc_bimap_t> &inner_maps,
114 const hb_subset_plan_t *plan)
115 {
116 for (unsigned int i = 0; i < max_inners.length; i++)
117 {
118 if (inner_maps[i].get_population () == 0) continue;
119 unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]);
120 if (bit_count > inner_bit_count) inner_bit_count = bit_count;
121 }
122
123 if (unlikely (!output_map.resize (map_count))) return;
124 for (const auto &_ : plan->new_to_old_gid_list)
125 {
126 hb_codepoint_t new_gid = _.first;
127 hb_codepoint_t old_gid = _.second;
128
129 if (unlikely (new_gid >= map_count)) break;
130
131 uint32_t v = input_map->map (old_gid);
132 unsigned int outer = v >> 16;
133 output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
134 }
135 }
136
137 unsigned int get_inner_bit_count () const { return inner_bit_count; }
138 unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
139 unsigned int get_map_count () const { return map_count; }
140
141 unsigned int get_size () const
142 { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); }
143
144 bool is_identity () const { return get_output_map ().length == 0; }
145 hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
146
147 protected:
148 unsigned int map_count;
149 hb_vector_t<unsigned int> max_inners;
150 unsigned int outer_bit_count;
151 unsigned int inner_bit_count;
152 hb_vector_t<uint32_t> output_map;
153};
154
155struct hvarvvar_subset_plan_t
156{
157 hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {}
158 ~hvarvvar_subset_plan_t() { fini (); }
159
160 void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
161 const VariationStore &_var_store,
162 const hb_subset_plan_t *plan)
163 {
164 index_map_plans.resize (index_maps.length);
165
166 var_store = &_var_store;
167 inner_sets.resize (var_store->get_sub_table_count ());
168 for (unsigned int i = 0; i < inner_sets.length; i++)
169 inner_sets[i] = hb_set_create ();
170 adv_set = hb_set_create ();
171
172 inner_maps.resize (var_store->get_sub_table_count ());
173
174 if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
175
176 bool retain_adv_map = false;
177 index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false);
178 if (index_maps[0] == &Null (DeltaSetIndexMap))
179 {
180 retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
181 outer_map.add (0);
182 for (hb_codepoint_t old_gid : plan->glyphset()->iter())
183 inner_sets[0]->add (old_gid);
184 hb_set_union (adv_set, inner_sets[0]);
185 }
186
187 for (unsigned int i = 1; i < index_maps.length; i++)
188 index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan);
189
190 outer_map.sort ();
191
192 if (retain_adv_map)
193 {
194 for (const auto &_ : plan->new_to_old_gid_list)
195 {
196 hb_codepoint_t old_gid = _.second;
197 inner_maps[0].add (old_gid);
198 }
199 }
200 else
201 {
202 inner_maps[0].add_set (adv_set);
203 hb_set_subtract (inner_sets[0], adv_set);
204 inner_maps[0].add_set (inner_sets[0]);
205 }
206
207 for (unsigned int i = 1; i < inner_maps.length; i++)
208 inner_maps[i].add_set (inner_sets[i]);
209
210 for (unsigned int i = 0; i < index_maps.length; i++)
211 index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
212 }
213
214 void fini ()
215 {
216 for (unsigned int i = 0; i < inner_sets.length; i++)
217 hb_set_destroy (inner_sets[i]);
218 hb_set_destroy (adv_set);
219 inner_maps.fini ();
220 index_map_plans.fini ();
221 }
222
223 hb_inc_bimap_t outer_map;
224 hb_vector_t<hb_inc_bimap_t> inner_maps;
225 hb_vector_t<index_map_subset_plan_t> index_map_plans;
226 const VariationStore *var_store;
227
228 protected:
229 hb_vector_t<hb_set_t *> inner_sets;
230 hb_set_t *adv_set;
231};
232
233/*
234 * HVAR -- Horizontal Metrics Variations
235 * https://docs.microsoft.com/en-us/typography/opentype/spec/hvar
236 * VVAR -- Vertical Metrics Variations
237 * https://docs.microsoft.com/en-us/typography/opentype/spec/vvar
238 */
239#define HB_OT_TAG_HVAR HB_TAG('H','V','A','R')
240#define HB_OT_TAG_VVAR HB_TAG('V','V','A','R')
241
242struct HVARVVAR
243{
244 static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR;
245 static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR;
246
247 bool sanitize (hb_sanitize_context_t *c) const
248 {
249 TRACE_SANITIZE (this);
250 return_trace (version.sanitize (c) &&
251 likely (version.major == 1) &&
252 varStore.sanitize (c, this) &&
253 advMap.sanitize (c, this) &&
254 lsbMap.sanitize (c, this) &&
255 rsbMap.sanitize (c, this));
256 }
257
258 const VariationStore& get_var_store () const
259 { return this+varStore; }
260
261 void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
262 {
263 index_maps.push (&(this+advMap));
264 index_maps.push (&(this+lsbMap));
265 index_maps.push (&(this+rsbMap));
266 }
267
268 bool serialize_index_maps (hb_serialize_context_t *c,
269 const hb_array_t<index_map_subset_plan_t> &im_plans)
270 {
271 TRACE_SERIALIZE (this);
272 if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ())
273 advMap = 0;
274 else if (unlikely (!advMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX])))
275 return_trace (false);
276 if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ())
277 lsbMap = 0;
278 else if (unlikely (!lsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX])))
279 return_trace (false);
280 if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ())
281 rsbMap = 0;
282 else if (unlikely (!rsbMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX])))
283 return_trace (false);
284
285 return_trace (true);
286 }
287
288 template <typename T>
289 bool _subset (hb_subset_context_t *c) const
290 {
291 TRACE_SUBSET (this);
292 hvarvvar_subset_plan_t hvar_plan;
293 hb_vector_t<const DeltaSetIndexMap *>
294 index_maps;
295
296 ((T*)this)->listup_index_maps (index_maps);
297 hvar_plan.init (index_maps.as_array (), this+varStore, c->plan);
298
299 T *out = c->serializer->allocate_min<T> ();
300 if (unlikely (!out)) return_trace (false);
301
302 out->version.major = 1;
303 out->version.minor = 0;
304
305 if (unlikely (!out->varStore
306 .serialize_serialize (c->serializer,
307 hvar_plan.var_store,
308 hvar_plan.inner_maps.as_array ())))
309 return_trace (false);
310
311 return_trace (out->T::serialize_index_maps (c->serializer,
312 hvar_plan.index_map_plans.as_array ()));
313 }
314
315 float get_advance_delta_unscaled (hb_codepoint_t glyph,
316 const int *coords, unsigned int coord_count,
317 VariationStore::cache_t *store_cache = nullptr) const
318 {
319 uint32_t varidx = (this+advMap).map (glyph);
320 return (this+varStore).get_delta (varidx,
321 coords, coord_count,
322 store_cache);
323 }
324
325 bool get_lsb_delta_unscaled (hb_codepoint_t glyph,
326 const int *coords, unsigned int coord_count,
327 float *lsb) const
328 {
329 if (!lsbMap) return false;
330 uint32_t varidx = (this+lsbMap).map (glyph);
331 *lsb = (this+varStore).get_delta (varidx, coords, coord_count);
332 return true;
333 }
334
335 public:
336 FixedVersion<>version; /* Version of the metrics variation table
337 * initially set to 0x00010000u */
338 Offset32To<VariationStore>
339 varStore; /* Offset to item variation store table. */
340 Offset32To<DeltaSetIndexMap>
341 advMap; /* Offset to advance var-idx mapping. */
342 Offset32To<DeltaSetIndexMap>
343 lsbMap; /* Offset to lsb/tsb var-idx mapping. */
344 Offset32To<DeltaSetIndexMap>
345 rsbMap; /* Offset to rsb/bsb var-idx mapping. */
346
347 public:
348 DEFINE_SIZE_STATIC (20);
349};
350
351struct HVAR : HVARVVAR {
352 static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR;
353 bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<HVAR> (c); }
354};
355struct VVAR : HVARVVAR {
356 static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR;
357
358 bool sanitize (hb_sanitize_context_t *c) const
359 {
360 TRACE_SANITIZE (this);
361 return_trace (static_cast<const HVARVVAR *> (this)->sanitize (c) &&
362 vorgMap.sanitize (c, this));
363 }
364
365 void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
366 {
367 HVARVVAR::listup_index_maps (index_maps);
368 index_maps.push (&(this+vorgMap));
369 }
370
371 bool serialize_index_maps (hb_serialize_context_t *c,
372 const hb_array_t<index_map_subset_plan_t> &im_plans)
373 {
374 TRACE_SERIALIZE (this);
375 if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans)))
376 return_trace (false);
377 if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ())
378 vorgMap = 0;
379 else if (unlikely (!vorgMap.serialize_serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX])))
380 return_trace (false);
381
382 return_trace (true);
383 }
384
385 bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); }
386
387 bool get_vorg_delta_unscaled (hb_codepoint_t glyph,
388 const int *coords, unsigned int coord_count,
389 float *delta) const
390 {
391 if (!vorgMap) return false;
392 uint32_t varidx = (this+vorgMap).map (glyph);
393 *delta = (this+varStore).get_delta (varidx, coords, coord_count);
394 return true;
395 }
396
397 protected:
398 Offset32To<DeltaSetIndexMap>
399 vorgMap; /* Offset to vertical-origin var-idx mapping. */
400
401 public:
402 DEFINE_SIZE_STATIC (24);
403};
404
405} /* namespace OT */
406
407
408#endif /* HB_OT_VAR_HVAR_TABLE_HH */
409