Coverage Report

Created: 2026-06-09 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/glyf/glyf.hh
Line
Count
Source
1
#ifndef OT_GLYF_GLYF_HH
2
#define OT_GLYF_GLYF_HH
3
4
5
#include "../../hb-open-type.hh"
6
#include "../../hb-ot-head-table.hh"
7
#include "../../hb-ot-hmtx-table.hh"
8
#include "../../hb-ot-var-gvar-table.hh"
9
#include "../../hb-draw.hh"
10
#include "../../hb-paint.hh"
11
12
#include "glyf-helpers.hh"
13
#include "Glyph.hh"
14
#include "SubsetGlyph.hh"
15
#include "loca.hh"
16
#include "path-builder.hh"
17
18
19
namespace OT {
20
21
22
/*
23
 * glyf -- TrueType Glyph Data
24
 * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
25
 */
26
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
27
28
struct glyf
29
{
30
  friend struct glyf_accelerator_t;
31
32
  static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
33
34
  static bool has_valid_glyf_format(const hb_face_t* face)
35
906
  {
36
906
    const OT::head &head = *face->table.head;
37
906
    return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1;
38
906
  }
39
40
  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
41
726
  {
42
726
    TRACE_SANITIZE (this);
43
    /* Runtime checks as eager sanitizing each glyph is costy */
44
726
    return_trace (true);
45
726
  }
46
47
  /* requires source of SubsetGlyph complains the identifier isn't declared */
48
  template <typename Iterator>
49
  bool serialize (hb_serialize_context_t *c,
50
      Iterator it,
51
                  bool use_short_loca,
52
      const hb_subset_plan_t *plan)
53
0
  {
54
0
    TRACE_SERIALIZE (this);
55
0
56
0
    unsigned init_len = c->length ();
57
0
    for (auto &_ : it)
58
0
      if (unlikely (!_.serialize (c, use_short_loca, plan)))
59
0
        return false;
60
0
61
0
    /* As a special case when all glyph in the font are empty, add a zero byte
62
0
     * to the table, so that OTS doesn’t reject it, and to make the table work
63
0
     * on Windows as well.
64
0
     * See https://github.com/khaledhosny/ots/issues/52 */
65
0
    if (init_len == c->length ())
66
0
    {
67
0
      HBUINT8 empty_byte;
68
0
      empty_byte = 0;
69
0
      c->copy (empty_byte);
70
0
    }
71
0
    return_trace (true);
72
0
  }
73
74
  /* Byte region(s) per glyph to output
75
     unpadded, hints removed if so requested
76
     If we fail to process a glyph we produce an empty (0-length) glyph */
77
  bool subset (hb_subset_context_t *c) const
78
0
  {
79
0
    TRACE_SUBSET (this);
80
0
81
0
    if (!has_valid_glyf_format (c->plan->source)) {
82
0
      // glyf format is unknown don't attempt to subset it.
83
0
      DEBUG_MSG (SUBSET, nullptr,
84
0
                 "unkown glyf format, dropping from subset.");
85
0
      return_trace (false);
86
0
    }
87
0
88
0
    hb_font_t *font = nullptr;
89
0
    if (c->plan->normalized_coords)
90
0
    {
91
0
      font = _create_font_for_instancing (c->plan);
92
0
      if (unlikely (!font))
93
0
  return_trace (false);
94
0
    }
95
0
96
0
    hb_vector_t<unsigned> padded_offsets;
97
0
    if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length)))
98
0
      return_trace (false);
99
0
100
0
    hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
101
0
    if (!_populate_subset_glyphs (c->plan, font, glyphs))
102
0
    {
103
0
      hb_font_destroy (font);
104
0
      return_trace (false);
105
0
    }
106
0
107
0
    if (font)
108
0
      hb_font_destroy (font);
109
0
110
0
    unsigned max_offset = 0;
111
0
    for (auto &g : glyphs)
112
0
    {
113
0
      unsigned size = g.padded_size ();
114
0
      padded_offsets.push (size);
115
0
      max_offset += size;
116
0
    }
