1#ifndef OT_GLYF_GLYPH_HH
2#define OT_GLYF_GLYPH_HH
3
4
5#include "../../hb-open-type.hh"
6
7#include "GlyphHeader.hh"
8#include "SimpleGlyph.hh"
9#include "CompositeGlyph.hh"
10#include "VarCompositeGlyph.hh"
11#include "coord-setter.hh"
12
13
14namespace OT {
15
16struct glyf_accelerator_t;
17
18namespace glyf_impl {
19
20
21enum phantom_point_index_t
22{
23 PHANTOM_LEFT = 0,
24 PHANTOM_RIGHT = 1,
25 PHANTOM_TOP = 2,
26 PHANTOM_BOTTOM = 3,
27 PHANTOM_COUNT = 4
28};
29
30struct Glyph
31{
32 enum glyph_type_t {
33 EMPTY,
34 SIMPLE,
35 COMPOSITE,
36#ifndef HB_NO_VAR_COMPOSITES
37 VAR_COMPOSITE,
38#endif
39 };
40
41 public:
42 composite_iter_t get_composite_iterator () const
43 {
44 if (type != COMPOSITE) return composite_iter_t ();
45 return CompositeGlyph (*header, bytes).iter ();
46 }
47 var_composite_iter_t get_var_composite_iterator () const
48 {
49#ifndef HB_NO_VAR_COMPOSITES
50 if (type != VAR_COMPOSITE) return var_composite_iter_t ();
51 return VarCompositeGlyph (*header, bytes).iter ();
52#else
53 return var_composite_iter_t ();
54#endif
55 }
56
57 const hb_bytes_t trim_padding () const
58 {
59 switch (type) {
60#ifndef HB_NO_VAR_COMPOSITES
61 case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
62#endif
63 case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
64 case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
65 case EMPTY: return bytes;
66 default: return bytes;
67 }
68 }
69
70 void drop_hints ()
71 {
72 switch (type) {
73#ifndef HB_NO_VAR_COMPOSITES
74 case VAR_COMPOSITE: return; // No hinting
75#endif
76 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
77 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
78 case EMPTY: return;
79 }
80 }
81
82 void set_overlaps_flag ()
83 {
84 switch (type) {
85#ifndef HB_NO_VAR_COMPOSITES
86 case VAR_COMPOSITE: return; // No overlaps flag
87#endif
88 case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
89 case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
90 case EMPTY: return;
91 }
92 }
93
94 void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
95 {
96 switch (type) {
97#ifndef HB_NO_VAR_COMPOSITES
98 case VAR_COMPOSITE: return; // No hinting
99#endif
100 case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
101 case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
102 case EMPTY: return;
103 }
104 }
105
106 void update_mtx (const hb_subset_plan_t *plan,
107 int xMin, int xMax,
108 int yMin, int yMax,
109 const contour_point_vector_t &all_points) const
110 {
111 hb_codepoint_t new_gid = 0;
112 if (!plan->new_gid_for_old_gid (gid, &new_gid))
113 return;
114
115 if (type != EMPTY)
116 {
117 plan->bounds_width_vec[new_gid] = xMax - xMin;
118 plan->bounds_height_vec[new_gid] = yMax - yMin;
119 }
120
121 unsigned len = all_points.length;
122 float leftSideX = all_points[len - 4].x;
123 float rightSideX = all_points[len - 3].x;
124 float topSideY = all_points[len - 2].y;
125 float bottomSideY = all_points[len - 1].y;
126
127 uint32_t hash = hb_hash (new_gid);
128
129 signed hori_aw = roundf (rightSideX - leftSideX);
130 if (hori_aw < 0) hori_aw = 0;
131 int lsb = roundf (xMin - leftSideX);
132 plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
133 //flag value should be computed using non-empty glyphs
134 if (type != EMPTY && lsb != xMin)
135 plan->head_maxp_info.allXMinIsLsb = false;
136
137 signed vert_aw = roundf (topSideY - bottomSideY);
138 if (vert_aw < 0) vert_aw = 0;
139 int tsb = roundf (topSideY - yMax);
140 plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
141 }
142
143 bool compile_header_bytes (const hb_subset_plan_t *plan,
144 const contour_point_vector_t &all_points,
145 hb_bytes_t &dest_bytes /* OUT */) const
146 {
147 GlyphHeader *glyph_header = nullptr;
148 if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
149 {
150 glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
151 if (unlikely (!glyph_header)) return false;
152 }
153
154 float xMin = 0, xMax = 0;
155 float yMin = 0, yMax = 0;
156 if (all_points.length > 4)
157 {
158 xMin = xMax = all_points[0].x;
159 yMin = yMax = all_points[0].y;
160
161 unsigned count = all_points.length - 4;
162 for (unsigned i = 1; i < count; i++)
163 {
164 float x = all_points[i].x;
165 float y = all_points[i].y;
166 xMin = hb_min (xMin, x);
167 xMax = hb_max (xMax, x);
168 yMin = hb_min (yMin, y);
169 yMax = hb_max (yMax, y);
170 }
171 }
172
173
174 // These are destined for storage in a 16 bit field to clamp the values to
175 // fit into a 16 bit signed integer.
176 int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
177 int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
178 int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
179 int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
180
181 update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
182
183 if (type != EMPTY)
184 {
185 plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
186 plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
187 plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
188 plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
189 }
190
191 /* when pinned at default, no need to compile glyph header
192 * and for empty glyphs: all_points only include phantom points.
193 * just update metrics and then return */
194 if (!glyph_header)
195 return true;
196
197 glyph_header->numberOfContours = header->numberOfContours;
198
199 glyph_header->xMin = rounded_xMin;
200 glyph_header->yMin = rounded_yMin;
201 glyph_header->xMax = rounded_xMax;
202 glyph_header->yMax = rounded_yMax;
203
204 dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
205 return true;
206 }
207
208 bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
209 hb_font_t *font,
210 const glyf_accelerator_t &glyf,
211 hb_bytes_t &dest_start, /* IN/OUT */
212 hb_bytes_t &dest_end /* OUT */)
213 {
214 contour_point_vector_t all_points, points_with_deltas;
215 unsigned composite_contours = 0;
216 head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
217 unsigned *composite_contours_p = &composite_contours;
218
219 // don't compute head/maxp values when glyph has no contours(type is EMPTY)
220 // also ignore .notdef glyph when --notdef-outline is not enabled
221 if (type == EMPTY ||
222 (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
223 {
224 head_maxp_info_p = nullptr;
225 composite_contours_p = nullptr;
226 }
227
228 if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
229 return false;
230
231 // .notdef, set type to empty so we only update metrics and don't compile bytes for
232 // it
233 if (gid == 0 &&
234 !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
235 {
236 type = EMPTY;
237 dest_start = hb_bytes_t ();
238 dest_end = hb_bytes_t ();
239 }
240
241 //dont compile bytes when pinned at default, just recalculate bounds
242 if (!plan->pinned_at_default)
243 {
244 switch (type)
245 {
246#ifndef HB_NO_VAR_COMPOSITES
247 case VAR_COMPOSITE:
248 // TODO
249 dest_end = hb_bytes_t ();
250 break;
251#endif
252
253 case COMPOSITE:
254 if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
255 points_with_deltas,
256 dest_end))
257 return false;
258 break;
259 case SIMPLE:
260 if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
261 plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
262 dest_end))
263 return false;
264 break;
265 case EMPTY:
266 /* set empty bytes for empty glyph
267 * do not use source glyph's pointers */
268 dest_start = hb_bytes_t ();
269 dest_end = hb_bytes_t ();
270 break;
271 }
272 }
273
274 if (!compile_header_bytes (plan, all_points, dest_start))
275 {
276 dest_end.fini ();
277 return false;
278 }
279 return true;
280 }
281
282
283 /* Note: Recursively calls itself.
284 * all_points includes phantom points
285 */
286 template <typename accelerator_t>
287 bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
288 contour_point_vector_t &all_points /* OUT */,
289 contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
290 head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
291 unsigned *composite_contours = nullptr, /* OUT */
292 bool shift_points_hori = true,
293 bool use_my_metrics = true,
294 bool phantom_only = false,
295 hb_array_t<int> coords = hb_array_t<int> (),
296 unsigned int depth = 0,
297 unsigned *edge_count = nullptr) const
298 {
299 if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
300 unsigned stack_edge_count = 0;
301 if (!edge_count) edge_count = &stack_edge_count;
302 if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
303 (*edge_count)++;
304
305 if (head_maxp_info)
306 {
307 head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
308 }
309
310 if (!coords)
311 coords = hb_array (font->coords, font->num_coords);
312
313 contour_point_vector_t stack_points;
314 contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
315 unsigned old_length = points.length;
316
317 switch (type) {
318 case SIMPLE:
319 if (depth == 0 && head_maxp_info)
320 head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
321 if (depth > 0 && composite_contours)
322 *composite_contours += (unsigned) header->numberOfContours;
323 if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
324 return false;
325 break;
326 case COMPOSITE:
327 {
328 for (auto &item : get_composite_iterator ())
329 if (unlikely (!item.get_points (points))) return false;
330 break;
331 }
332#ifndef HB_NO_VAR_COMPOSITES
333 case VAR_COMPOSITE:
334 {
335 for (auto &item : get_var_composite_iterator ())
336 if (unlikely (!item.get_points (points))) return false;
337 break;
338 }
339#endif
340 case EMPTY:
341 break;
342 }
343
344 /* Init phantom points */
345 if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
346 hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
347 {
348 int lsb = 0;
349 int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
350 (int) header->xMin - lsb : 0;
351 HB_UNUSED int tsb = 0;
352 int v_orig = (int) header->yMax +
353#ifndef HB_NO_VERTICAL
354 ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
355#else
356 0
357#endif
358 ;
359 unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
360 unsigned v_adv =
361#ifndef HB_NO_VERTICAL
362 glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
363#else
364 - font->face->get_upem ()
365#endif
366 ;
367 phantoms[PHANTOM_LEFT].x = h_delta;
368 phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
369 phantoms[PHANTOM_TOP].y = v_orig;
370 phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
371 }
372
373#ifndef HB_NO_VAR
374 if (coords)
375 glyf_accelerator.gvar->apply_deltas_to_points (gid,
376 coords,
377 points.as_array ().sub_array (old_length),
378 phantom_only && type == SIMPLE);
379#endif
380
381 // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
382 // with child glyphs' points
383 if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
384 {
385 if (unlikely (!points_with_deltas->resize (points.length))) return false;
386 *points_with_deltas = points;
387 }
388
389 switch (type) {
390 case SIMPLE:
391 if (depth == 0 && head_maxp_info)
392 head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
393 break;
394 case COMPOSITE:
395 {
396 unsigned int comp_index = 0;
397 for (auto &item : get_composite_iterator ())
398 {
399 unsigned old_count = all_points.length;
400
401 if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
402 !glyf_accelerator.glyph_for_gid (item.get_gid ())
403 .get_points (font,
404 glyf_accelerator,
405 all_points,
406 points_with_deltas,
407 head_maxp_info,
408 composite_contours,
409 shift_points_hori,
410 use_my_metrics,
411 phantom_only,
412 coords,
413 depth + 1,
414 edge_count)))
415 return false;
416
417 auto comp_points = all_points.as_array ().sub_array (old_count);
418
419 /* Copy phantom points from component if USE_MY_METRICS flag set */
420 if (use_my_metrics && item.is_use_my_metrics ())
421 for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
422 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
423
424 if (comp_points) // Empty in case of phantom_only
425 {
426 float matrix[4];
427 contour_point_t default_trans;
428 item.get_transformation (matrix, default_trans);
429
430 /* Apply component transformation & translation (with deltas applied) */
431 item.transform_points (comp_points, matrix, points[comp_index]);
432 }
433
434 if (item.is_anchored () && !phantom_only)
435 {
436 unsigned int p1, p2;
437 item.get_anchor_points (p1, p2);
438 if (likely (p1 < all_points.length && p2 < comp_points.length))
439 {
440 contour_point_t delta;
441 delta.init (all_points[p1].x - comp_points[p2].x,
442 all_points[p1].y - comp_points[p2].y);
443
444 item.translate (delta, comp_points);
445 }
446 }
447
448 all_points.resize (all_points.length - PHANTOM_COUNT);
449
450 if (all_points.length > HB_GLYF_MAX_POINTS)
451 return false;
452
453 comp_index++;
454 }
455
456 if (head_maxp_info && depth == 0)
457 {
458 if (composite_contours)
459 head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
460 head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
461 head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
462 }
463 all_points.extend (phantoms);
464 } break;
465#ifndef HB_NO_VAR_COMPOSITES
466 case VAR_COMPOSITE:
467 {
468 hb_array_t<contour_point_t> points_left = points.as_array ();
469 for (auto &item : get_var_composite_iterator ())
470 {
471 unsigned item_num_points = item.get_num_points ();
472 hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
473 assert (record_points.length == item_num_points);
474
475 auto component_coords = coords;
476 /* Copying coords is expensive; so we have put an arbitrary
477 * limit on the max number of coords for now. */
478 if (item.is_reset_unspecified_axes () ||
479 coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
480 component_coords = hb_array<int> ();
481
482 coord_setter_t coord_setter (component_coords);
483 item.set_variations (coord_setter, record_points);
484
485 unsigned old_count = all_points.length;
486
487 if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
488 !glyf_accelerator.glyph_for_gid (item.get_gid ())
489 .get_points (font,
490 glyf_accelerator,
491 all_points,
492 points_with_deltas,
493 head_maxp_info,
494 nullptr,
495 shift_points_hori,
496 use_my_metrics,
497 phantom_only,
498 coord_setter.get_coords (),
499 depth + 1,
500 edge_count)))
501 return false;
502
503 auto comp_points = all_points.as_array ().sub_array (old_count);
504
505 /* Apply component transformation */
506 if (comp_points) // Empty in case of phantom_only
507 item.transform_points (record_points, comp_points);
508
509 /* Copy phantom points from component if USE_MY_METRICS flag set */
510 if (use_my_metrics && item.is_use_my_metrics ())
511 for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
512 phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
513
514 all_points.resize (all_points.length - PHANTOM_COUNT);
515
516 if (all_points.length > HB_GLYF_MAX_POINTS)
517 return false;
518
519 points_left += item_num_points;
520 }
521 all_points.extend (phantoms);
522 } break;
523#endif
524 case EMPTY:
525 all_points.extend (phantoms);
526 break;
527 }
528
529 if (depth == 0 && shift_points_hori) /* Apply at top level */
530 {
531 /* Undocumented rasterizer behavior:
532 * Shift points horizontally by the updated left side bearing
533 */
534 int v = -phantoms[PHANTOM_LEFT].x;
535 if (v)
536 for (auto &point : all_points)
537 point.x += v;
538 }
539
540 return !all_points.in_error ();
541 }
542
543 bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
544 hb_glyph_extents_t *extents) const
545 {
546 if (type == EMPTY) return true; /* Empty glyph; zero extents. */
547 return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
548 }
549
550 hb_bytes_t get_bytes () const { return bytes; }
551 glyph_type_t get_type () const { return type; }
552 const GlyphHeader *get_header () const { return header; }
553
554 Glyph () : bytes (),
555 header (bytes.as<GlyphHeader> ()),
556 gid (-1),
557 type(EMPTY)
558 {}
559
560 Glyph (hb_bytes_t bytes_,
561 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
562 header (bytes.as<GlyphHeader> ()),
563 gid (gid_)
564 {
565 int num_contours = header->numberOfContours;
566 if (unlikely (num_contours == 0)) type = EMPTY;
567 else if (num_contours > 0) type = SIMPLE;
568 else if (num_contours == -1) type = COMPOSITE;
569#ifndef HB_NO_VAR_COMPOSITES
570 else if (num_contours == -2) type = VAR_COMPOSITE;
571#endif
572 else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
573 }
574
575 protected:
576 hb_bytes_t bytes;
577 const GlyphHeader *header;
578 hb_codepoint_t gid;
579 glyph_type_t type;
580};
581
582
583} /* namespace glyf_impl */
584} /* namespace OT */
585
586
587#endif /* OT_GLYF_GLYPH_HH */
588