• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2015  Google, Inc.
3  * Copyright © 2019  Adobe Inc.
4  * Copyright © 2019  Ebrahim Byagowi
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter
27  * Adobe Author(s): Michiharu Ariza
28  */
29 
30 #ifndef HB_OT_GLYF_TABLE_HH
31 #define HB_OT_GLYF_TABLE_HH
32 
33 #include "hb-open-type.hh"
34 #include "hb-ot-head-table.hh"
35 #include "hb-ot-hmtx-table.hh"
36 #include "hb-ot-var-gvar-table.hh"
37 #include "hb-draw.hh"
38 
39 namespace OT {
40 
41 
42 /*
43  * loca -- Index to Location
44  * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
45  */
46 #define HB_OT_TAG_loca HB_TAG('l','o','c','a')
47 
48 #ifndef HB_MAX_COMPOSITE_OPERATIONS
49 #define HB_MAX_COMPOSITE_OPERATIONS 100000
50 #endif
51 
52 
53 struct loca
54 {
55   friend struct glyf;
56 
57   static constexpr hb_tag_t tableTag = HB_OT_TAG_loca;
58 
sanitizeOT::loca59   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
60   {
61     TRACE_SANITIZE (this);
62     return_trace (true);
63   }
64 
65   protected:
66   UnsizedArrayOf<HBUINT8>
67 		dataZ;	/* Location data. */
68   public:
69   DEFINE_SIZE_MIN (0);	/* In reality, this is UNBOUNDED() type; but since we always
70 			 * check the size externally, allow Null() object of it by
71 			 * defining it _MIN instead. */
72 };
73 
74 
75 /*
76  * glyf -- TrueType Glyph Data
77  * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
78  */
79 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
80 
81 
82 struct glyf
83 {
84   static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
85 
sanitizeOT::glyf86   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
87   {
88     TRACE_SANITIZE (this);
89     /* Runtime checks as eager sanitizing each glyph is costy */
90     return_trace (true);
91   }
92 
93   template<typename Iterator,
94 	   hb_requires (hb_is_source_of (Iterator, unsigned int))>
95   static bool
_add_loca_and_headOT::glyf96   _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets)
97   {
98     unsigned max_offset =
99     + padded_offsets
100     | hb_reduce (hb_add, 0)
101     ;
102     unsigned num_offsets = padded_offsets.len () + 1;
103     bool use_short_loca = max_offset < 0x1FFFF;
104     unsigned entry_size = use_short_loca ? 2 : 4;
105     char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
106 
107     if (unlikely (!loca_prime_data)) return false;
108 
109     DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d "
110 				"max_offset %d size %d",
111 	       entry_size, num_offsets, max_offset, entry_size * num_offsets);
112 
113     if (use_short_loca)
114       _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
115     else
116       _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
117 
118     hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
119 					   entry_size * num_offsets,
120 					   HB_MEMORY_MODE_WRITABLE,
121 					   loca_prime_data,
122 					   hb_free);
123 
124     bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
125 	       && _add_head_and_set_loca_version (plan, use_short_loca);
126 
127     hb_blob_destroy (loca_blob);
128     return result;
129   }
130 
131   template<typename IteratorIn, typename IteratorOut,
132 	   hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
133 	   hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
134   static void
_write_locaOT::glyf135   _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest)
136   {
137     unsigned int offset = 0;
138     dest << 0;
139     + it
140     | hb_map ([=, &offset] (unsigned int padded_size)
141 	      {
142 		offset += padded_size;
143 		DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
144 		return offset >> right_shift;
145 	      })
146     | hb_sink (dest)
147     ;
148   }
149 
150   /* requires source of SubsetGlyph complains the identifier isn't declared */
151   template <typename Iterator>
serializeOT::glyf152   bool serialize (hb_serialize_context_t *c,
153 		  Iterator it,
154 		  const hb_subset_plan_t *plan)
155   {
156     TRACE_SERIALIZE (this);
157     unsigned init_len = c->length ();
158     for (const auto &_ : it) _.serialize (c, plan);
159 
160     /* As a special case when all glyph in the font are empty, add a zero byte
161      * to the table, so that OTS doesn’t reject it, and to make the table work
162      * on Windows as well.
163      * See https://github.com/khaledhosny/ots/issues/52 */
164     if (init_len == c->length ())
165     {
166       HBUINT8 empty_byte;
167       empty_byte = 0;
168       c->copy (empty_byte);
169     }
170     return_trace (true);
171   }
172 
173   /* Byte region(s) per glyph to output
174      unpadded, hints removed if so requested
175      If we fail to process a glyph we produce an empty (0-length) glyph */
subsetOT::glyf176   bool subset (hb_subset_context_t *c) const
177   {
178     TRACE_SUBSET (this);
179 
180     glyf *glyf_prime = c->serializer->start_embed <glyf> ();
181     if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
182 
183     hb_vector_t<SubsetGlyph> glyphs;
184     _populate_subset_glyphs (c->plan, &glyphs);
185 
186     glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan);
187 
188     auto padded_offsets =
189     + hb_iter (glyphs)
190     | hb_map (&SubsetGlyph::padded_size)
191     ;
192 
193     if (unlikely (c->serializer->in_error ())) return_trace (false);
194     return_trace (c->serializer->check_success (_add_loca_and_head (c->plan,
195 								    padded_offsets)));
196   }
197 
198   template <typename SubsetGlyph>
199   void
_populate_subset_glyphsOT::glyf200   _populate_subset_glyphs (const hb_subset_plan_t   *plan,
201 			   hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const
202   {
203     OT::glyf::accelerator_t glyf;
204     glyf.init (plan->source);
205 
206     + hb_range (plan->num_output_glyphs ())
207     | hb_map ([&] (hb_codepoint_t new_gid)
208 	      {
209 		SubsetGlyph subset_glyph = {0};
210 		subset_glyph.new_gid = new_gid;
211 
212 		/* should never fail: all old gids should be mapped */
213 		if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
214 		  return subset_glyph;
215 
216 		if (new_gid == 0 &&
217                     !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
218 		  subset_glyph.source_glyph = Glyph ();
219 		else
220 		  subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
221 		if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
222                   subset_glyph.drop_hints_bytes ();
223 		else
224                   subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
225 		return subset_glyph;
226 	      })
227     | hb_sink (glyphs)
228     ;
229 
230     glyf.fini ();
231   }
232 
233   static bool
_add_head_and_set_loca_versionOT::glyf234   _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
235   {
236     hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source);
237     hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
238     hb_blob_destroy (head_blob);
239 
240     if (unlikely (!head_prime_blob))
241       return false;
242 
243     head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
244     head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
245     bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
246 
247     hb_blob_destroy (head_prime_blob);
248     return success;
249   }
250 
251   struct CompositeGlyphChain
252   {
253     protected:
254     enum composite_glyph_flag_t
255     {
256       ARG_1_AND_2_ARE_WORDS	= 0x0001,
257       ARGS_ARE_XY_VALUES	= 0x0002,
258       ROUND_XY_TO_GRID		= 0x0004,
259       WE_HAVE_A_SCALE		= 0x0008,
260       MORE_COMPONENTS		= 0x0020,
261       WE_HAVE_AN_X_AND_Y_SCALE	= 0x0040,
262       WE_HAVE_A_TWO_BY_TWO	= 0x0080,
263       WE_HAVE_INSTRUCTIONS	= 0x0100,
264       USE_MY_METRICS		= 0x0200,
265       OVERLAP_COMPOUND		= 0x0400,
266       SCALED_COMPONENT_OFFSET	= 0x0800,
267       UNSCALED_COMPONENT_OFFSET = 0x1000
268     };
269 
270     public:
get_sizeOT::glyf::CompositeGlyphChain271     unsigned int get_size () const
272     {
273       unsigned int size = min_size;
274       /* arg1 and 2 are int16 */
275       if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
276       /* arg1 and 2 are int8 */
277       else size += 2;
278 
279       /* One x 16 bit (scale) */
280       if (flags & WE_HAVE_A_SCALE) size += 2;
281       /* Two x 16 bit (xscale, yscale) */
282       else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
283       /* Four x 16 bit (xscale, scale01, scale10, yscale) */
284       else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
285 
286       return size;
287     }
288 
set_glyph_indexOT::glyf::CompositeGlyphChain289     void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; }
get_glyph_indexOT::glyf::CompositeGlyphChain290     hb_codepoint_t get_glyph_index ()       const { return glyphIndex; }
291 
drop_instructions_flagOT::glyf::CompositeGlyphChain292     void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
set_overlaps_flagOT::glyf::CompositeGlyphChain293     void set_overlaps_flag ()
294     {
295       flags = (uint16_t) flags | OVERLAP_COMPOUND;
296     }
297 
has_instructionsOT::glyf::CompositeGlyphChain298     bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
299 
has_moreOT::glyf::CompositeGlyphChain300     bool has_more ()          const { return   flags & MORE_COMPONENTS; }
is_use_my_metricsOT::glyf::CompositeGlyphChain301     bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
is_anchoredOT::glyf::CompositeGlyphChain302     bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
get_anchor_pointsOT::glyf::CompositeGlyphChain303     void get_anchor_points (unsigned int &point1, unsigned int &point2) const
304     {
305       const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
306       if (flags & ARG_1_AND_2_ARE_WORDS)
307       {
308 	point1 = ((const HBUINT16 *) p)[0];
309 	point2 = ((const HBUINT16 *) p)[1];
310       }
311       else
312       {
313 	point1 = p[0];
314 	point2 = p[1];
315       }
316     }
317 
transform_pointsOT::glyf::CompositeGlyphChain318     void transform_points (contour_point_vector_t &points) const
319     {
320       float matrix[4];
321       contour_point_t trans;
322       if (get_transformation (matrix, trans))
323       {
324 	if (scaled_offsets ())
325 	{
326 	  points.translate (trans);
327 	  points.transform (matrix);
328 	}
329 	else
330 	{
331 	  points.transform (matrix);
332 	  points.translate (trans);
333 	}
334       }
335     }
336 
337     protected:
scaled_offsetsOT::glyf::CompositeGlyphChain338     bool scaled_offsets () const
339     { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
340 
get_transformationOT::glyf::CompositeGlyphChain341     bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
342     {
343       matrix[0] = matrix[3] = 1.f;
344       matrix[1] = matrix[2] = 0.f;
345 
346       int tx, ty;
347       const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
348       if (flags & ARG_1_AND_2_ARE_WORDS)
349       {
350 	tx = *(const HBINT16 *) p;
351 	p += HBINT16::static_size;
352 	ty = *(const HBINT16 *) p;
353 	p += HBINT16::static_size;
354       }
355       else
356       {
357 	tx = *p++;
358 	ty = *p++;
359       }
360       if (is_anchored ()) tx = ty = 0;
361 
362       trans.init ((float) tx, (float) ty);
363 
364       {
365 	const F2DOT14 *points = (const F2DOT14 *) p;
366 	if (flags & WE_HAVE_A_SCALE)
367 	{
368 	  matrix[0] = matrix[3] = points[0].to_float ();
369 	  return true;
370 	}
371 	else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
372 	{
373 	  matrix[0] = points[0].to_float ();
374 	  matrix[3] = points[1].to_float ();
375 	  return true;
376 	}
377 	else if (flags & WE_HAVE_A_TWO_BY_TWO)
378 	{
379 	  matrix[0] = points[0].to_float ();
380 	  matrix[1] = points[1].to_float ();
381 	  matrix[2] = points[2].to_float ();
382 	  matrix[3] = points[3].to_float ();
383 	  return true;
384 	}
385       }
386       return tx || ty;
387     }
388 
389     protected:
390     HBUINT16	flags;
391     HBGlyphID16	glyphIndex;
392     public:
393     DEFINE_SIZE_MIN (4);
394   };
395 
396   struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &>
397   {
398     typedef const CompositeGlyphChain *__item_t__;
composite_iter_tOT::glyf::composite_iter_t399     composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
400         glyph (glyph_), current (nullptr), current_size (0)
401     {
402       set_next (current_);
403     }
404 
composite_iter_tOT::glyf::composite_iter_t405     composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
406 
__item__OT::glyf::composite_iter_t407     const CompositeGlyphChain &__item__ () const { return *current; }
__more__OT::glyf::composite_iter_t408     bool __more__ () const { return current; }
__next__OT::glyf::composite_iter_t409     void __next__ ()
410     {
411       if (!current->has_more ()) { current = nullptr; return; }
412 
413       set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
414     }
operator !=OT::glyf::composite_iter_t415     bool operator != (const composite_iter_t& o) const
416     { return glyph != o.glyph || current != o.current; }
417 
418 
set_nextOT::glyf::composite_iter_t419     void set_next (const CompositeGlyphChain *composite)
420     {
421       if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
422       {
423         current = nullptr;
424         current_size = 0;
425         return;
426       }
427       unsigned size = composite->get_size ();
428       if (!glyph.check_range (composite, size))
429       {
430         current = nullptr;
431         current_size = 0;
432         return;
433       }
434 
435       current = composite;
436       current_size = size;
437     }
438 
439     private:
440     hb_bytes_t glyph;
441     __item_t__ current;
442     unsigned current_size;
443   };
444 
445   enum phantom_point_index_t
446   {
447     PHANTOM_LEFT   = 0,
448     PHANTOM_RIGHT  = 1,
449     PHANTOM_TOP    = 2,
450     PHANTOM_BOTTOM = 3,
451     PHANTOM_COUNT  = 4
452   };
453 
454   struct accelerator_t;
455 
456   struct Glyph
457   {
458     enum simple_glyph_flag_t
459     {
460       FLAG_ON_CURVE       = 0x01,
461       FLAG_X_SHORT        = 0x02,
462       FLAG_Y_SHORT        = 0x04,
463       FLAG_REPEAT         = 0x08,
464       FLAG_X_SAME         = 0x10,
465       FLAG_Y_SAME         = 0x20,
466       FLAG_OVERLAP_SIMPLE = 0x40,
467       FLAG_RESERVED2      = 0x80
468     };
469 
470     private:
471     struct GlyphHeader
472     {
has_dataOT::glyf::Glyph::GlyphHeader473       bool has_data () const { return numberOfContours; }
474 
get_extentsOT::glyf::Glyph::GlyphHeader475       bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
476 		        hb_codepoint_t gid, hb_glyph_extents_t *extents) const
477       {
478 	/* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */
479 	/* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
480 	extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid));
481 	extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
482 	extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
483 	extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
484 
485 	return true;
486       }
487 
488       HBINT16	numberOfContours;
489 			/* If the number of contours is
490 			 * greater than or equal to zero,
491 			 * this is a simple glyph; if negative,
492 			 * this is a composite glyph. */
493       FWORD	xMin;	/* Minimum x for coordinate data. */
494       FWORD	yMin;	/* Minimum y for coordinate data. */
495       FWORD	xMax;	/* Maximum x for coordinate data. */
496       FWORD	yMax;	/* Maximum y for coordinate data. */
497       public:
498       DEFINE_SIZE_STATIC (10);
499     };
500 
501     struct SimpleGlyph
502     {
503       const GlyphHeader &header;
504       hb_bytes_t bytes;
SimpleGlyphOT::glyf::Glyph::SimpleGlyph505       SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
506 	header (header_), bytes (bytes_) {}
507 
instruction_len_offsetOT::glyf::Glyph::SimpleGlyph508       unsigned int instruction_len_offset () const
509       { return GlyphHeader::static_size + 2 * header.numberOfContours; }
510 
lengthOT::glyf::Glyph::SimpleGlyph511       unsigned int length (unsigned int instruction_len) const
512       { return instruction_len_offset () + 2 + instruction_len; }
513 
instructions_lengthOT::glyf::Glyph::SimpleGlyph514       unsigned int instructions_length () const
515       {
516 	unsigned int instruction_length_offset = instruction_len_offset ();
517 	if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
518 
519 	const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
520 	/* Out of bounds of the current glyph */
521 	if (unlikely (length (instructionLength) > bytes.length)) return 0;
522 	return instructionLength;
523       }
524 
trim_paddingOT::glyf::Glyph::SimpleGlyph525       const Glyph trim_padding () const
526       {
527 	/* based on FontTools _g_l_y_f.py::trim */
528 	const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
529 	const uint8_t *glyph_end = glyph + bytes.length;
530 	/* simple glyph w/contours, possibly trimmable */
531 	glyph += instruction_len_offset ();
532 
533 	if (unlikely (glyph + 2 >= glyph_end)) return Glyph ();
534 	unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
535 	unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
536 
537 	glyph += 2 + num_instructions;
538 
539 	unsigned int coord_bytes = 0;
540 	unsigned int coords_with_flags = 0;
541 	while (glyph < glyph_end)
542 	{
543 	  uint8_t flag = *glyph;
544 	  glyph++;
545 
546 	  unsigned int repeat = 1;
547 	  if (flag & FLAG_REPEAT)
548 	  {
549 	    if (unlikely (glyph >= glyph_end)) return Glyph ();
550 	    repeat = *glyph + 1;
551 	    glyph++;
552 	  }
553 
554 	  unsigned int xBytes, yBytes;
555 	  xBytes = yBytes = 0;
556 	  if (flag & FLAG_X_SHORT) xBytes = 1;
557 	  else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
558 
559 	  if (flag & FLAG_Y_SHORT) yBytes = 1;
560 	  else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
561 
562 	  coord_bytes += (xBytes + yBytes) * repeat;
563 	  coords_with_flags += repeat;
564 	  if (coords_with_flags >= num_coordinates) break;
565 	}
566 
567 	if (unlikely (coords_with_flags != num_coordinates)) return Glyph ();
568 	return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)));
569       }
570 
571       /* zero instruction length */
drop_hintsOT::glyf::Glyph::SimpleGlyph572       void drop_hints ()
573       {
574 	GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
575 	(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
576       }
577 
drop_hints_bytesOT::glyf::Glyph::SimpleGlyph578       void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
579       {
580 	unsigned int instructions_len = instructions_length ();
581 	unsigned int glyph_length = length (instructions_len);
582 	dest_start = bytes.sub_array (0, glyph_length - instructions_len);
583 	dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
584       }
585 
set_overlaps_flagOT::glyf::Glyph::SimpleGlyph586       void set_overlaps_flag ()
587       {
588         if (unlikely (!header.numberOfContours)) return;
589 
590         unsigned flags_offset = length (instructions_length ());
591         if (unlikely (length (flags_offset + 1) > bytes.length)) return;
592 
593 	HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
594         first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
595       }
596 
read_pointsOT::glyf::Glyph::SimpleGlyph597       static bool read_points (const HBUINT8 *&p /* IN/OUT */,
598 			       contour_point_vector_t &points_ /* IN/OUT */,
599 			       const hb_bytes_t &bytes,
600 			       void (* setter) (contour_point_t &_, float v),
601 			       const simple_glyph_flag_t short_flag,
602 			       const simple_glyph_flag_t same_flag)
603       {
604 	float v = 0;
605 	for (unsigned i = 0; i < points_.length; i++)
606 	{
607 	  uint8_t flag = points_[i].flag;
608 	  if (flag & short_flag)
609 	  {
610 	    if (unlikely (!bytes.check_range (p))) return false;
611 	    if (flag & same_flag)
612 	      v += *p++;
613 	    else
614 	      v -= *p++;
615 	  }
616 	  else
617 	  {
618 	    if (!(flag & same_flag))
619 	    {
620 	      if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false;
621 	      v += *(const HBINT16 *) p;
622 	      p += HBINT16::static_size;
623 	    }
624 	  }
625 	  setter (points_[i], v);
626 	}
627 	return true;
628       }
629 
get_contour_pointsOT::glyf::Glyph::SimpleGlyph630       bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
631 			       bool phantom_only = false) const
632       {
633 	const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
634 	int num_contours = header.numberOfContours;
635 	if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
636 	unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
637 
638 	points_.resize (num_points);
639 	for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
640 	if (phantom_only) return true;
641 
642 	for (int i = 0; i < num_contours; i++)
643 	  points_[endPtsOfContours[i]].is_end_point = true;
644 
645 	/* Skip instructions */
646 	const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
647 						     endPtsOfContours[num_contours]);
648 
649 	/* Read flags */
650 	for (unsigned int i = 0; i < num_points; i++)
651 	{
652 	  if (unlikely (!bytes.check_range (p))) return false;
653 	  uint8_t flag = *p++;
654 	  points_[i].flag = flag;
655 	  if (flag & FLAG_REPEAT)
656 	  {
657 	    if (unlikely (!bytes.check_range (p))) return false;
658 	    unsigned int repeat_count = *p++;
659 	    while ((repeat_count-- > 0) && (++i < num_points))
660 	      points_[i].flag = flag;
661 	  }
662 	}
663 
664 	/* Read x & y coordinates */
665 	return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; },
666 			    FLAG_X_SHORT, FLAG_X_SAME)
667 	    && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; },
668 			    FLAG_Y_SHORT, FLAG_Y_SAME);
669       }
670     };
671 
672     struct CompositeGlyph
673     {
674       const GlyphHeader &header;
675       hb_bytes_t bytes;
CompositeGlyphOT::glyf::Glyph::CompositeGlyph676       CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
677 	header (header_), bytes (bytes_) {}
678 
get_iteratorOT::glyf::Glyph::CompositeGlyph679       composite_iter_t get_iterator () const
680       { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); }
681 
instructions_lengthOT::glyf::Glyph::CompositeGlyph682       unsigned int instructions_length (hb_bytes_t bytes) const
683       {
684 	unsigned int start = bytes.length;
685 	unsigned int end = bytes.length;
686 	const CompositeGlyphChain *last = nullptr;
687 	for (auto &item : get_iterator ())
688 	  last = &item;
689 	if (unlikely (!last)) return 0;
690 
691 	if (last->has_instructions ())
692 	  start = (char *) last - &bytes + last->get_size ();
693 	if (unlikely (start > end)) return 0;
694 	return end - start;
695       }
696 
697       /* Trimming for composites not implemented.
698        * If removing hints it falls out of that. */
trim_paddingOT::glyf::Glyph::CompositeGlyph699       const Glyph trim_padding () const { return Glyph (bytes); }
700 
drop_hintsOT::glyf::Glyph::CompositeGlyph701       void drop_hints ()
702       {
703 	for (const auto &_ : get_iterator ())
704 	  const_cast<CompositeGlyphChain &> (_).drop_instructions_flag ();
705       }
706 
707       /* Chop instructions off the end */
drop_hints_bytesOT::glyf::Glyph::CompositeGlyph708       void drop_hints_bytes (hb_bytes_t &dest_start) const
709       { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
710 
set_overlaps_flagOT::glyf::Glyph::CompositeGlyph711       void set_overlaps_flag ()
712       {
713         const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
714                 .set_overlaps_flag ();
715       }
716     };
717 
718     enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
719 
720     public:
get_composite_iteratorOT::glyf::Glyph721     composite_iter_t get_composite_iterator () const
722     {
723       if (type != COMPOSITE) return composite_iter_t ();
724       return CompositeGlyph (*header, bytes).get_iterator ();
725     }
726 
trim_paddingOT::glyf::Glyph727     const Glyph trim_padding () const
728     {
729       switch (type) {
730       case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
731       case SIMPLE:    return SimpleGlyph (*header, bytes).trim_padding ();
732       default:        return bytes;
733       }
734     }
735 
drop_hintsOT::glyf::Glyph736     void drop_hints ()
737     {
738       switch (type) {
739       case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
740       case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints (); return;
741       default:        return;
742       }
743     }
744 
set_overlaps_flagOT::glyf::Glyph745     void set_overlaps_flag ()
746     {
747       switch (type) {
748       case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
749       case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
750       default:        return;
751       }
752     }
753 
drop_hints_bytesOT::glyf::Glyph754     void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
755     {
756       switch (type) {
757       case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
758       case SIMPLE:    SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
759       default:        return;
760       }
761     }
762 
763     /* Note: Recursively calls itself.
764      * all_points includes phantom points
765      */
get_pointsOT::glyf::Glyph766     bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
767 		     contour_point_vector_t &all_points /* OUT */,
768 		     bool phantom_only = false,
769 		     unsigned int depth = 0) const
770     {
771       if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
772       contour_point_vector_t points;
773 
774       switch (type) {
775       case COMPOSITE:
776       {
777 	/* pseudo component points for each component in composite glyph */
778 	unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ());
779 	if (unlikely (!points.resize (num_points))) return false;
780 	for (unsigned i = 0; i < points.length; i++)
781 	  points[i].init ();
782 	break;
783       }
784       case SIMPLE:
785 	if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
786 	  return false;
787 	break;
788       }
789 
790       /* Init phantom points */
791       if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
792       hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
793       {
794 	for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
795 	int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid);
796 	int v_orig  = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid);
797 	unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid);
798 	unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid);
799 	phantoms[PHANTOM_LEFT].x = h_delta;
800 	phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
801 	phantoms[PHANTOM_TOP].y = v_orig;
802 	phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
803       }
804 
805 #ifndef HB_NO_VAR
806       if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ())))
807 	return false;
808 #endif
809 
810       switch (type) {
811       case SIMPLE:
812 	all_points.extend (points.as_array ());
813 	break;
814       case COMPOSITE:
815       {
816 	unsigned int comp_index = 0;
817 	for (auto &item : get_composite_iterator ())
818 	{
819 	  contour_point_vector_t comp_points;
820 	  if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ())
821 					 .get_points (font, glyf_accelerator, comp_points,
822 			 			      phantom_only, depth + 1)
823 			|| comp_points.length < PHANTOM_COUNT))
824 	    return false;
825 
826 	  /* Copy phantom points from component if USE_MY_METRICS flag set */
827 	  if (item.is_use_my_metrics ())
828 	    for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
829 	      phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
830 
831 	  /* Apply component transformation & translation */
832 	  item.transform_points (comp_points);
833 
834 	  /* Apply translation from gvar */
835 	  comp_points.translate (points[comp_index]);
836 
837 	  if (item.is_anchored ())
838 	  {
839 	    unsigned int p1, p2;
840 	    item.get_anchor_points (p1, p2);
841 	    if (likely (p1 < all_points.length && p2 < comp_points.length))
842 	    {
843 	      contour_point_t delta;
844 	      delta.init (all_points[p1].x - comp_points[p2].x,
845 			  all_points[p1].y - comp_points[p2].y);
846 
847 	      comp_points.translate (delta);
848 	    }
849 	  }
850 
851 	  all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
852 
853 	  comp_index++;
854 	}
855 
856 	all_points.extend (phantoms);
857       } break;
858       default:
859 	all_points.extend (phantoms);
860       }
861 
862       if (depth == 0) /* Apply at top level */
863       {
864 	/* Undocumented rasterizer behavior:
865 	 * Shift points horizontally by the updated left side bearing
866 	 */
867 	contour_point_t delta;
868 	delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
869 	if (delta.x) all_points.translate (delta);
870       }
871 
872       return true;
873     }
874 
get_extentsOT::glyf::Glyph875     bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator,
876 		      hb_glyph_extents_t *extents) const
877     {
878       if (type == EMPTY) return true; /* Empty glyph; zero extents. */
879       return header->get_extents (font, glyf_accelerator, gid, extents);
880     }
881 
get_bytesOT::glyf::Glyph882     hb_bytes_t get_bytes () const { return bytes; }
883 
GlyphOT::glyf::Glyph884     Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
885 	   hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_),
886 							header (bytes.as<GlyphHeader> ())
887     {
888       int num_contours = header->numberOfContours;
889       if (unlikely (num_contours == 0)) type = EMPTY;
890       else if (num_contours > 0) type = SIMPLE;
891       else type = COMPOSITE; /* negative numbers */
892     }
893 
894     protected:
895     hb_bytes_t bytes;
896     hb_codepoint_t gid;
897     const GlyphHeader *header;
898     unsigned type;
899   };
900 
901   struct accelerator_t
902   {
initOT::glyf::accelerator_t903     void init (hb_face_t *face_)
904     {
905       short_offset = false;
906       num_glyphs = 0;
907       loca_table = nullptr;
908       glyf_table = nullptr;
909 #ifndef HB_NO_VAR
910       gvar = nullptr;
911 #endif
912       hmtx = nullptr;
913       vmtx = nullptr;
914       face = face_;
915       const OT::head &head = *face->table.head;
916       if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
917 	/* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
918 	return;
919       short_offset = 0 == head.indexToLocFormat;
920 
921       loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
922       glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
923 #ifndef HB_NO_VAR
924       gvar = face->table.gvar;
925 #endif
926       hmtx = face->table.hmtx;
927       vmtx = face->table.vmtx;
928 
929       num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
930       num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
931     }
932 
finiOT::glyf::accelerator_t933     void fini ()
934     {
935       loca_table.destroy ();
936       glyf_table.destroy ();
937     }
938 
939     protected:
940     template<typename T>
get_pointsOT::glyf::accelerator_t941     bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
942     {
943       if (gid >= num_glyphs) return false;
944 
945       /* Making this allocfree is not that easy
946 	 https://github.com/harfbuzz/harfbuzz/issues/2095
947 	 mostly because of gvar handling in VF fonts,
948 	 perhaps a separate path for non-VF fonts can be considered */
949       contour_point_vector_t all_points;
950 
951       bool phantom_only = !consumer.is_consuming_contour_points ();
952       if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
953 	return false;
954 
955       if (consumer.is_consuming_contour_points ())
956       {
957 	for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index)
958 	  consumer.consume_point (all_points[point_index]);
959 	consumer.points_end ();
960       }
961 
962       /* Where to write phantoms, nullptr if not requested */
963       contour_point_t *phantoms = consumer.get_phantoms_sink ();
964       if (phantoms)
965 	for (unsigned i = 0; i < PHANTOM_COUNT; ++i)
966 	  phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i];
967 
968       return true;
969     }
970 
971 #ifndef HB_NO_VAR
972     struct points_aggregator_t
973     {
974       hb_font_t *font;
975       hb_glyph_extents_t *extents;
976       contour_point_t *phantoms;
977 
978       struct contour_bounds_t
979       {
contour_bounds_tOT::glyf::accelerator_t::points_aggregator_t::contour_bounds_t980 	contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
981 
addOT::glyf::accelerator_t::points_aggregator_t::contour_bounds_t982 	void add (const contour_point_t &p)
983 	{
984 	  min_x = hb_min (min_x, p.x);
985 	  min_y = hb_min (min_y, p.y);
986 	  max_x = hb_max (max_x, p.x);
987 	  max_y = hb_max (max_y, p.y);
988 	}
989 
emptyOT::glyf::accelerator_t::points_aggregator_t::contour_bounds_t990 	bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
991 
get_extentsOT::glyf::accelerator_t::points_aggregator_t::contour_bounds_t992 	void get_extents (hb_font_t *font, hb_glyph_extents_t *extents)
993 	{
994 	  if (unlikely (empty ()))
995 	  {
996 	    extents->width = 0;
997 	    extents->x_bearing = 0;
998 	    extents->height = 0;
999 	    extents->y_bearing = 0;
1000 	    return;
1001 	  }
1002 	  extents->x_bearing = font->em_scalef_x (min_x);
1003 	  extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
1004 	  extents->y_bearing = font->em_scalef_y (max_y);
1005 	  extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
1006 	}
1007 
1008 	protected:
1009 	float min_x, min_y, max_x, max_y;
1010       } bounds;
1011 
points_aggregator_tOT::glyf::accelerator_t::points_aggregator_t1012       points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_)
1013       {
1014 	font = font_;
1015 	extents = extents_;
1016 	phantoms = phantoms_;
1017 	if (extents) bounds = contour_bounds_t ();
1018       }
1019 
consume_pointOT::glyf::accelerator_t::points_aggregator_t1020       void consume_point (const contour_point_t &point) { bounds.add (point); }
points_endOT::glyf::accelerator_t::points_aggregator_t1021       void points_end () { bounds.get_extents (font, extents); }
1022 
is_consuming_contour_pointsOT::glyf::accelerator_t::points_aggregator_t1023       bool is_consuming_contour_points () { return extents; }
get_phantoms_sinkOT::glyf::accelerator_t::points_aggregator_t1024       contour_point_t *get_phantoms_sink () { return phantoms; }
1025     };
1026 
1027     public:
1028     unsigned
get_advance_varOT::glyf::accelerator_t1029     get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
1030     {
1031       if (unlikely (gid >= num_glyphs)) return 0;
1032 
1033       bool success = false;
1034 
1035       contour_point_t phantoms[PHANTOM_COUNT];
1036       if (likely (font->num_coords == gvar->get_axis_count ()))
1037 	success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms));
1038 
1039       if (unlikely (!success))
1040 	return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid);
1041 
1042       float result = is_vertical
1043 		   ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y
1044 		   : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x;
1045       return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
1046     }
1047 
get_side_bearing_varOT::glyf::accelerator_t1048     int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
1049     {
1050       if (unlikely (gid >= num_glyphs)) return 0;
1051 
1052       hb_glyph_extents_t extents;
1053 
1054       contour_point_t phantoms[PHANTOM_COUNT];
1055       if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms))))
1056 	return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid);
1057 
1058       return is_vertical
1059 	   ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing
1060 	   : floorf (phantoms[PHANTOM_LEFT].x);
1061     }
1062 #endif
1063 
1064     public:
get_extentsOT::glyf::accelerator_t1065     bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
1066     {
1067       if (unlikely (gid >= num_glyphs)) return false;
1068 
1069 #ifndef HB_NO_VAR
1070       if (font->num_coords && font->num_coords == gvar->get_axis_count ())
1071 	return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
1072 #endif
1073       return glyph_for_gid (gid).get_extents (font, *this, extents);
1074     }
1075 
1076     const Glyph
glyph_for_gidOT::glyf::accelerator_t1077     glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
1078     {
1079       if (unlikely (gid >= num_glyphs)) return Glyph ();
1080 
1081       unsigned int start_offset, end_offset;
1082 
1083       if (short_offset)
1084       {
1085 	const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
1086 	start_offset = 2 * offsets[gid];
1087 	end_offset   = 2 * offsets[gid + 1];
1088       }
1089       else
1090       {
1091 	const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
1092 	start_offset = offsets[gid];
1093 	end_offset   = offsets[gid + 1];
1094       }
1095 
1096       if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
1097 	return Glyph ();
1098 
1099       Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
1100 			       end_offset - start_offset), gid);
1101       return needs_padding_removal ? glyph.trim_padding () : glyph;
1102     }
1103 
1104     unsigned
add_gid_and_childrenOT::glyf::accelerator_t1105     add_gid_and_children (hb_codepoint_t gid,
1106 			  hb_set_t *gids_to_retain,
1107 			  unsigned depth = 0,
1108 			  unsigned operation_count = 0) const
1109     {
1110       if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
1111       if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count;
1112       /* Check if is already visited */
1113       if (gids_to_retain->has (gid)) return operation_count;
1114 
1115       gids_to_retain->add (gid);
1116 
1117       auto it = glyph_for_gid (gid).get_composite_iterator ();
1118       while (it)
1119       {
1120         auto item = *(it++);
1121         operation_count =
1122             add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count);
1123       }
1124 
1125       return operation_count;
1126     }
1127 
1128 #ifdef HB_EXPERIMENTAL_API
1129     struct path_builder_t
1130     {
1131       hb_font_t *font;
1132       draw_helper_t *draw_helper;
1133 
1134       struct optional_point_t
1135       {
optional_point_tOT::glyf::accelerator_t::path_builder_t::optional_point_t1136 	optional_point_t () { has_data = false; }
optional_point_tOT::glyf::accelerator_t::path_builder_t::optional_point_t1137 	optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; }
1138 
1139 	bool has_data;
1140 	float x;
1141 	float y;
1142 
lerpOT::glyf::accelerator_t::path_builder_t::optional_point_t1143 	optional_point_t lerp (optional_point_t p, float t)
1144 	{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
1145       } first_oncurve, first_offcurve, last_offcurve;
1146 
path_builder_tOT::glyf::accelerator_t::path_builder_t1147       path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_)
1148       {
1149 	font = font_;
1150 	draw_helper = &draw_helper_;
1151 	first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
1152       }
1153 
1154       /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
1155 	 See also:
1156 	 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
1157 	 * https://stackoverflow.com/a/20772557 */
consume_pointOT::glyf::accelerator_t::path_builder_t1158       void consume_point (const contour_point_t &point)
1159       {
1160 	/* Skip empty contours */
1161 	if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data))
1162 	  return;
1163 
1164 	bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE;
1165 	optional_point_t p (point.x, point.y);
1166 	if (!first_oncurve.has_data)
1167 	{
1168 	  if (is_on_curve)
1169 	  {
1170 	    first_oncurve = p;
1171 	    draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
1172 	  }
1173 	  else
1174 	  {
1175 	    if (first_offcurve.has_data)
1176 	    {
1177 	      optional_point_t mid = first_offcurve.lerp (p, .5f);
1178 	      first_oncurve = mid;
1179 	      last_offcurve = p;
1180 	      draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
1181 	    }
1182 	    else
1183 	      first_offcurve = p;
1184 	  }
1185 	}
1186 	else
1187 	{
1188 	  if (last_offcurve.has_data)
1189 	  {
1190 	    if (is_on_curve)
1191 	    {
1192 	      draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
1193 					 font->em_scalef_x (p.x), font->em_scalef_y (p.y));
1194 	      last_offcurve = optional_point_t ();
1195 	    }
1196 	    else
1197 	    {
1198 	      optional_point_t mid = last_offcurve.lerp (p, .5f);
1199 	      draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
1200 					 font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
1201 	      last_offcurve = p;
1202 	    }
1203 	  }
1204 	  else
1205 	  {
1206 	    if (is_on_curve)
1207 	      draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y));
1208 	    else
1209 	      last_offcurve = p;
1210 	  }
1211 	}
1212 
1213 	if (point.is_end_point)
1214 	{
1215 	  if (first_offcurve.has_data && last_offcurve.has_data)
1216 	  {
1217 	    optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
1218 	    draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
1219 				       font->em_scalef_x (mid.x), font->em_scalef_y (mid.y));
1220 	    last_offcurve = optional_point_t ();
1221 	    /* now check the rest */
1222 	  }
1223 
1224 	  if (first_offcurve.has_data && first_oncurve.has_data)
1225 	    draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y),
1226 				       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
1227 	  else if (last_offcurve.has_data && first_oncurve.has_data)
1228 	    draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y),
1229 				       font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
1230 	  else if (first_oncurve.has_data)
1231 	    draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y));
1232 
1233 	  /* Getting ready for the next contour */
1234 	  first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
1235 	  draw_helper->end_path ();
1236 	}
1237       }
points_endOT::glyf::accelerator_t::path_builder_t1238       void points_end () {}
1239 
is_consuming_contour_pointsOT::glyf::accelerator_t::path_builder_t1240       bool is_consuming_contour_points () { return true; }
get_phantoms_sinkOT::glyf::accelerator_t::path_builder_t1241       contour_point_t *get_phantoms_sink () { return nullptr; }
1242     };
1243 
1244     bool
get_pathOT::glyf::accelerator_t1245     get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const
1246     { return get_points (font, gid, path_builder_t (font, draw_helper)); }
1247 #endif
1248 
1249 #ifndef HB_NO_VAR
1250     const gvar_accelerator_t *gvar;
1251 #endif
1252     const hmtx_accelerator_t *hmtx;
1253     const vmtx_accelerator_t *vmtx;
1254 
1255     private:
1256     bool short_offset;
1257     unsigned int num_glyphs;
1258     hb_blob_ptr_t<loca> loca_table;
1259     hb_blob_ptr_t<glyf> glyf_table;
1260     hb_face_t *face;
1261   };
1262 
1263   struct SubsetGlyph
1264   {
1265     hb_codepoint_t new_gid;
1266     hb_codepoint_t old_gid;
1267     Glyph source_glyph;
1268     hb_bytes_t dest_start;  /* region of source_glyph to copy first */
1269     hb_bytes_t dest_end;    /* region of source_glyph to copy second */
1270 
serializeOT::glyf::SubsetGlyph1271     bool serialize (hb_serialize_context_t *c,
1272 		    const hb_subset_plan_t *plan) const
1273     {
1274       TRACE_SERIALIZE (this);
1275 
1276       hb_bytes_t dest_glyph = dest_start.copy (c);
1277       dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
1278       unsigned int pad_length = padding ();
1279       DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
1280 
1281       HBUINT8 pad;
1282       pad = 0;
1283       while (pad_length > 0)
1284       {
1285 	c->embed (pad);
1286 	pad_length--;
1287       }
1288 
1289       if (unlikely (!dest_glyph.length)) return_trace (true);
1290 
1291       /* update components gids */
1292       for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
1293       {
1294 	hb_codepoint_t new_gid;
1295 	if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid))
1296 	  const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
1297       }
1298 
1299       if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
1300         Glyph (dest_glyph).drop_hints ();
1301 
1302       if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
1303         Glyph (dest_glyph).set_overlaps_flag ();
1304 
1305       return_trace (true);
1306     }
1307 
drop_hints_bytesOT::glyf::SubsetGlyph1308     void drop_hints_bytes ()
1309     { source_glyph.drop_hints_bytes (dest_start, dest_end); }
1310 
lengthOT::glyf::SubsetGlyph1311     unsigned int      length () const { return dest_start.length + dest_end.length; }
1312     /* pad to 2 to ensure 2-byte loca will be ok */
paddingOT::glyf::SubsetGlyph1313     unsigned int     padding () const { return length () % 2; }
padded_sizeOT::glyf::SubsetGlyph1314     unsigned int padded_size () const { return length () + padding (); }
1315   };
1316 
1317   protected:
1318   UnsizedArrayOf<HBUINT8>
1319 		dataZ;	/* Glyphs data. */
1320   public:
1321   DEFINE_SIZE_MIN (0);	/* In reality, this is UNBOUNDED() type; but since we always
1322 			 * check the size externally, allow Null() object of it by
1323 			 * defining it _MIN instead. */
1324 };
1325 
1326 struct glyf_accelerator_t : glyf::accelerator_t {};
1327 
1328 } /* namespace OT */
1329 
1330 
1331 #endif /* HB_OT_GLYF_TABLE_HH */
1332