117
0
118
0
    bool use_short_loca = false;
119
0
    if (likely (!c->plan->force_long_loca))
120
0
      use_short_loca = max_offset < 0x1FFFF;
121
0
122
0
    if (!use_short_loca)
123
0
    {
124
0
      padded_offsets.clear ();
125
0
      for (auto &g : glyphs)
126
0
  padded_offsets.push (g.length ());
127
0
    }
128
0
129
0
    auto *glyf_prime = c->serializer->start_embed <glyf> ();
130
0
    bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
131
0
    if (c->plan->normalized_coords && !c->plan->pinned_at_default)
132
0
      _free_compiled_subset_glyphs (glyphs);
133
0
134
0
    if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c,
135
0
             padded_offsets.iter (),
136
0
             use_short_loca))))
137
0
      return_trace (false);
138
0
139
0
    return result;
140
0
  }
141
142
  bool
143
  _populate_subset_glyphs (const hb_subset_plan_t   *plan,
144
         hb_font_t                *font,
145
         hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const;
146
147
  hb_font_t *
148
  _create_font_for_instancing (const hb_subset_plan_t *plan) const;
149
150
  void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
151
0
  {
152
0
    for (auto &g : glyphs)
153
0
      g.free_compiled_bytes ();
154
0
  }
155
156
  protected:
157
  UnsizedArrayOf<HBUINT8>
158
    dataZ;  /* Glyphs data. */
159
  public:
160
  DEFINE_SIZE_MIN (0);  /* In reality, this is UNBOUNDED() type; but since we always
161
       * check the size externally, allow Null() object of it by
162
       * defining it _MIN instead. */
163
};
164
165
struct glyf_accelerator_t
166
{
167
  glyf_accelerator_t (hb_face_t *face)
168
906
  {
169
906
    short_offset = false;
170
906
    num_glyphs = 0;
171
906
    loca_table = nullptr;
172
906
    glyf_table = nullptr;
173
906
#ifndef HB_NO_VAR
174
906
    gvar = nullptr;
175
906
#ifndef HB_NO_BEYOND_64K
176
906
    GVAR = nullptr;
177
906
#endif
178
906
#endif
179
906
    hmtx = nullptr;
180
906
#ifndef HB_NO_VERTICAL
181
906
    vmtx = nullptr;
182
906
#endif
183
906
    const OT::head &head = *face->table.head;
184
906
    if (!glyf::has_valid_glyf_format (face))
185
      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
186
63
      return;
187
843
    short_offset = 0 == head.indexToLocFormat;
188
189
843
    loca_table = face->table.loca.get_blob (); // Needs no destruct!
190
843
    glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
191
843
#ifndef HB_NO_VAR
192
843
    gvar = face->table.gvar;
193
843
#ifndef HB_NO_BEYOND_64K
194
843
    GVAR = face->table.GVAR;
195
843
#endif
196
843
#endif
197
843
    hmtx = face->table.hmtx;
198
843
#ifndef HB_NO_VERTICAL
199
843
    vmtx = face->table.vmtx;
200
843
#endif
201
202
843
    num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
203
843
    num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ());
204
843
  }
205
  ~glyf_accelerator_t ()
206
906
  {
207
906
    auto *scratch = cached_scratch.get_relaxed ();
208
906
    if (scratch)
209
763
    {
210
763
      scratch->~hb_glyf_scratch_t ();
211
763
      hb_free (scratch);
212
763
    }
213
214
906
    glyf_table.destroy ();
215
906
  }
216
217
906k
  bool has_data () const { return num_glyphs; }
218
219
  protected:
220
  template<typename T>
221
  bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
222
       hb_array_t<const int> coords,
223
       hb_glyf_scratch_t &scratch,
224
       hb_scalar_cache_t *gvar_cache = nullptr) const
225
450k
  {
226
450k
    if (gid >= num_glyphs) return false;
227
228
337k
    auto &all_points = scratch.all_points;
229
337k
    all_points.clear ();
230
231
337k
    bool phantom_only = !consumer.is_consuming_contour_points ();
232
337k
    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache)))
