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 | |
32 | |
33 | namespace OT { |
34 | |
35 | |
36 | struct DeltaSetIndexMap |
37 | { |
38 | bool sanitize (hb_sanitize_context_t *c) const |
39 | { |
40 | TRACE_SANITIZE (this); |
41 | return_trace (c->check_struct (this) && |
42 | c->check_range (mapDataZ.arrayZ, |
43 | mapCount, |
44 | get_width ())); |
45 | } |
46 | |
47 | template <typename T> |
48 | bool serialize (hb_serialize_context_t *c, const T &plan) |
49 | { |
50 | unsigned int width = plan.get_width (); |
51 | unsigned int inner_bit_count = plan.get_inner_bit_count (); |
52 | const hb_array_t<const unsigned int> output_map = plan.get_output_map (); |
53 | |
54 | TRACE_SERIALIZE (this); |
55 | if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0)))) |
56 | return_trace (false); |
57 | if (unlikely (!c->extend_min (*this))) return_trace (false); |
58 | |
59 | format = ((width-1)<<4)|(inner_bit_count-1); |
60 | mapCount = output_map.length; |
61 | HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length); |
62 | if (unlikely (!p)) return_trace (false); |
63 | for (unsigned int i = 0; i < output_map.length; i++) |
64 | { |
65 | unsigned int v = output_map[i]; |
66 | unsigned int outer = v >> 16; |
67 | unsigned int inner = v & 0xFFFF; |
68 | unsigned int u = (outer << inner_bit_count) | inner; |
69 | for (unsigned int w = width; w > 0;) |
70 | { |
71 | p[--w] = u; |
72 | u >>= 8; |
73 | } |
74 | p += width; |
75 | } |
76 | return_trace (true); |
77 | } |
78 | |
79 | unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ |
80 | { |
81 | /* If count is zero, pass value unchanged. This takes |
82 | * care of direct mapping for advance map. */ |
83 | if (!mapCount) |
84 | return v; |
85 | |
86 | if (v >= mapCount) |
87 | v = mapCount - 1; |
88 | |
89 | unsigned int u = 0; |
90 | { /* Fetch it. */ |
91 | unsigned int w = get_width (); |
92 | const HBUINT8 *p = mapDataZ.arrayZ + w * v; |
93 | for (; w; w--) |
94 | u = (u << 8) + *p++; |
95 | } |
96 | |
97 | { /* Repack it. */ |
98 | unsigned int n = get_inner_bit_count (); |
99 | unsigned int outer = u >> n; |
100 | unsigned int inner = u & ((1 << n) - 1); |
101 | u = (outer<<16) | inner; |
102 | } |
103 | |
104 | return u; |
105 | } |
106 | |
107 | unsigned int get_map_count () const { return mapCount; } |
108 | unsigned int get_width () const { return ((format >> 4) & 3) + 1; } |
109 | unsigned int get_inner_bit_count () const { return (format & 0xF) + 1; } |
110 | |
111 | protected: |
112 | HBUINT16 format; /* A packed field that describes the compressed |
113 | * representation of delta-set indices. */ |
114 | HBUINT16 mapCount; /* The number of mapping entries. */ |
115 | UnsizedArrayOf<HBUINT8> |
116 | mapDataZ; /* The delta-set index mapping data. */ |
117 | |
118 | public: |
119 | DEFINE_SIZE_ARRAY (4, mapDataZ); |
120 | }; |
121 | |
122 | struct index_map_subset_plan_t |
123 | { |
124 | enum index_map_index_t { |
125 | ADV_INDEX, |
126 | LSB_INDEX, /* dual as TSB */ |
127 | RSB_INDEX, /* dual as BSB */ |
128 | VORG_INDEX |
129 | }; |
130 | |
131 | void init (const DeltaSetIndexMap &index_map, |
132 | hb_inc_bimap_t &outer_map, |
133 | hb_vector_t<hb_set_t *> &inner_sets, |
134 | const hb_subset_plan_t *plan) |
135 | { |
136 | map_count = 0; |
137 | outer_bit_count = 0; |
138 | inner_bit_count = 1; |
139 | max_inners.init (); |
140 | output_map.init (); |
141 | |
142 | if (&index_map == &Null (DeltaSetIndexMap)) return; |
143 | |
144 | unsigned int last_val = (unsigned int)-1; |
145 | hb_codepoint_t last_gid = (hb_codepoint_t)-1; |
146 | hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ()); |
147 | |
148 | outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count (); |
149 | max_inners.resize (inner_sets.length); |
150 | for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0; |
151 | |
152 | /* Search backwards for a map value different from the last map value */ |
153 | for (; gid > 0; gid--) |
154 | { |
155 | hb_codepoint_t old_gid; |
156 | if (!plan->old_gid_for_new_gid (gid - 1, &old_gid)) |
157 | { |
158 | if (last_gid == (hb_codepoint_t) -1) |
159 | continue; |
160 | else |
161 | break; |
162 | } |
163 | |
164 | unsigned int v = index_map.map (old_gid); |
165 | if (last_gid == (hb_codepoint_t) -1) |
166 | { |
167 | last_val = v; |
168 | last_gid = gid; |
169 | continue; |
170 | } |
171 | if (v != last_val) break; |
172 | |
173 | last_gid = gid; |
174 | } |
175 | |
176 | if (unlikely (last_gid == (hb_codepoint_t)-1)) return; |
177 | map_count = last_gid; |
178 | for (gid = 0; gid < map_count; gid++) |
179 | { |
180 | hb_codepoint_t old_gid; |
181 | if (plan->old_gid_for_new_gid (gid, &old_gid)) |
182 | { |
183 | unsigned int v = index_map.map (old_gid); |
184 | unsigned int outer = v >> 16; |
185 | unsigned int inner = v & 0xFFFF; |
186 | outer_map.add (outer); |
187 | if (inner > max_inners[outer]) max_inners[outer] = inner; |
188 | if (outer >= inner_sets.length) return; |
189 | inner_sets[outer]->add (inner); |
190 | } |
191 | } |
192 | } |
193 | |
194 | void fini () |
195 | { |
196 | max_inners.fini (); |
197 | output_map.fini (); |
198 | } |
199 | |
200 | void remap (const DeltaSetIndexMap *input_map, |
201 | const hb_inc_bimap_t &outer_map, |
202 | const hb_vector_t<hb_inc_bimap_t> &inner_maps, |
203 | const hb_subset_plan_t *plan) |
204 | { |
205 | if (input_map == &Null (DeltaSetIndexMap)) return; |
206 | |
207 | for (unsigned int i = 0; i < max_inners.length; i++) |
208 | { |
209 | if (inner_maps[i].get_population () == 0) continue; |
210 | unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]); |
211 | if (bit_count > inner_bit_count) inner_bit_count = bit_count; |
212 | } |
213 | |
214 | output_map.resize (map_count); |
215 | for (hb_codepoint_t gid = 0; gid < output_map.length; gid++) |
216 | { |
217 | hb_codepoint_t old_gid; |
218 | if (plan->old_gid_for_new_gid (gid, &old_gid)) |
219 | { |
220 | unsigned int v = input_map->map (old_gid); |
221 | unsigned int outer = v >> 16; |
222 | output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); |
223 | } |
224 | else |
225 | output_map[gid] = 0; /* Map unused glyph to outer/inner=0/0 */ |
226 | } |
227 | } |
228 | |
229 | unsigned int get_inner_bit_count () const { return inner_bit_count; } |
230 | unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); } |
231 | unsigned int get_map_count () const { return map_count; } |
232 | |
233 | unsigned int get_size () const |
234 | { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } |
235 | |
236 | bool is_identity () const { return get_output_map ().length == 0; } |
237 | hb_array_t<const unsigned int> get_output_map () const { return output_map.as_array (); } |
238 | |
239 | protected: |
240 | unsigned int map_count; |
241 | hb_vector_t<unsigned int> max_inners; |
242 | unsigned int outer_bit_count; |
243 | unsigned int inner_bit_count; |
244 | hb_vector_t<unsigned int> output_map; |
245 | }; |
246 | |
247 | struct hvarvvar_subset_plan_t |
248 | { |
249 | hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {} |
250 | ~hvarvvar_subset_plan_t() { fini (); } |
251 | |
252 | void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps, |
253 | const VariationStore &_var_store, |
254 | const hb_subset_plan_t *plan) |
255 | { |
256 | index_map_plans.resize (index_maps.length); |
257 | |
258 | var_store = &_var_store; |
259 | inner_sets.resize (var_store->get_sub_table_count ()); |
260 | for (unsigned int i = 0; i < inner_sets.length; i++) |
261 | inner_sets[i] = hb_set_create (); |
262 | adv_set = hb_set_create (); |
263 | |
264 | inner_maps.resize (var_store->get_sub_table_count ()); |
265 | |
266 | for (unsigned int i = 0; i < inner_maps.length; i++) |
267 | inner_maps[i].init (); |
268 | |
269 | if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; |
270 | |
271 | bool retain_adv_map = false; |
272 | index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan); |
273 | if (index_maps[0] == &Null (DeltaSetIndexMap)) |
274 | { |
275 | retain_adv_map = plan->retain_gids; |
276 | outer_map.add (0); |
277 | for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) |
278 | { |
279 | hb_codepoint_t old_gid; |
280 | if (plan->old_gid_for_new_gid (gid, &old_gid)) |
281 | inner_sets[0]->add (old_gid); |
282 | } |
283 | hb_set_union (adv_set, inner_sets[0]); |
284 | } |
285 | |
286 | for (unsigned int i = 1; i < index_maps.length; i++) |
287 | index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan); |
288 | |
289 | outer_map.sort (); |
290 | |
291 | if (retain_adv_map) |
292 | { |
293 | for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) |
294 | if (inner_sets[0]->has (gid)) |
295 | inner_maps[0].add (gid); |
296 | else |
297 | inner_maps[0].skip (); |
298 | } |
299 | else |
300 | { |
301 | inner_maps[0].add_set (adv_set); |
302 | hb_set_subtract (inner_sets[0], adv_set); |
303 | inner_maps[0].add_set (inner_sets[0]); |
304 | } |
305 | |
306 | for (unsigned int i = 1; i < inner_maps.length; i++) |
307 | inner_maps[i].add_set (inner_sets[i]); |
308 | |
309 | for (unsigned int i = 0; i < index_maps.length; i++) |
310 | index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan); |
311 | } |
312 | |
313 | void fini () |
314 | { |
315 | for (unsigned int i = 0; i < inner_sets.length; i++) |
316 | hb_set_destroy (inner_sets[i]); |
317 | hb_set_destroy (adv_set); |
318 | inner_maps.fini_deep (); |
319 | index_map_plans.fini_deep (); |
320 | } |
321 | |
322 | hb_inc_bimap_t outer_map; |
323 | hb_vector_t<hb_inc_bimap_t> inner_maps; |
324 | hb_vector_t<index_map_subset_plan_t> index_map_plans; |
325 | const VariationStore *var_store; |
326 | |
327 | protected: |
328 | hb_vector_t<hb_set_t *> inner_sets; |
329 | hb_set_t *adv_set; |
330 | }; |
331 | |
332 | /* |
333 | * HVAR -- Horizontal Metrics Variations |
334 | * https://docs.microsoft.com/en-us/typography/opentype/spec/hvar |
335 | * VVAR -- Vertical Metrics Variations |
336 | * https://docs.microsoft.com/en-us/typography/opentype/spec/vvar |
337 | */ |
338 | #define HB_OT_TAG_HVAR HB_TAG('H','V','A','R') |
339 | #define HB_OT_TAG_VVAR HB_TAG('V','V','A','R') |
340 | |
341 | struct HVARVVAR |
342 | { |
343 | static constexpr hb_tag_t HVARTag = HB_OT_TAG_HVAR; |
344 | static constexpr hb_tag_t VVARTag = HB_OT_TAG_VVAR; |
345 | |
346 | bool sanitize (hb_sanitize_context_t *c) const |
347 | { |
348 | TRACE_SANITIZE (this); |
349 | return_trace (version.sanitize (c) && |
350 | likely (version.major == 1) && |
351 | varStore.sanitize (c, this) && |
352 | advMap.sanitize (c, this) && |
353 | lsbMap.sanitize (c, this) && |
354 | rsbMap.sanitize (c, this)); |
355 | } |
356 | |
357 | void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const |
358 | { |
359 | index_maps.push (&(this+advMap)); |
360 | index_maps.push (&(this+lsbMap)); |
361 | index_maps.push (&(this+rsbMap)); |
362 | } |
363 | |
364 | bool serialize_index_maps (hb_serialize_context_t *c, |
365 | const hb_array_t<index_map_subset_plan_t> &im_plans) |
366 | { |
367 | TRACE_SERIALIZE (this); |
368 | if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ()) |
369 | advMap = 0; |
370 | else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX]))) |
371 | return_trace (false); |
372 | if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ()) |
373 | lsbMap = 0; |
374 | else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX]))) |
375 | return_trace (false); |
376 | if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ()) |
377 | rsbMap = 0; |
378 | else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX]))) |
379 | return_trace (false); |
380 | |
381 | return_trace (true); |
382 | } |
383 | |
384 | template <typename T> |
385 | bool _subset (hb_subset_context_t *c) const |
386 | { |
387 | TRACE_SUBSET (this); |
388 | hvarvvar_subset_plan_t hvar_plan; |
389 | hb_vector_t<const DeltaSetIndexMap *> |
390 | index_maps; |
391 | |
392 | ((T*)this)->listup_index_maps (index_maps); |
393 | hvar_plan.init (index_maps.as_array (), this+varStore, c->plan); |
394 | |
395 | T *out = c->serializer->allocate_min<T> (); |
396 | if (unlikely (!out)) return_trace (false); |
397 | |
398 | out->version.major = 1; |
399 | out->version.minor = 0; |
400 | |
401 | if (unlikely (!out->varStore.serialize (c->serializer, out) |
402 | .serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ()))) |
403 | return_trace (false); |
404 | |
405 | return_trace (out->T::serialize_index_maps (c->serializer, |
406 | hvar_plan.index_map_plans.as_array ())); |
407 | } |
408 | |
409 | float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const |
410 | { |
411 | unsigned int varidx = (this+advMap).map (glyph); |
412 | return (this+varStore).get_delta (varidx, font->coords, font->num_coords); |
413 | } |
414 | |
415 | float get_side_bearing_var (hb_codepoint_t glyph, |
416 | const int *coords, unsigned int coord_count) const |
417 | { |
418 | if (!has_side_bearing_deltas ()) return 0.f; |
419 | unsigned int varidx = (this+lsbMap).map (glyph); |
420 | return (this+varStore).get_delta (varidx, coords, coord_count); |
421 | } |
422 | |
423 | bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } |
424 | |
425 | protected: |
426 | FixedVersion<>version; /* Version of the metrics variation table |
427 | * initially set to 0x00010000u */ |
428 | LOffsetTo<VariationStore> |
429 | varStore; /* Offset to item variation store table. */ |
430 | LOffsetTo<DeltaSetIndexMap> |
431 | advMap; /* Offset to advance var-idx mapping. */ |
432 | LOffsetTo<DeltaSetIndexMap> |
433 | lsbMap; /* Offset to lsb/tsb var-idx mapping. */ |
434 | LOffsetTo<DeltaSetIndexMap> |
435 | rsbMap; /* Offset to rsb/bsb var-idx mapping. */ |
436 | |
437 | public: |
438 | DEFINE_SIZE_STATIC (20); |
439 | }; |
440 | |
441 | struct HVAR : HVARVVAR { |
442 | static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR; |
443 | bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<HVAR> (c); } |
444 | }; |
445 | struct VVAR : HVARVVAR { |
446 | static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR; |
447 | |
448 | bool sanitize (hb_sanitize_context_t *c) const |
449 | { |
450 | TRACE_SANITIZE (this); |
451 | return_trace (static_cast<const HVARVVAR *> (this)->sanitize (c) && |
452 | vorgMap.sanitize (c, this)); |
453 | } |
454 | |
455 | void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const |
456 | { |
457 | HVARVVAR::listup_index_maps (index_maps); |
458 | index_maps.push (&(this+vorgMap)); |
459 | } |
460 | |
461 | bool serialize_index_maps (hb_serialize_context_t *c, |
462 | const hb_array_t<index_map_subset_plan_t> &im_plans) |
463 | { |
464 | TRACE_SERIALIZE (this); |
465 | if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans))) |
466 | return_trace (false); |
467 | if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ()) |
468 | vorgMap = 0; |
469 | else if (unlikely (!vorgMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX]))) |
470 | return_trace (false); |
471 | |
472 | return_trace (true); |
473 | } |
474 | |
475 | bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset<VVAR> (c); } |
476 | |
477 | protected: |
478 | LOffsetTo<DeltaSetIndexMap> |
479 | vorgMap; /* Offset to vertical-origin var-idx mapping. */ |
480 | |
481 | public: |
482 | DEFINE_SIZE_STATIC (24); |
483 | }; |
484 | |
485 | } /* namespace OT */ |
486 | |
487 | |
488 | #endif /* HB_OT_VAR_HVAR_TABLE_HH */ |
489 | |