1/*
2 * Copyright © 2019 Adobe Inc.
3 * Copyright © 2019 Ebrahim Byagowi
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Adobe Author(s): Michiharu Ariza
26 */
27
28#ifndef HB_OT_VAR_GVAR_TABLE_HH
29#define HB_OT_VAR_GVAR_TABLE_HH
30
31#include "hb-open-type.hh"
32#include "hb-ot-var-common.hh"
33
34/*
35 * gvar -- Glyph Variation Table
36 * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar
37 */
38#define HB_OT_TAG_gvar HB_TAG('g','v','a','r')
39
40namespace OT {
41
42struct contour_point_t
43{
44 void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
45 { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
46
47 void transform (const float (&matrix)[4])
48 {
49 float x_ = x * matrix[0] + y * matrix[2];
50 y = x * matrix[1] + y * matrix[3];
51 x = x_;
52 }
53 HB_ALWAYS_INLINE
54 void translate (const contour_point_t &p) { x += p.x; y += p.y; }
55
56
57 float x;
58 float y;
59 uint8_t flag;
60 bool is_end_point;
61};
62
63struct contour_point_vector_t : hb_vector_t<contour_point_t>
64{
65 void extend (const hb_array_t<contour_point_t> &a)
66 {
67 unsigned int old_len = length;
68 if (unlikely (!resize (old_len + a.length, false)))
69 return;
70 auto arrayZ = this->arrayZ + old_len;
71 unsigned count = a.length;
72 hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
73 }
74};
75
76struct GlyphVariationData : TupleVariationData
77{};
78
79struct gvar
80{
81 static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar;
82
83 bool sanitize_shallow (hb_sanitize_context_t *c) const
84 {
85 TRACE_SANITIZE (this);
86 return_trace (c->check_struct (this) && (version.major == 1) &&
87 sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
88 (is_long_offset () ?
89 c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) :
90 c->check_array (get_short_offset_array (), c->get_num_glyphs () + 1)));
91 }
92
93 /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */
94 bool sanitize (hb_sanitize_context_t *c) const
95 { return sanitize_shallow (c); }
96
97 bool subset (hb_subset_context_t *c) const
98 {
99 TRACE_SUBSET (this);
100
101 unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
102
103 gvar *out = c->serializer->allocate_min<gvar> ();
104 if (unlikely (!out)) return_trace (false);
105
106 out->version.major = 1;
107 out->version.minor = 0;
108 out->axisCount = axisCount;
109 out->sharedTupleCount = sharedTupleCount;
110
111 unsigned int num_glyphs = c->plan->num_output_glyphs ();
112 out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
113
114 auto it = hb_iter (c->plan->new_to_old_gid_list);
115 if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
116 it++;
117 unsigned int subset_data_size = 0;
118 for (auto &_ : it)
119 {
120 hb_codepoint_t old_gid = _.second;
121 subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
122 }
123
124 bool long_offset = subset_data_size & ~0xFFFFu;
125 out->flags = long_offset ? 1 : 0;
126
127 HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
128 if (!subset_offsets) return_trace (false);
129
130 /* shared tuples */
131 if (!sharedTupleCount || !sharedTuples)
132 out->sharedTuples = 0;
133 else
134 {
135 unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount;
136 F2DOT14 *tuples = c->serializer->allocate_size<F2DOT14> (shared_tuple_size);
137 if (!tuples) return_trace (false);
138 out->sharedTuples = (char *) tuples - (char *) out;
139 hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
140 }
141
142 char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false);
143 if (!subset_data) return_trace (false);
144 out->dataZ = subset_data - (char *) out;
145
146
147 if (long_offset)
148 {
149 ((HBUINT32 *) subset_offsets)[0] = 0;
150 subset_offsets += 4;
151 }
152 else
153 {
154 ((HBUINT16 *) subset_offsets)[0] = 0;
155 subset_offsets += 2;
156 }
157 unsigned int glyph_offset = 0;
158
159 hb_codepoint_t last = 0;
160 it = hb_iter (c->plan->new_to_old_gid_list);
161 if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
162 it++;
163 for (auto &_ : it)
164 {
165 hb_codepoint_t gid = _.first;
166 hb_codepoint_t old_gid = _.second;
167
168 if (long_offset)
169 for (; last < gid; last++)
170 ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
171 else
172 for (; last < gid; last++)
173 ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
174
175 hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob,
176 glyph_count,
177 old_gid);
178
179 hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
180 subset_data += var_data_bytes.length;
181 glyph_offset += var_data_bytes.length;
182
183 if (long_offset)
184 ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
185 else
186 ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
187
188 last++; // Skip over gid
189 }
190
191 if (long_offset)
192 for (; last < num_glyphs; last++)
193 ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
194 else
195 for (; last < num_glyphs; last++)
196 ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
197
198 return_trace (true);
199 }
200
201 protected:
202 const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob,
203 unsigned glyph_count,
204 hb_codepoint_t glyph) const
205 {
206 unsigned start_offset = get_offset (glyph_count, glyph);
207 unsigned end_offset = get_offset (glyph_count, glyph+1);
208 if (unlikely (end_offset < start_offset)) return hb_bytes_t ();
209 unsigned length = end_offset - start_offset;
210 hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
211 return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t ();
212 }
213
214 bool is_long_offset () const { return flags & 1; }
215
216 unsigned get_offset (unsigned glyph_count, unsigned i) const
217 {
218 if (unlikely (i > glyph_count)) return 0;
219 _hb_compiler_memory_r_barrier ();
220 return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
221 }
222
223 const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; }
224 const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; }
225
226 public:
227 struct accelerator_t
228 {
229 accelerator_t (hb_face_t *face)
230 {
231 table = hb_sanitize_context_t ().reference_table<gvar> (face);
232 /* If sanitize failed, set glyphCount to 0. */
233 glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
234
235 /* For shared tuples that only have one axis active, shared the index of
236 * that axis as a cache. This will speed up caclulate_scalar() a lot
237 * for fonts with lots of axes and many "monovar" tuples. */
238 hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
239 unsigned count = table->sharedTupleCount;
240 if (unlikely (!shared_tuple_active_idx.resize (count, false))) return;
241 unsigned axis_count = table->axisCount;
242 for (unsigned i = 0; i < count; i++)
243 {
244 hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count);
245 int idx1 = -1, idx2 = -1;
246 for (unsigned j = 0; j < axis_count; j++)
247 {
248 const F2DOT14 &peak = tuple.arrayZ[j];
249 if (peak.to_int () != 0)
250 {
251 if (idx1 == -1)
252 idx1 = j;
253 else if (idx2 == -1)
254 idx2 = j;
255 else
256 {
257 idx1 = idx2 = -1;
258 break;
259 }
260 }
261 }
262 shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
263 }
264 }
265 ~accelerator_t () { table.destroy (); }
266
267 private:
268
269 static float infer_delta (const hb_array_t<contour_point_t> points,
270 const hb_array_t<contour_point_t> deltas,
271 unsigned int target, unsigned int prev, unsigned int next,
272 float contour_point_t::*m)
273 {
274 float target_val = points.arrayZ[target].*m;
275 float prev_val = points.arrayZ[prev].*m;
276 float next_val = points.arrayZ[next].*m;
277 float prev_delta = deltas.arrayZ[prev].*m;
278 float next_delta = deltas.arrayZ[next].*m;
279
280 if (prev_val == next_val)
281 return (prev_delta == next_delta) ? prev_delta : 0.f;
282 else if (target_val <= hb_min (prev_val, next_val))
283 return (prev_val < next_val) ? prev_delta : next_delta;
284 else if (target_val >= hb_max (prev_val, next_val))
285 return (prev_val > next_val) ? prev_delta : next_delta;
286
287 /* linear interpolation */
288 float r = (target_val - prev_val) / (next_val - prev_val);
289 return prev_delta + r * (next_delta - prev_delta);
290 }
291
292 static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
293 { return (i >= end) ? start : (i + 1); }
294
295 public:
296 bool apply_deltas_to_points (hb_codepoint_t glyph,
297 hb_array_t<int> coords,
298 const hb_array_t<contour_point_t> points,
299 bool phantom_only = false) const
300 {
301 if (unlikely (glyph >= glyphCount)) return true;
302
303 hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
304 if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
305 hb_vector_t<unsigned int> shared_indices;
306 GlyphVariationData::tuple_iterator_t iterator;
307 if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
308 var_data_bytes.arrayZ,
309 shared_indices, &iterator))
310 return true; /* so isn't applied at all */
311
312 /* Save original points for inferred delta calculation */
313 contour_point_vector_t orig_points_vec; // Populated lazily
314 auto orig_points = orig_points_vec.as_array ();
315
316 /* flag is used to indicate referenced point */
317 contour_point_vector_t deltas_vec; // Populated lazily
318 auto deltas = deltas_vec.as_array ();
319
320 hb_vector_t<unsigned> end_points; // Populated lazily
321
322 unsigned num_coords = table->axisCount;
323 hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords);
324
325 hb_vector_t<unsigned int> private_indices;
326 hb_vector_t<int> x_deltas;
327 hb_vector_t<int> y_deltas;
328 unsigned count = points.length;
329 bool flush = false;
330 do
331 {
332 float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples,
333 &shared_tuple_active_idx);
334 if (scalar == 0.f) continue;
335 const HBUINT8 *p = iterator.get_serialized_data ();
336 unsigned int length = iterator.current_tuple->get_data_size ();
337 if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
338 return false;
339
340 if (!deltas)
341 {
342 if (unlikely (!deltas_vec.resize (count, false))) return false;
343 deltas = deltas_vec.as_array ();
344 hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
345 (phantom_only ? 4 : count) * sizeof (deltas[0]));
346 }
347
348 const HBUINT8 *end = p + length;
349
350 bool has_private_points = iterator.current_tuple->has_private_points ();
351 if (has_private_points &&
352 !GlyphVariationData::unpack_points (p, private_indices, end))
353 return false;
354 const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
355
356 bool apply_to_all = (indices.length == 0);
357 unsigned int num_deltas = apply_to_all ? points.length : indices.length;
358 if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
359 if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
360 if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
361 if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
362
363 if (!apply_to_all)
364 {
365 if (!orig_points && !phantom_only)
366 {
367 orig_points_vec.extend (points);
368 if (unlikely (orig_points_vec.in_error ())) return false;
369 orig_points = orig_points_vec.as_array ();
370 }
371
372 if (flush)
373 {
374 for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
375 points.arrayZ[i].translate (deltas.arrayZ[i]);
376 flush = false;
377
378 }
379 hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
380 (phantom_only ? 4 : count) * sizeof (deltas[0]));
381 }
382
383 if (HB_OPTIMIZE_SIZE_VAL)
384 {
385 for (unsigned int i = 0; i < num_deltas; i++)
386 {
387 unsigned int pt_index;
388 if (apply_to_all)
389 pt_index = i;
390 else
391 {
392 pt_index = indices[i];
393 if (unlikely (pt_index >= deltas.length)) continue;
394 }
395 if (phantom_only && pt_index < count - 4) continue;
396 auto &delta = deltas.arrayZ[pt_index];
397 delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
398 delta.x += x_deltas.arrayZ[i] * scalar;
399 delta.y += y_deltas.arrayZ[i] * scalar;
400 }
401 }
402 else
403 {
404 /* Ouch. Four cases... for optimization. */
405 if (scalar != 1.0f)
406 {
407 if (apply_to_all)
408 for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
409 {
410 unsigned int pt_index = i;
411 auto &delta = deltas.arrayZ[pt_index];
412 delta.x += x_deltas.arrayZ[i] * scalar;
413 delta.y += y_deltas.arrayZ[i] * scalar;
414 }
415 else
416 for (unsigned int i = 0; i < num_deltas; i++)
417 {
418 unsigned int pt_index = indices[i];
419 if (unlikely (pt_index >= deltas.length)) continue;
420 if (phantom_only && pt_index < count - 4) continue;
421 auto &delta = deltas.arrayZ[pt_index];
422 delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
423 delta.x += x_deltas.arrayZ[i] * scalar;
424 delta.y += y_deltas.arrayZ[i] * scalar;
425 }
426 }
427 else
428 {
429 if (apply_to_all)
430 for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
431 {
432 unsigned int pt_index = i;
433 auto &delta = deltas.arrayZ[pt_index];
434 delta.x += x_deltas.arrayZ[i];
435 delta.y += y_deltas.arrayZ[i];
436 }
437 else
438 for (unsigned int i = 0; i < num_deltas; i++)
439 {
440 unsigned int pt_index = indices[i];
441 if (unlikely (pt_index >= deltas.length)) continue;
442 if (phantom_only && pt_index < count - 4) continue;
443 auto &delta = deltas.arrayZ[pt_index];
444 delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
445 delta.x += x_deltas.arrayZ[i];
446 delta.y += y_deltas.arrayZ[i];
447 }
448 }
449 }
450
451 /* infer deltas for unreferenced points */
452 if (!apply_to_all && !phantom_only)
453 {
454 if (!end_points)
455 {
456 for (unsigned i = 0; i < count; ++i)
457 if (points.arrayZ[i].is_end_point)
458 end_points.push (i);
459 if (unlikely (end_points.in_error ())) return false;
460 }
461
462 unsigned start_point = 0;
463 for (unsigned end_point : end_points)
464 {
465 /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
466 unsigned unref_count = 0;
467 for (unsigned i = start_point; i < end_point + 1; i++)
468 unref_count += deltas.arrayZ[i].flag;
469 unref_count = (end_point - start_point + 1) - unref_count;
470
471 unsigned j = start_point;
472 if (unref_count == 0 || unref_count > end_point - start_point)
473 goto no_more_gaps;
474
475 for (;;)
476 {
477 /* Locate the next gap of unreferenced points between two referenced points prev and next.
478 * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
479 */
480 unsigned int prev, next, i;
481 for (;;)
482 {
483 i = j;
484 j = next_index (i, start_point, end_point);
485 if (deltas.arrayZ[i].flag && !deltas.arrayZ[j].flag) break;
486 }
487 prev = j = i;
488 for (;;)
489 {
490 i = j;
491 j = next_index (i, start_point, end_point);
492 if (!deltas.arrayZ[i].flag && deltas.arrayZ[j].flag) break;
493 }
494 next = j;
495 /* Infer deltas for all unref points in the gap between prev and next */
496 i = prev;
497 for (;;)
498 {
499 i = next_index (i, start_point, end_point);
500 if (i == next) break;
501 deltas.arrayZ[i].x = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::x);
502 deltas.arrayZ[i].y = infer_delta (orig_points, deltas, i, prev, next, &contour_point_t::y);
503 if (--unref_count == 0) goto no_more_gaps;
504 }
505 }
506 no_more_gaps:
507 start_point = end_point + 1;
508 }
509 }
510
511 flush = true;
512
513 } while (iterator.move_to_next ());
514
515 if (flush)
516 {
517 for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
518 points.arrayZ[i].translate (deltas.arrayZ[i]);
519 }
520
521 return true;
522 }
523
524 unsigned int get_axis_count () const { return table->axisCount; }
525
526 private:
527 hb_blob_ptr_t<gvar> table;
528 unsigned glyphCount;
529 hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
530 };
531
532 protected:
533 FixedVersion<>version; /* Version number of the glyph variations table
534 * Set to 0x00010000u. */
535 HBUINT16 axisCount; /* The number of variation axes for this font. This must be
536 * the same number as axisCount in the 'fvar' table. */
537 HBUINT16 sharedTupleCount;
538 /* The number of shared tuple records. Shared tuple records
539 * can be referenced within glyph variation data tables for
540 * multiple glyphs, as opposed to other tuple records stored
541 * directly within a glyph variation data table. */
542 NNOffset32To<UnsizedArrayOf<F2DOT14>>
543 sharedTuples; /* Offset from the start of this table to the shared tuple records.
544 * Array of tuple records shared across all glyph variation data tables. */
545 HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of
546 * glyphs stored elsewhere in the font. */
547 HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows.
548 * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
549 * offsets are uint32. */
550 Offset32To<GlyphVariationData>
551 dataZ; /* Offset from the start of this table to the array of
552 * GlyphVariationData tables. */
553 UnsizedArrayOf<HBUINT8>
554 offsetZ; /* Offsets from the start of the GlyphVariationData array
555 * to each GlyphVariationData table. */
556 public:
557 DEFINE_SIZE_ARRAY (20, offsetZ);
558};
559
560struct gvar_accelerator_t : gvar::accelerator_t {
561 gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {}
562};
563
564} /* namespace OT */
565
566#endif /* HB_OT_VAR_GVAR_TABLE_HH */
567