233
58.2k
      return false;
234
235
279k
    unsigned count = all_points.length;
236
279k
    assert (count >= glyf_impl::PHANTOM_COUNT);
237
279k
    count -= glyf_impl::PHANTOM_COUNT;
238
239
279k
    if (consumer.is_consuming_contour_points ())
240
279k
    {
241
279k
      auto *points = all_points.arrayZ;
242
243
279k
      if (false)
244
0
      {
245
  /* Our path-builder was designed to work with this simple loop.
246
   * But FreeType and CoreText do it differently, so we match those
247
   * with the other, more complicated, code branch below. */
248
0
  for (unsigned i = 0; i < count; i++)
249
0
  {
250
0
    consumer.consume_point (points[i]);
251
0
    if (points[i].is_end_point)
252
0
      consumer.contour_end ();
253
0
  }
254
0
      }
255
279k
      else
256
279k
      {
257
828k
  for (unsigned i = 0; i < count; i++)
258
548k
  {
259
    // Start of a contour.
260
548k
    if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE)
261
249k
    {
262
      // First point is on-curve. Draw the contour.
263
12.4M
      for (; i < count; i++)
264
12.4M
      {
265
12.4M
        consumer.consume_point (points[i]);
266
12.4M
        if (points[i].is_end_point)
267
249k
        {
268
249k
    consumer.contour_end ();
269
249k
    break;
270
249k
        }
271
12.4M
      }
272
249k
    }
273
299k
    else
274
299k
    {
275
299k
      unsigned start = i;
276
277
      // Find end of the contour.
278
11.8M
      for (; i < count; i++)
279
11.8M
        if (points[i].is_end_point)
280
299k
    break;
281
282
299k
      unsigned end = i;
283
284
      // Enough to start from the end. Our path-builder takes care of the rest.
285
299k
      if (likely (end < count)) // Can only fail in case of alloc failure *maybe*.
286
299k
        consumer.consume_point (points[end]);
287
288
11.8M
      for (i = start; i < end; i++)
289
11.5M
        consumer.consume_point (points[i]);
290
291
299k
      consumer.contour_end ();
292
299k
    }
293
548k
  }
294
279k
      }
295
296
279k
      consumer.points_end ();
297
279k
    }
298
299
    /* Where to write phantoms, nullptr if not requested */
300
279k
    contour_point_t *phantoms = consumer.get_phantoms_sink ();
301
279k
    if (phantoms)
302
0
      for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
303
0
  phantoms[i] = all_points.arrayZ[count + i];
304
305
279k
    return true;
306
279k
  }
bool OT::glyf_accelerator_t::get_points<OT::glyf_accelerator_t::points_aggregator_t>(hb_font_t*, unsigned int, OT::glyf_accelerator_t::points_aggregator_t, hb_array_t<int const>, hb_glyf_scratch_t&, OT::hb_scalar_cache_t*) const
Line
Count
Source
225
832
  {
226
832
    if (gid >= num_glyphs) return false;
227
228
832
    auto &all_points = scratch.all_points;
229
832
    all_points.clear ();
230
231
832
    bool phantom_only = !consumer.is_consuming_contour_points ();
232
832
    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache)))
233
272
      return false;
234
235
560
    unsigned count = all_points.length;
236
560
    assert (count >= glyf_impl::PHANTOM_COUNT);
237
560
    count -= glyf_impl::PHANTOM_COUNT;
238
239
560
    if (consumer.is_consuming_contour_points ())
