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