• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace OT {
15 
16 struct glyf_accelerator_t;
17 
18 namespace glyf_impl {
19 
20 
21 enum 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 
30 struct 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:
get_composite_iteratorOT::glyf_impl::Glyph42   composite_iter_t get_composite_iterator () const
43   {
44     if (type != COMPOSITE) return composite_iter_t ();
45     return CompositeGlyph (*header, bytes).iter ();
46   }
get_var_composite_iteratorOT::glyf_impl::Glyph47   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 
trim_paddingOT::glyf_impl::Glyph57   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 
drop_hintsOT::glyf_impl::Glyph70   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 
set_overlaps_flagOT::glyf_impl::Glyph82   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 
drop_hints_bytesOT::glyf_impl::Glyph94   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 
get_all_points_without_varOT::glyf_impl::Glyph106   bool get_all_points_without_var (const hb_face_t *face,
107                                    contour_point_vector_t &points /* OUT */) const
108   {
109     switch (type) {
110     case SIMPLE:
111       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
112         return false;
113       break;
114     case COMPOSITE:
115     {
116       for (auto &item : get_composite_iterator ())
117         if (unlikely (!item.get_points (points))) return false;
118       break;
119     }
120 #ifndef HB_NO_VAR_COMPOSITES
121     case VAR_COMPOSITE:
122     {
123       for (auto &item : get_var_composite_iterator ())
124         if (unlikely (!item.get_points (points))) return false;
125       break;
126     }
127 #endif
128     case EMPTY:
129       break;
130     }
131 
132     /* Init phantom points */
133     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
134     hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
135     {
136       int lsb = 0;
137       int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
138                     (int) header->xMin - lsb : 0;
139       HB_UNUSED int tsb = 0;
140       int v_orig  = (int) header->yMax +
141 #ifndef HB_NO_VERTICAL
142                     ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
143 #else
144                     0
145 #endif
146                     ;
147       unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
148       unsigned v_adv =
149 #ifndef HB_NO_VERTICAL
150                        face->table.vmtx->get_advance_without_var_unscaled (gid)
151 #else
152                        - face->get_upem ()
153 #endif
154                        ;
155       phantoms[PHANTOM_LEFT].x = h_delta;
156       phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
157       phantoms[PHANTOM_TOP].y = v_orig;
158       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
159     }
160     return true;
161   }
162 
update_mtxOT::glyf_impl::Glyph163   void update_mtx (const hb_subset_plan_t *plan,
164                    int xMin, int xMax,
165                    int yMin, int yMax,
166                    const contour_point_vector_t &all_points) const
167   {
168     hb_codepoint_t new_gid = 0;
169     if (!plan->new_gid_for_old_gid (gid, &new_gid))
170       return;
171 
172     if (type != EMPTY)
173     {
174       plan->bounds_width_vec[new_gid] = xMax - xMin;
175       plan->bounds_height_vec[new_gid] = yMax - yMin;
176     }
177 
178     unsigned len = all_points.length;
179     float leftSideX = all_points[len - 4].x;
180     float rightSideX = all_points[len - 3].x;
181     float topSideY = all_points[len - 2].y;
182     float bottomSideY = all_points[len - 1].y;
183 
184     uint32_t hash = hb_hash (new_gid);
185 
186     signed hori_aw = roundf (rightSideX - leftSideX);
187     if (hori_aw < 0) hori_aw = 0;
188     int lsb = roundf (xMin - leftSideX);
189     plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
190     //flag value should be computed using non-empty glyphs
191     if (type != EMPTY && lsb != xMin)
192       plan->head_maxp_info.allXMinIsLsb = false;
193 
194     signed vert_aw = roundf (topSideY - bottomSideY);
195     if (vert_aw < 0) vert_aw = 0;
196     int tsb = roundf (topSideY - yMax);
197     plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
198   }
199 
compile_header_bytesOT::glyf_impl::Glyph200   bool compile_header_bytes (const hb_subset_plan_t *plan,
201                              const contour_point_vector_t &all_points,
202                              hb_bytes_t &dest_bytes /* OUT */) const
203   {
204     GlyphHeader *glyph_header = nullptr;
205     if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
206     {
207       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
208       if (unlikely (!glyph_header)) return false;
209     }
210 
211     float xMin = 0, xMax = 0;
212     float yMin = 0, yMax = 0;
213     if (all_points.length > 4)
214     {
215       xMin = xMax = all_points[0].x;
216       yMin = yMax = all_points[0].y;
217 
218       unsigned count = all_points.length - 4;
219       for (unsigned i = 1; i < count; i++)
220       {
221 	float x = all_points[i].x;
222 	float y = all_points[i].y;
223 	xMin = hb_min (xMin, x);
224 	xMax = hb_max (xMax, x);
225 	yMin = hb_min (yMin, y);
226 	yMax = hb_max (yMax, y);
227       }
228     }
229 
230 
231     // These are destined for storage in a 16 bit field to clamp the values to
232     // fit into a 16 bit signed integer.
233     int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
234     int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
235     int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
236     int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
237 
238     update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
239 
240     if (type != EMPTY)
241     {
242       plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
243       plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
244       plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
245       plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
246     }
247 
248     /* when pinned at default, no need to compile glyph header
249      * and for empty glyphs: all_points only include phantom points.
250      * just update metrics and then return */
251     if (!glyph_header)
252       return true;
253 
254     glyph_header->numberOfContours = header->numberOfContours;
255 
256     glyph_header->xMin = rounded_xMin;
257     glyph_header->yMin = rounded_yMin;
258     glyph_header->xMax = rounded_xMax;
259     glyph_header->yMax = rounded_yMax;
260 
261     dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
262     return true;
263   }
264 
compile_bytes_with_deltasOT::glyf_impl::Glyph265   bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
266                                   hb_font_t *font,
267                                   const glyf_accelerator_t &glyf,
268                                   hb_bytes_t &dest_start,  /* IN/OUT */
269                                   hb_bytes_t &dest_end /* OUT */)
270   {
271     contour_point_vector_t all_points, points_with_deltas;
272     unsigned composite_contours = 0;
273     head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
274     unsigned *composite_contours_p = &composite_contours;
275 
276     // don't compute head/maxp values when glyph has no contours(type is EMPTY)
277     // also ignore .notdef glyph when --notdef-outline is not enabled
278     if (type == EMPTY ||
279         (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
280     {
281       head_maxp_info_p = nullptr;
282       composite_contours_p = nullptr;
283     }
284 
285     if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
286       return false;
287 
288     // .notdef, set type to empty so we only update metrics and don't compile bytes for
289     // it
290     if (gid == 0 &&
291         !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
292     {
293       type = EMPTY;
294       dest_start = hb_bytes_t ();
295       dest_end = hb_bytes_t ();
296     }
297 
298     //dont compile bytes when pinned at default, just recalculate bounds
299     if (!plan->pinned_at_default)
300     {
301       switch (type)
302       {
303 #ifndef HB_NO_VAR_COMPOSITES
304       case VAR_COMPOSITE:
305 	// TODO
306 	dest_end = hb_bytes_t ();
307 	break;
308 #endif
309 
310       case COMPOSITE:
311         if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
312                                                                         points_with_deltas,
313                                                                         dest_end))
314           return false;
315         break;
316       case SIMPLE:
317         if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
318                                                                      plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
319                                                                      dest_end))
320           return false;
321         break;
322       case EMPTY:
323         /* set empty bytes for empty glyph
324          * do not use source glyph's pointers */
325         dest_start = hb_bytes_t ();
326         dest_end = hb_bytes_t ();
327         break;
328       }
329     }
330 
331     if (!compile_header_bytes (plan, all_points, dest_start))
332     {
333       dest_end.fini ();
334       return false;
335     }
336     return true;
337   }
338 
339 
340   /* Note: Recursively calls itself.
341    * all_points includes phantom points
342    */
343   template <typename accelerator_t>
get_pointsOT::glyf_impl::Glyph344   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
345 		   contour_point_vector_t &all_points /* OUT */,
346 		   contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
347 		   head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
348 		   unsigned *composite_contours = nullptr, /* OUT */
349 		   bool shift_points_hori = true,
350 		   bool use_my_metrics = true,
351 		   bool phantom_only = false,
352 		   hb_array_t<int> coords = hb_array_t<int> (),
353 		   hb_map_t *current_glyphs = nullptr,
354 		   unsigned int depth = 0,
355 		   unsigned *edge_count = nullptr) const
356   {
357     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
358     unsigned stack_edge_count = 0;
359     if (!edge_count) edge_count = &stack_edge_count;
360     if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
361     (*edge_count)++;
362 
363     hb_map_t current_glyphs_stack;
364     if (current_glyphs == nullptr)
365       current_glyphs = &current_glyphs_stack;
366 
367     if (head_maxp_info)
368     {
369       head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
370     }
371 
372     if (!coords)
373       coords = hb_array (font->coords, font->num_coords);
374 
375     contour_point_vector_t stack_points;
376     contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
377     unsigned old_length = points.length;
378 
379     switch (type) {
380     case SIMPLE:
381       if (depth == 0 && head_maxp_info)
382         head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
383       if (depth > 0 && composite_contours)
384         *composite_contours += (unsigned) header->numberOfContours;
385       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
386 	return false;
387       break;
388     case COMPOSITE:
389     {
390       for (auto &item : get_composite_iterator ())
391         if (unlikely (!item.get_points (points))) return false;
392       break;
393     }
394 #ifndef HB_NO_VAR_COMPOSITES
395     case VAR_COMPOSITE:
396     {
397       for (auto &item : get_var_composite_iterator ())
398         if (unlikely (!item.get_points (points))) return false;
399       break;
400     }
401 #endif
402     case EMPTY:
403       break;
404     }
405 
406     /* Init phantom points */
407     if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
408     hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
409     {
410       int lsb = 0;
411       int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
412 		    (int) header->xMin - lsb : 0;
413       HB_UNUSED int tsb = 0;
414       int v_orig  = (int) header->yMax +
415 #ifndef HB_NO_VERTICAL
416 		    ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
417 #else
418 		    0
419 #endif
420 		    ;
421       unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid);
422       unsigned v_adv =
423 #ifndef HB_NO_VERTICAL
424 		       glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid)
425 #else
426 		       - font->face->get_upem ()
427 #endif
428 		       ;
429       phantoms[PHANTOM_LEFT].x = h_delta;
430       phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
431       phantoms[PHANTOM_TOP].y = v_orig;
432       phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
433     }
434 
435 #ifndef HB_NO_VAR
436     if (coords)
437       glyf_accelerator.gvar->apply_deltas_to_points (gid,
438 						     coords,
439 						     points.as_array ().sub_array (old_length),
440 						     phantom_only && type == SIMPLE);
441 #endif
442 
443     // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
444     // with child glyphs' points
445     if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
446     {
447       if (unlikely (!points_with_deltas->resize (points.length))) return false;
448       *points_with_deltas = points;
449     }
450 
451     switch (type) {
452     case SIMPLE:
453       if (depth == 0 && head_maxp_info)
454         head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
455       break;
456     case COMPOSITE:
457     {
458       unsigned int comp_index = 0;
459       for (auto &item : get_composite_iterator ())
460       {
461 	hb_codepoint_t item_gid = item.get_gid ();
462 
463         if (unlikely (current_glyphs->has (item_gid)))
464 	  continue;
465 
466 	current_glyphs->add (item_gid);
467 
468 	unsigned old_count = all_points.length;
469 
470 	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
471 		      !glyf_accelerator.glyph_for_gid (item_gid)
472 				       .get_points (font,
473 						    glyf_accelerator,
474 						    all_points,
475 						    points_with_deltas,
476 						    head_maxp_info,
477 						    composite_contours,
478 						    shift_points_hori,
479 						    use_my_metrics,
480 						    phantom_only,
481 						    coords,
482 						    current_glyphs,
483 						    depth + 1,
484 						    edge_count)))
485 	{
486 	  current_glyphs->del (item_gid);
487 	  return false;
488 	}
489 
490 	auto comp_points = all_points.as_array ().sub_array (old_count);
491 
492 	/* Copy phantom points from component if USE_MY_METRICS flag set */
493 	if (use_my_metrics && item.is_use_my_metrics ())
494 	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
495 	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
496 
497 	if (comp_points) // Empty in case of phantom_only
498 	{
499 	  float matrix[4];
500 	  contour_point_t default_trans;
501 	  item.get_transformation (matrix, default_trans);
502 
503 	  /* Apply component transformation & translation (with deltas applied) */
504 	  item.transform_points (comp_points, matrix, points[comp_index]);
505 	}
506 
507 	if (item.is_anchored () && !phantom_only)
508 	{
509 	  unsigned int p1, p2;
510 	  item.get_anchor_points (p1, p2);
511 	  if (likely (p1 < all_points.length && p2 < comp_points.length))
512 	  {
513 	    contour_point_t delta;
514 	    delta.init (all_points[p1].x - comp_points[p2].x,
515 			all_points[p1].y - comp_points[p2].y);
516 
517 	    item.translate (delta, comp_points);
518 	  }
519 	}
520 
521 	all_points.resize (all_points.length - PHANTOM_COUNT);
522 
523 	if (all_points.length > HB_GLYF_MAX_POINTS)
524 	{
525 	  current_glyphs->del (item_gid);
526 	  return false;
527 	}
528 
529 	comp_index++;
530         current_glyphs->del (item_gid);
531       }
532 
533       if (head_maxp_info && depth == 0)
534       {
535         if (composite_contours)
536           head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
537         head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
538         head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
539       }
540       all_points.extend (phantoms);
541     } break;
542 #ifndef HB_NO_VAR_COMPOSITES
543     case VAR_COMPOSITE:
544     {
545       hb_array_t<contour_point_t> points_left = points.as_array ();
546       for (auto &item : get_var_composite_iterator ())
547       {
548 	hb_codepoint_t item_gid = item.get_gid ();
549 
550         if (unlikely (current_glyphs->has (item_gid)))
551 	  continue;
552 
553 	current_glyphs->add (item_gid);
554 
555 	unsigned item_num_points = item.get_num_points ();
556 	hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
557 	assert (record_points.length == item_num_points);
558 
559 	auto component_coords = coords;
560 	/* Copying coords is expensive; so we have put an arbitrary
561 	 * limit on the max number of coords for now. */
562 	if (item.is_reset_unspecified_axes () ||
563 	    coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
564 	  component_coords = hb_array<int> ();
565 
566 	coord_setter_t coord_setter (component_coords);
567 	item.set_variations (coord_setter, record_points);
568 
569 	unsigned old_count = all_points.length;
570 
571 	if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
572 		      !glyf_accelerator.glyph_for_gid (item_gid)
573 				       .get_points (font,
574 						    glyf_accelerator,
575 						    all_points,
576 						    points_with_deltas,
577 						    head_maxp_info,
578 						    nullptr,
579 						    shift_points_hori,
580 						    use_my_metrics,
581 						    phantom_only,
582 						    coord_setter.get_coords (),
583 						    current_glyphs,
584 						    depth + 1,
585 						    edge_count)))
586 	{
587 	  current_glyphs->del (item_gid);
588 	  return false;
589 	}
590 
591 	auto comp_points = all_points.as_array ().sub_array (old_count);
592 
593 	/* Apply component transformation */
594 	if (comp_points) // Empty in case of phantom_only
595 	  item.transform_points (record_points, comp_points);
596 
597 	/* Copy phantom points from component if USE_MY_METRICS flag set */
598 	if (use_my_metrics && item.is_use_my_metrics ())
599 	  for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
600 	    phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
601 
602 	all_points.resize (all_points.length - PHANTOM_COUNT);
603 
604 	if (all_points.length > HB_GLYF_MAX_POINTS)
605 	{
606 	  current_glyphs->del (item_gid);
607 	  return false;
608 	}
609 
610 	points_left += item_num_points;
611 
612         current_glyphs->del (item_gid);
613       }
614       all_points.extend (phantoms);
615     } break;
616 #endif
617     case EMPTY:
618       all_points.extend (phantoms);
619       break;
620     }
621 
622     if (depth == 0 && shift_points_hori) /* Apply at top level */
623     {
624       /* Undocumented rasterizer behavior:
625        * Shift points horizontally by the updated left side bearing
626        */
627       int v = -phantoms[PHANTOM_LEFT].x;
628       if (v)
629         for (auto &point : all_points)
630 	  point.x += v;
631     }
632 
633     return !all_points.in_error ();
634   }
635 
get_extents_without_var_scaledOT::glyf_impl::Glyph636   bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
637 				       hb_glyph_extents_t *extents) const
638   {
639     if (type == EMPTY) return true; /* Empty glyph; zero extents. */
640     return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
641   }
642 
get_bytesOT::glyf_impl::Glyph643   hb_bytes_t get_bytes () const { return bytes; }
get_typeOT::glyf_impl::Glyph644   glyph_type_t get_type () const { return type; }
get_headerOT::glyf_impl::Glyph645   const GlyphHeader *get_header () const { return header; }
646 
GlyphOT::glyf_impl::Glyph647   Glyph () : bytes (),
648              header (bytes.as<GlyphHeader> ()),
649              gid (-1),
650              type(EMPTY)
651   {}
652 
GlyphOT::glyf_impl::Glyph653   Glyph (hb_bytes_t bytes_,
654 	 hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
655                                                 header (bytes.as<GlyphHeader> ()),
656                                                 gid (gid_)
657   {
658     int num_contours = header->numberOfContours;
659     if (unlikely (num_contours == 0)) type = EMPTY;
660     else if (num_contours > 0) type = SIMPLE;
661     else if (num_contours == -1) type = COMPOSITE;
662 #ifndef HB_NO_VAR_COMPOSITES
663     else if (num_contours == -2) type = VAR_COMPOSITE;
664 #endif
665     else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
666   }
667 
668   protected:
669   hb_bytes_t bytes;
670   const GlyphHeader *header;
671   hb_codepoint_t gid;
672   glyph_type_t type;
673 };
674 
675 
676 } /* namespace glyf_impl */
677 } /* namespace OT */
678 
679 
680 #endif /* OT_GLYF_GLYPH_HH */
681