240
560
    {
241
560
      auto *points = all_points.arrayZ;
242
243
560
      if (false)
244
0
      {
245
  /* Our path-builder was designed to work with this simple loop.
246
   * But FreeType and CoreText do it differently, so we match those
247
   * with the other, more complicated, code branch below. */
248
0
  for (unsigned i = 0; i < count; i++)
249
0
  {
250
0
    consumer.consume_point (points[i]);
251
0
    if (points[i].is_end_point)
252
0
      consumer.contour_end ();
253
0
  }
254
0
      }
255
560
      else
256
560
      {
257
1.00k
  for (unsigned i = 0; i < count; i++)
258
443
  {
259
    // Start of a contour.
260
443
    if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE)
261
237
    {
262
      // First point is on-curve. Draw the contour.
263
8.25k
      for (; i < count; i++)
264
8.25k
      {
265
8.25k
        consumer.consume_point (points[i]);
266
8.25k
        if (points[i].is_end_point)
267
237
        {
268
237
    consumer.contour_end ();
269
237
    break;
270
237
        }
271
8.25k
      }
272
237
    }
273
206
    else
274
206
    {
275
206
      unsigned start = i;
276
277
      // Find end of the contour.
278
45.5k
      for (; i < count; i++)
279
45.5k
        if (points[i].is_end_point)
280
206
    break;
281
282
206
      unsigned end = i;
283
284
      // Enough to start from the end. Our path-builder takes care of the rest.
285
206
      if (likely (end < count)) // Can only fail in case of alloc failure *maybe*.
286
206
        consumer.consume_point (points[end]);
287
288
45.5k
      for (i = start; i < end; i++)
289
45.3k
        consumer.consume_point (points[i]);
290
291
206
      consumer.contour_end ();
292
206
    }
293
443
  }
294
560
      }
295
296
560
      consumer.points_end ();
297
560
    }
298
299
    /* Where to write phantoms, nullptr if not requested */
300
560
    contour_point_t *phantoms = consumer.get_phantoms_sink ();
301
560
    if (phantoms)
302
0
      for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
303
0
  phantoms[i] = all_points.arrayZ[count + i];
304
305
560
    return true;
306
560
  }
bool OT::glyf_accelerator_t::get_points<OT::glyf_impl::path_builder_t>(hb_font_t*, unsigned int, OT::glyf_impl::path_builder_t, hb_array_t<int const>, hb_glyf_scratch_t&, OT::hb_scalar_cache_t*) const
Line
Count
Source
225
450k
  {
226
450k
    if (gid >= num_glyphs) return false;
227
228
336k
    auto &all_points = scratch.all_points;
229
336k
    all_points.clear ();
230
231
336k
    bool phantom_only = !consumer.is_consuming_contour_points ();
232
336k
    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache)))
233
57.9k
      return false;
234
235
278k
    unsigned count = all_points.length;
236
278k
    assert (count >= glyf_impl::PHANTOM_COUNT);
237
278k
    count -= glyf_impl::PHANTOM_COUNT;
238
239
278k
    if (consumer.is_consuming_contour_points ())
240
278k
    {
241
278k
      auto *points = all_points.arrayZ;
242
243
278k
      if (false)
244
0
      {
245
  /* Our path-builder was designed to work with this simple loop.
246
   * But FreeType and CoreText do it differently, so we match those
247
   * with the other, more complicated, code branch below. */
248
0
  for (unsigned i = 0; i < count; i++)
249
0
  {
250
0
    consumer.consume_point (points[i]);
251
0
    if (points[i].is_end_point)
252
0
      consumer.contour_end ();
253
0
  }
254
0
      }
255
278k
      else
256
278k
      {
257
827k
  for (unsigned i = 0; i < count; i++)
258
548k
  {
259
    // Start of a contour.
260
548k
    if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE)
261
249k
    {
262
      // First point is on-curve. Draw the contour.
263
12.4M
      for (; i < count; i++)
264
12.4M
      {
265
12.4M
        consumer.consume_point (points[i]);
266
12.4M
        if (points[i].is_end_point)
267
249k
        {
268
249k
    consumer.contour_end ();
269
249k
    break;
270
249k
        }
271
12.4M
      }
272
249k
    }
273
299k
    else
274
299k
    {
275
299k
      unsigned start = i;
276
277
      // Find end of the contour.
278
11.7M
      for (; i < count; i++)
279
11.7M
        if (points[i].is_end_point)
280
299k
    break;
281
282
299k
      unsigned end = i;
283
284
      // Enough to start from the end. Our path-builder takes care of the rest.
285
299k
      if (likely (end < count)) // Can only fail in case of alloc failure *maybe*.
286
299k
        consumer.consume_point (points[end]);
287
288
11.7M
      for (i = start; i < end; i++)
289
11.4M
        consumer.consume_point (points[i]);
290
291
299k
      consumer.contour_end ();
292
299k
    }
293
548k
  }
294
278k
      }
