Coverage Report

Created: 2026-10-17 07:10

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