295
296
278k
      consumer.points_end ();
297
278k
    }
298
299
    /* Where to write phantoms, nullptr if not requested */
300
278k
    contour_point_t *phantoms = consumer.get_phantoms_sink ();
301
278k
    if (phantoms)
302
0
      for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
303
0
  phantoms[i] = all_points.arrayZ[count + i];
304
305
278k
    return true;
306
278k
  }
307
308
  public:
309
310
#ifndef HB_NO_VAR
311
  struct points_aggregator_t
312
  {
313
    hb_font_t *font;
314
    hb_glyph_extents_t *extents;
315
    contour_point_t *phantoms;
316
    bool scaled;
317
318
    struct contour_bounds_t
319
    {
320
1.66k
      contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; }
321
322
      void add (const contour_point_t &p)
323
53.8k
      {
324
53.8k
  min_x = hb_min (min_x, p.x);
325
53.8k
  min_y = hb_min (min_y, p.y);
326
53.8k
  max_x = hb_max (max_x, p.x);
327
53.8k
  max_y = hb_max (max_y, p.y);
328
53.8k
      }
329
330
560
      bool empty () const { return (min_x >= max_x) || (min_y >= max_y); }
331
332
      void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled)
333
560
      {
334
560
  if (unlikely (empty ()))
335
438
  {
336
438
    extents->width = 0;
337
438
    extents->x_bearing = 0;
338
438
    extents->height = 0;
339
438
    extents->y_bearing = 0;
340
438
    return;
341
438
  }
342
122
  {
343
122
    extents->x_bearing = roundf (min_x);
344
122
    extents->width = roundf (max_x - extents->x_bearing);
345
122
    extents->y_bearing = roundf (max_y);
346
122
    extents->height = roundf (min_y - extents->y_bearing);
347
348
122
    if (scaled)
349
122
      font->scale_glyph_extents (extents);
350
122
  }
351
122
      }
352
353
      protected:
354
      float min_x, min_y, max_x, max_y;
355
    } bounds;
356
357
    points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_)
358
832
    {
359
832
      font = font_;
360
832
      extents = extents_;
361
832
      phantoms = phantoms_;
362
832
      scaled = scaled_;
363
832
      if (extents) bounds = contour_bounds_t ();
364
832
    }
365
366
    HB_ALWAYS_INLINE
367
53.8k
    void consume_point (const contour_point_t &point) { bounds.add (point); }
368
443
    void contour_end () {}
369
560
    void points_end () { bounds.get_extents (font, extents, scaled); }
370
371
1.39k
    bool is_consuming_contour_points () { return extents; }
372
560
    contour_point_t *get_phantoms_sink () { return phantoms; }
373
  };
374
375
#ifndef HB_NO_VAR
376
  unsigned
377
  get_advance_with_var_unscaled (hb_codepoint_t gid,
378
         hb_font_t *font,
379
         bool is_vertical,
380
          hb_glyf_scratch_t &scratch,
381
         hb_scalar_cache_t *gvar_cache = nullptr) const
382
0
  {
383
0
    if (unlikely (gid >= num_glyphs)) return 0;
384
385
0
    bool success = false;
386
387
0
    contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
388
0
    success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
389
0
        hb_array (font->coords,
390
0
            font->has_nonzero_coords ? font->num_coords : 0),
391
0
        scratch, gvar_cache);
392
0
    if (unlikely (!success))
393
0
    {
394
0
      unsigned upem = font->face->get_upem ();
395
0
      return is_vertical ? upem : upem / 2;
396
0
    }
397
398
0
    float result = is_vertical
399
0
     ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y
400
0
     : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x;
401
0
    return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2);
402
0
  }
403
404
  float
405
  get_v_origin_with_var_unscaled (hb_codepoint_t gid,
406
          hb_font_t *font,
407
          hb_glyf_scratch_t &scratch,
408
          hb_scalar_cache_t *gvar_cache = nullptr) const
409
0
  {
410
0
    if (unlikely (gid >= num_glyphs)) return 0;
411
412
0
    bool success = false;
413
414
0
    contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
415
0
    success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
416
0
        hb_array (font->coords,
417
0
            font->has_nonzero_coords ? font->num_coords : 0),
418
0
        scratch, gvar_cache);
419
0
    if (unlikely (!success))
420
0
    {
421
0
      return font->face->get_upem ();
422
0
    }
423
424
0
    return phantoms[glyf_impl::PHANTOM_TOP].y;
425
0
  }
426
#endif
427
#endif
428
429
  public:
430
431
  bool get_extents (hb_font_t *font,
432
        hb_codepoint_t gid,
433
        hb_glyph_extents_t *extents) const
434
4.11k
  { return get_extents_at (font, gid, extents, hb_array (font->coords,
435
4.11k
               font->has_nonzero_coords ? font->num_coords : 0)); }
436
437
  bool get_extents_at (hb_font_t *font,
438
           hb_codepoint_t gid,
439
           hb_glyph_extents_t *extents,
440
           hb_array_t<const int> coords) const
441
4.11k
  {
442
4.11k
    if (unlikely (gid >= num_glyphs)) return false;
443
444
1.97k
#ifndef HB_NO_VAR
445
1.97k
    if (coords)
446
832
    {
447
832
      hb_glyf_scratch_t *scratch = acquire_scratch ();
448
832
      if (unlikely (!scratch)) return false;
449
832
      bool ret = get_points (font,
450
832
           gid,
451
832
           points_aggregator_t (font, extents, nullptr, true),
452
832
           coords,
453
832
           *scratch);
454
832
      release_scratch (scratch);
455
832
      return ret;
456
832
    }
457
1.14k
#endif
458
1.14k
    return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
459
1.97k
  }
460
461
  const glyf_impl::Glyph
462
  glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
463
2.13M
  {
464
2.13M
    if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph ();
465
466
425k
    unsigned int start_offset, end_offset;
467
468
425k
    if (short_offset)
469
425k
    {
470
425k
      const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
471
425k
      start_offset = 2 * offsets[gid];
472
425k
      end_offset   = 2 * offsets[gid + 1];
473
425k
    }
474
378
    else
475
378
    {
476
378
      const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
477
378
      start_offset = offsets[gid];
478
378
      end_offset   = offsets[gid + 1];
479
378
    }
480
481
425k
    if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ()))
482
149k
      return glyf_impl::Glyph ();
483
484
275k
    glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
485
275k
           end_offset - start_offset), gid);
486
275k
    return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph;
487
425k
  }
488
489
  bool
490
  get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const
491
455k
  {
492
455k
    if (!has_data ()) return false;
493
494
450k
    hb_glyf_scratch_t *scratch = acquire_scratch ();
495
450k
    if (unlikely (!scratch)) return true;
496
497
450k
    bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
498
450k
         hb_array (font->coords,
499
450k
             font->has_nonzero_coords ? font->num_coords : 0),
500
450k
         *scratch,
501
450k
          gvar_cache);
502
503
450k
    release_scratch (scratch);
504
505
450k
    return ret;
506
450k
  }
507
508
  bool
509
  get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
510
         hb_array_t<const int> coords,
511
         hb_glyf_scratch_t &scratch,
512
         hb_scalar_cache_t *gvar_cache = nullptr) const
513
0
  {
514
0
    if (!has_data ()) return false;
515
0
    return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
516
0
           coords,
517
0
           scratch,
518
0
           gvar_cache);
519
0
  }
520
521
522
  hb_glyf_scratch_t *acquire_scratch () const
523
450k
  {
524
450k
    if (!has_data ()) return nullptr;
525
450k
    hb_glyf_scratch_t *scratch = cached_scratch.get_acquire ();
526
450k
    if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
527
771
    {
528
771
      scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
529
771
      if (unlikely (!scratch))
530
8
  return nullptr;
531
771
    }
532
450k
    return scratch;
533
450k
  }
534
  void release_scratch (hb_glyf_scratch_t *scratch) const
535
450k
  {
536
450k
    if (!scratch)
537
0
      return;
538
450k
    if (!cached_scratch.cmpexch (nullptr, scratch))
539
0
    {
540
0
      scratch->~hb_glyf_scratch_t ();
541
0
      hb_free (scratch);
542
0
    }
543
450k
  }
544
545
#ifndef HB_NO_VAR
546
  const gvar_accelerator_t *gvar;
547
#ifndef HB_NO_BEYOND_64K
548
  const GVAR_accelerator_t *GVAR;
549
#endif
550
#endif
551
  const hmtx_accelerator_t *hmtx;
552
#ifndef HB_NO_VERTICAL
553
  const vmtx_accelerator_t *vmtx;
554
#endif
555
556
  private:
557
  bool short_offset;
558
  unsigned int num_glyphs;
559
  hb_blob_ptr_t<loca> loca_table;
560
  hb_blob_ptr_t<glyf> glyf_table;
561
  mutable hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
562
};
563
564
565
inline bool
566
glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
567
             hb_font_t *font,
568
             hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
569
0
{
570
0
  OT::glyf_accelerator_t glyf (plan->source);
571
0
  if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false;
572
0
573
0
  for (const auto &pair : plan->new_to_old_gid_list)
574
0
  {
575
0
    hb_codepoint_t new_gid = pair.first;
576
0
    hb_codepoint_t old_gid = pair.second;
577
0
    glyf_impl::SubsetGlyph *p = glyphs.push ();
578
0
    glyf_impl::SubsetGlyph& subset_glyph = *p;
579
0
    subset_glyph.old_gid = old_gid;
580
0
581
0
    if (unlikely (old_gid == 0 && new_gid == 0 &&
582
0
                  !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
583
0
                  !plan->normalized_coords)
584
0
      subset_glyph.source_glyph = glyf_impl::Glyph ();
585
0
    else
586
0
    {
587
0
      /* If plan has an accelerator, the preprocessing step already trimmed glyphs.
588
0
       * Don't trim them again! */
589
0
      subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator);
590
0
    }
591
0
592
0
    if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
593
0
      subset_glyph.drop_hints_bytes ();
594
0
    else
595
0
      subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
596
0
597
0
    if (font)
598
0
    {
599
0
      if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
600
0
      {
601
0
        // when pinned at default, only bounds are updated, thus no need to free
602
0
        if (!plan->pinned_at_default)
603
0
          _free_compiled_subset_glyphs (glyphs);
604
0
        return false;
605
0
      }
606
0
    }
607
0
  }
608
0
  return true;
609
0
}
610
611
inline hb_font_t *
612
glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
613
0
{
614
0
  hb_font_t *font = hb_font_create (plan->source);
615
0
  if (unlikely (font == hb_font_get_empty ())) return nullptr;
616
0
617
0
  hb_vector_t<hb_variation_t> vars;
618
0
  if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
619
0
  {
620
0
    hb_font_destroy (font);
621
0
    return nullptr;
622
0
  }
623
0
624
0
  for (auto _ : plan->user_axes_location)
625
0
  {
626
0
    hb_variation_t var;
627
0
    var.tag = _.first;
628
0
    var.value = _.second.middle;
629
0
    vars.push (var);
630
0
  }
631
0
632
0
#ifndef HB_NO_VAR
633
0
  hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
634
0
#endif
635
0
  return font;
636
0
}
637
638
639
} /* namespace OT */
640
641
642
#endif /* OT_GLYF_GLYF_HH */