Coverage Report

Created: 2025-10-28 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-ot-font.cc
Line
Count
Source
1
/*
2
 * Copyright © 2011,2014  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
25
 */
26
27
#include "hb.hh"
28
29
#ifndef HB_NO_OT_FONT
30
31
#include "hb-ot.h"
32
33
#include "hb-cache.hh"
34
#include "hb-font.hh"
35
#include "hb-machinery.hh"
36
#include "hb-ot-face.hh"
37
38
#include "hb-ot-cmap-table.hh"
39
#include "hb-ot-glyf-table.hh"
40
#include "hb-ot-var-gvar-table.hh"
41
#include "hb-ot-cff2-table.hh"
42
#include "hb-ot-cff1-table.hh"
43
#include "hb-ot-hmtx-table.hh"
44
#include "hb-ot-post-table.hh"
45
#include "hb-ot-stat-table.hh"
46
#include "hb-ot-var-varc-table.hh"
47
#include "hb-ot-vorg-table.hh"
48
#include "OT/Color/CBDT/CBDT.hh"
49
#include "OT/Color/COLR/COLR.hh"
50
#include "OT/Color/sbix/sbix.hh"
51
#include "OT/Color/svg/svg.hh"
52
53
54
/**
55
 * SECTION:hb-ot-font
56
 * @title: hb-ot-font
57
 * @short_description: OpenType font implementation
58
 * @include: hb-ot.h
59
 *
60
 * Functions for using OpenType fonts with hb_shape().  Note that fonts returned
61
 * by hb_font_create() default to using these functions, so most clients would
62
 * never need to call these functions directly.
63
 **/
64
65
using hb_ot_font_advance_cache_t = hb_cache_t<24, 16>;
66
static_assert (sizeof (hb_ot_font_advance_cache_t) == 1024, "");
67
68
using hb_ot_font_origin_cache_t = hb_cache_t<20, 20>;
69
static_assert (sizeof (hb_ot_font_origin_cache_t) == 1024, "");
70
71
struct hb_ot_font_t
72
{
73
  const hb_ot_face_t *ot_face;
74
75
  mutable hb_atomic_t<int> cached_serial;
76
  mutable hb_atomic_t<int> cached_coords_serial;
77
78
  struct direction_cache_t
79
  {
80
    mutable hb_atomic_t<hb_ot_font_advance_cache_t *> advance_cache;
81
    mutable hb_atomic_t<OT::hb_scalar_cache_t *> varStore_cache;
82
83
    ~direction_cache_t ()
84
20.3k
    {
85
20.3k
      clear ();
86
20.3k
    }
87
88
    hb_ot_font_advance_cache_t *acquire_advance_cache () const
89
0
    {
90
0
    retry:
91
0
      auto *cache = advance_cache.get_acquire ();
92
0
      if (!cache)
93
0
      {
94
0
        cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t));
95
0
  if (!cache)
96
0
    return nullptr;
97
0
  new (cache) hb_ot_font_advance_cache_t;
98
0
  return cache;
99
0
      }
100
0
      if (advance_cache.cmpexch (cache, nullptr))
101
0
        return cache;
102
0
      else
103
0
        goto retry;
104
0
    }
105
    void release_advance_cache (hb_ot_font_advance_cache_t *cache) const
106
0
    {
107
0
      if (!cache)
108
0
        return;
109
0
      if (!advance_cache.cmpexch (nullptr, cache))
110
0
        hb_free (cache);
111
0
    }
112
    void clear_advance_cache () const
113
20.3k
    {
114
20.3k
    retry:
115
20.3k
      auto *cache = advance_cache.get_acquire ();
116
20.3k
      if (!cache)
117
20.3k
  return;
118
0
      if (advance_cache.cmpexch (cache, nullptr))
119
0
  hb_free (cache);
120
0
      else
121
0
        goto retry;
122
0
    }
123
124
    OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
125
0
    {
126
0
    retry:
127
0
      auto *cache = varStore_cache.get_acquire ();
128
0
      if (!cache)
129
0
  return varStore.create_cache ();
130
0
      if (varStore_cache.cmpexch (cache, nullptr))
131
0
  return cache;
132
0
      else
133
0
  goto retry;
134
0
    }
135
    void release_varStore_cache (OT::hb_scalar_cache_t *cache) const
136
0
    {
137
0
      if (!cache)
138
0
  return;
139
0
      if (!varStore_cache.cmpexch (nullptr, cache))
140
0
  OT::ItemVariationStore::destroy_cache (cache);
141
0
    }
142
    void clear_varStore_cache () const
143
20.3k
    {
144
20.3k
    retry:
145
20.3k
      auto *cache = varStore_cache.get_acquire ();
146
20.3k
      if (!cache)
147
20.3k
  return;
148
0
      if (varStore_cache.cmpexch (cache, nullptr))
149
0
  OT::ItemVariationStore::destroy_cache (cache);
150
0
      else
151
0
  goto retry;
152
0
    }
153
154
    void clear () const
155
20.3k
    {
156
20.3k
      clear_advance_cache ();
157
20.3k
      clear_varStore_cache ();
158
20.3k
    }
159
160
  } h, v;
161
162
  struct origin_cache_t
163
  {
164
    mutable hb_atomic_t<hb_ot_font_origin_cache_t *> origin_cache;
165
    mutable hb_atomic_t<OT::hb_scalar_cache_t *> varStore_cache;
166
167
    ~origin_cache_t ()
168
10.1k
    {
169
10.1k
      clear ();
170
10.1k
    }
171
172
    hb_ot_font_origin_cache_t *acquire_origin_cache () const
173
0
    {
174
0
    retry:
175
0
      auto *cache = origin_cache.get_acquire ();
176
0
      if (!cache)
177
0
      {
178
0
        cache = (hb_ot_font_origin_cache_t *) hb_malloc (sizeof (hb_ot_font_origin_cache_t));
179
0
  if (!cache)
180
0
    return nullptr;
181
0
  new (cache) hb_ot_font_origin_cache_t;
182
0
  return cache;
183
0
      }
184
0
      if (origin_cache.cmpexch (cache, nullptr))
185
0
        return cache;
186
0
      else
187
0
        goto retry;
188
0
    }
189
    void release_origin_cache (hb_ot_font_origin_cache_t *cache) const
190
0
    {
191
0
      if (!cache)
192
0
        return;
193
0
      if (!origin_cache.cmpexch (nullptr, cache))
194
0
        hb_free (cache);
195
0
    }
196
    void clear_origin_cache () const
197
10.1k
    {
198
10.1k
    retry:
199
10.1k
      auto *cache = origin_cache.get_acquire ();
200
10.1k
      if (!cache)
201
10.1k
  return;
202
0
      if (origin_cache.cmpexch (cache, nullptr))
203
0
  hb_free (cache);
204
0
      else
205
0
        goto retry;
206
0
    }
207
208
    OT::hb_scalar_cache_t *acquire_varStore_cache (const OT::ItemVariationStore &varStore) const
209
0
    {
210
0
    retry:
211
0
      auto *cache = varStore_cache.get_acquire ();
212
0
      if (!cache)
213
0
  return varStore.create_cache ();
214
0
      if (varStore_cache.cmpexch (cache, nullptr))
215
0
  return cache;
216
0
      else
217
0
  goto retry;
218
0
    }
219
    void release_varStore_cache (OT::hb_scalar_cache_t *cache) const
220
0
    {
221
0
      if (!cache)
222
0
  return;
223
0
      if (!varStore_cache.cmpexch (nullptr, cache))
224
0
  OT::ItemVariationStore::destroy_cache (cache);
225
0
    }
226
    void clear_varStore_cache () const
227
10.1k
    {
228
10.1k
    retry:
229
10.1k
      auto *cache = varStore_cache.get_acquire ();
230
10.1k
      if (!cache)
231
10.1k
  return;
232
0
      if (varStore_cache.cmpexch (cache, nullptr))
233
0
  OT::ItemVariationStore::destroy_cache (cache);
234
0
      else
235
0
  goto retry;
236
0
    }
237
238
    void clear () const
239
10.1k
    {
240
10.1k
      clear_origin_cache ();
241
10.1k
      clear_varStore_cache ();
242
10.1k
    }
243
  } v_origin;
244
245
  struct draw_cache_t
246
  {
247
    mutable hb_atomic_t<OT::hb_scalar_cache_t *> gvar_cache;
248
249
    ~draw_cache_t ()
250
10.1k
    {
251
10.1k
      clear ();
252
10.1k
    }
253
254
    OT::hb_scalar_cache_t *acquire_gvar_cache (const OT::gvar_accelerator_t &gvar) const
255
0
    {
256
0
    retry:
257
0
      auto *cache = gvar_cache.get_acquire ();
258
0
      if (!cache)
259
0
  return gvar.create_cache ();
260
0
      if (gvar_cache.cmpexch (cache, nullptr))
261
0
  return cache;
262
0
      else
263
0
  goto retry;
264
0
    }
265
    void release_gvar_cache (OT::hb_scalar_cache_t *cache) const
266
0
    {
267
0
      if (!cache)
268
0
  return;
269
0
      if (!gvar_cache.cmpexch (nullptr, cache))
270
0
  OT::gvar_accelerator_t::destroy_cache (cache);
271
0
    }
272
    void clear_gvar_cache () const
273
10.1k
    {
274
10.1k
    retry:
275
10.1k
      auto *cache = gvar_cache.get_acquire ();
276
10.1k
      if (!cache)
277
10.1k
  return;
278
0
      if (gvar_cache.cmpexch (cache, nullptr))
279
0
  OT::gvar_accelerator_t::destroy_cache (cache);
280
0
      else
281
0
  goto retry;
282
0
    }
283
284
    void clear () const
285
10.1k
    {
286
10.1k
      clear_gvar_cache ();
287
10.1k
    }
288
  } draw;
289
290
  void check_serial (hb_font_t *font) const
291
0
  {
292
0
    int font_serial = font->serial_coords.get_acquire ();
293
0
    if (cached_serial.get_acquire () != font_serial)
294
0
    {
295
      /* These caches are dependent on scale and synthetic settings.
296
       * Any change to the font invalidates them. */
297
0
      v_origin.clear ();
298
299
0
      cached_serial.set_release (font_serial);
300
0
    }
301
302
0
    int font_serial_coords = font->serial_coords.get_acquire ();
303
0
    if (cached_coords_serial.get_acquire () != font_serial_coords)
304
0
    {
305
      /* These caches are independent of scale or synthetic settings.
306
       * Just variation changes will invalidate them. */
307
0
      h.clear ();
308
0
      v.clear ();
309
0
      draw.clear ();
310
311
0
      cached_coords_serial.set_release (font_serial_coords);
312
0
    }
313
0
  }
314
};
315
316
static hb_ot_font_t *
317
_hb_ot_font_create (hb_font_t *font)
318
10.1k
{
319
10.1k
  hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t));
320
10.1k
  if (unlikely (!ot_font))
321
0
    return nullptr;
322
323
10.1k
  ot_font->ot_face = &font->face->table;
324
325
10.1k
  return ot_font;
326
10.1k
}
327
328
static void
329
_hb_ot_font_destroy (void *font_data)
330
10.1k
{
331
10.1k
  hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data;
332
333
10.1k
  ot_font->~hb_ot_font_t ();
334
335
10.1k
  hb_free (ot_font);
336
10.1k
}
337
338
static hb_bool_t
339
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
340
       void *font_data,
341
       hb_codepoint_t unicode,
342
       hb_codepoint_t *glyph,
343
       void *user_data HB_UNUSED)
344
0
{
345
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
346
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
347
0
  return ot_face->cmap->get_nominal_glyph (unicode, glyph);
348
0
}
349
350
static unsigned int
351
hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
352
        void *font_data,
353
        unsigned int count,
354
        const hb_codepoint_t *first_unicode,
355
        unsigned int unicode_stride,
356
        hb_codepoint_t *first_glyph,
357
        unsigned int glyph_stride,
358
        void *user_data HB_UNUSED)
359
0
{
360
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
361
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
362
0
  return ot_face->cmap->get_nominal_glyphs (count,
363
0
              first_unicode, unicode_stride,
364
0
              first_glyph, glyph_stride);
365
0
}
366
367
static hb_bool_t
368
hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
369
         void *font_data,
370
         hb_codepoint_t unicode,
371
         hb_codepoint_t variation_selector,
372
         hb_codepoint_t *glyph,
373
         void *user_data HB_UNUSED)
374
0
{
375
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
376
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
377
0
  return ot_face->cmap->get_variation_glyph (unicode,
378
0
                                             variation_selector, glyph);
379
0
}
380
381
static void
382
hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
383
          unsigned count,
384
          const hb_codepoint_t *first_glyph,
385
          unsigned glyph_stride,
386
          hb_position_t *first_advance,
387
          unsigned advance_stride,
388
          void *user_data HB_UNUSED)
389
0
{
390
  // Duplicated in v_advances. Ugly. Keep in sync'ish.
391
392
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
393
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
394
0
  const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
395
396
0
  if (unlikely (!hmtx.has_data ()))
397
0
  {
398
0
    hb_position_t advance = font->face->get_upem () / 2;
399
0
    advance = font->em_scale_x (advance);
400
0
    for (unsigned int i = 0; i < count; i++)
401
0
    {
402
0
      *first_advance = advance;
403
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
404
0
    }
405
0
    return;
406
0
  }
407
408
0
#ifndef HB_NO_VAR
409
0
  if (!font->has_nonzero_coords)
410
0
  {
411
0
  fallback:
412
#else
413
  {
414
#endif
415
    // Just plain htmx data. No need to cache.
416
0
    for (unsigned int i = 0; i < count; i++)
417
0
    {
418
0
      *first_advance = font->em_scale_x (hmtx.get_advance_without_var_unscaled (*first_glyph));
419
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
420
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
421
0
    }
422
0
    return;
423
0
  }
424
425
0
#ifndef HB_NO_VAR
426
  /* has_nonzero_coords. */
427
428
0
  ot_font->check_serial (font);
429
0
  hb_ot_font_advance_cache_t *advance_cache = ot_font->h.acquire_advance_cache ();
430
0
  if (!advance_cache)
431
0
  {
432
    // malloc failure. Just use the fallback non-variable path.
433
0
    goto fallback;
434
0
  }
435
436
  /* If HVAR is present, use it.*/
437
0
  const OT::HVAR &HVAR = *hmtx.var_table;
438
0
  if (HVAR.has_data ())
439
0
  {
440
0
    const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
441
0
    OT::hb_scalar_cache_t *varStore_cache = ot_font->h.acquire_varStore_cache (varStore);
442
443
0
    for (unsigned int i = 0; i < count; i++)
444
0
    {
445
0
      hb_position_t v;
446
0
      unsigned cv;
447
0
      if (advance_cache->get (*first_glyph, &cv))
448
0
  v = cv;
449
0
      else
450
0
      {
451
0
        v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
452
0
  advance_cache->set (*first_glyph, v);
453
0
      }
454
0
      *first_advance = font->em_scale_x (v);
455
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
456
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
457
0
    }
458
459
0
    ot_font->h.release_varStore_cache (varStore_cache);
460
0
    ot_font->h.release_advance_cache (advance_cache);
461
0
    return;
462
0
  }
463
464
0
  const auto &gvar = *ot_face->gvar;
465
0
  if (gvar.has_data ())
466
0
  {
467
0
    const auto &glyf = *ot_face->glyf;
468
0
    auto *scratch = glyf.acquire_scratch ();
469
0
    if (unlikely (!scratch))
470
0
    {
471
0
      ot_font->h.release_advance_cache (advance_cache);
472
0
      goto fallback;
473
0
    }
474
0
    OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
475
476
0
    for (unsigned int i = 0; i < count; i++)
477
0
    {
478
0
      hb_position_t v;
479
0
      unsigned cv;
480
0
      if (advance_cache->get (*first_glyph, &cv))
481
0
  v = cv;
482
0
      else
483
0
      {
484
0
        v = glyf.get_advance_with_var_unscaled (*first_glyph, font, false, *scratch, gvar_cache);
485
0
  advance_cache->set (*first_glyph, v);
486
0
      }
487
0
      *first_advance = font->em_scale_x (v);
488
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
489
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
490
0
    }
491
492
0
    ot_font->draw.release_gvar_cache (gvar_cache);
493
0
    glyf.release_scratch (scratch);
494
0
    ot_font->h.release_advance_cache (advance_cache);
495
0
    return;
496
0
  }
497
498
0
  ot_font->h.release_advance_cache (advance_cache);
499
  // No HVAR or GVAR.  Just use the fallback non-variable path.
500
0
  goto fallback;
501
0
#endif
502
0
}
503
504
#ifndef HB_NO_VERTICAL
505
static void
506
hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
507
          unsigned count,
508
          const hb_codepoint_t *first_glyph,
509
          unsigned glyph_stride,
510
          hb_position_t *first_advance,
511
          unsigned advance_stride,
512
          void *user_data HB_UNUSED)
513
0
{
514
  // Duplicated from h_advances. Ugly. Keep in sync'ish.
515
516
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
517
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
518
0
  const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
519
520
0
  if (unlikely (!vmtx.has_data ()))
521
0
  {
522
0
    hb_font_extents_t font_extents;
523
0
    font->get_h_extents_with_fallback (&font_extents);
524
0
    hb_position_t advance = font_extents.descender - font_extents.ascender;
525
0
    for (unsigned int i = 0; i < count; i++)
526
0
    {
527
0
      *first_advance = advance;
528
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
529
0
    }
530
0
    return;
531
0
  }
532
533
0
#ifndef HB_NO_VAR
534
0
  if (!font->has_nonzero_coords)
535
0
  {
536
0
  fallback:
537
#else
538
  {
539
#endif
540
    // Just plain vtmx data. No need to cache.
541
0
    for (unsigned int i = 0; i < count; i++)
542
0
    {
543
0
      *first_advance = font->em_scale_y (- (int) vmtx.get_advance_without_var_unscaled (*first_glyph));
544
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
545
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
546
0
    }
547
0
    return;
548
0
  }
549
550
0
#ifndef HB_NO_VAR
551
  /* has_nonzero_coords. */
552
553
0
  ot_font->check_serial (font);
554
0
  hb_ot_font_advance_cache_t *advance_cache = ot_font->v.acquire_advance_cache ();
555
0
  if (!advance_cache)
556
0
  {
557
    // malloc failure. Just use the fallback non-variable path.
558
0
    goto fallback;
559
0
  }
560
561
  /* If VVAR is present, use it.*/
562
0
  const OT::VVAR &VVAR = *vmtx.var_table;
563
0
  if (VVAR.has_data ())
564
0
  {
565
0
    const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
566
0
    OT::hb_scalar_cache_t *varStore_cache = ot_font->v.acquire_varStore_cache (varStore);
567
568
0
    for (unsigned int i = 0; i < count; i++)
569
0
    {
570
0
      hb_position_t v;
571
0
      unsigned cv;
572
0
      if (advance_cache->get (*first_glyph, &cv))
573
0
  v = cv;
574
0
      else
575
0
      {
576
0
        v = vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache);
577
0
  advance_cache->set (*first_glyph, v);
578
0
      }
579
0
      *first_advance = font->em_scale_y (- (int) v);
580
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
581
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
582
0
    }
583
584
0
    ot_font->v.release_varStore_cache (varStore_cache);
585
0
    ot_font->v.release_advance_cache (advance_cache);
586
0
    return;
587
0
  }
588
589
0
  const auto &gvar = *ot_face->gvar;
590
0
  if (gvar.has_data ())
591
0
  {
592
0
    const auto &glyf = *ot_face->glyf;
593
0
    auto *scratch = glyf.acquire_scratch ();
594
0
    if (unlikely (!scratch))
595
0
    {
596
0
      ot_font->v.release_advance_cache (advance_cache);
597
0
      goto fallback;
598
0
    }
599
0
    OT::hb_scalar_cache_t *gvar_cache = ot_font->draw.acquire_gvar_cache (gvar);
600
601
0
    for (unsigned int i = 0; i < count; i++)
602
0
    {
603
0
      hb_position_t v;
604
0
      unsigned cv;
605
0
      if (advance_cache->get (*first_glyph, &cv))
606
0
  v = cv;
607
0
      else
608
0
      {
609
0
        v = glyf.get_advance_with_var_unscaled (*first_glyph, font, true, *scratch, gvar_cache);
610
0
  advance_cache->set (*first_glyph, v);
611
0
      }
612
0
      *first_advance = font->em_scale_y (- (int) v);
613
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
614
0
      first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
615
0
    }
616
617
0
    ot_font->draw.release_gvar_cache (gvar_cache);
618
0
    glyf.release_scratch (scratch);
619
0
    ot_font->v.release_advance_cache (advance_cache);
620
0
    return;
621
0
  }
622
623
0
  ot_font->v.release_advance_cache (advance_cache);
624
  // No VVAR or GVAR.  Just use the fallback non-variable path.
625
0
  goto fallback;
626
0
#endif
627
0
}
628
#endif
629
630
#ifndef HB_NO_VERTICAL
631
HB_HOT
632
static hb_bool_t
633
hb_ot_get_glyph_v_origins (hb_font_t *font,
634
         void *font_data,
635
         unsigned int count,
636
         const hb_codepoint_t *first_glyph,
637
         unsigned glyph_stride,
638
         hb_position_t *first_x,
639
         unsigned x_stride,
640
         hb_position_t *first_y,
641
         unsigned y_stride,
642
         void *user_data HB_UNUSED)
643
0
{
644
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
645
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
646
647
  /* First, set all the x values to half the advance width. */
648
0
  font->get_glyph_h_advances (count,
649
0
            first_glyph, glyph_stride,
650
0
            first_x, x_stride);
651
0
  for (unsigned i = 0; i < count; i++)
652
0
  {
653
0
    *first_x /= 2;
654
0
    first_x = &StructAtOffsetUnaligned<hb_position_t> (first_x, x_stride);
655
0
  }
656
657
  /* The vertical origin business is messy...
658
   *
659
   * We allocate the cache, then have various code paths that use the cache.
660
   * Each one is responsible to free it before returning.
661
   */
662
0
  hb_ot_font_origin_cache_t *origin_cache = ot_font->v_origin.acquire_origin_cache ();
663
664
  /* If there is VORG, always use it. It uses VVAR for variations if necessary. */
665
0
  const OT::VORG &VORG = *ot_face->VORG;
666
0
  if (origin_cache && VORG.has_data ())
667
0
  {
668
0
#ifndef HB_NO_VAR
669
0
    if (!font->has_nonzero_coords)
670
0
#endif
671
0
    {
672
0
      for (unsigned i = 0; i < count; i++)
673
0
      {
674
0
  hb_position_t origin;
675
0
  unsigned cv;
676
0
  if (origin_cache->get (*first_glyph, &cv))
677
0
    origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
678
0
  else
679
0
  {
680
0
    origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph));
681
0
    origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
682
0
  }
683
684
0
  *first_y = origin;
685
686
0
  first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
687
0
  first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride);
688
0
      }
689
0
    }
690
0
#ifndef HB_NO_VAR
691
0
    else
692
0
    {
693
0
      const OT::VVAR &VVAR = *ot_face->vmtx->var_table;
694
0
      const auto &varStore = &VVAR + VVAR.varStore;
695
0
      auto *varStore_cache = ot_font->v_origin.acquire_varStore_cache (varStore);
696
0
      for (unsigned i = 0; i < count; i++)
697
0
      {
698
0
  hb_position_t origin;
699
0
  unsigned cv;
700
0
  if (origin_cache->get (*first_glyph, &cv))
701
0
    origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
702
0
  else
703
0
  {
704
0
    origin = font->em_scalef_y (VORG.get_y_origin (*first_glyph) +
705
0
              VVAR.get_vorg_delta_unscaled (*first_glyph,
706
0
                    font->coords, font->num_coords,
707
0
                    varStore_cache));
708
0
    origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
709
0
  }
710
711
0
  *first_y = origin;
712
713
0
  first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
714
0
  first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride);
715
0
      }
716
0
      ot_font->v_origin.release_varStore_cache (varStore_cache);
717
0
    }
718
0
#endif
719
0
    ot_font->v_origin.release_origin_cache (origin_cache);
720
0
    return true;
721
0
  }
722
723
  /* If and only if `vmtx` is present and it's a `glyf` font,
724
   * we use the top phantom point, deduced from vmtx,glyf[,gvar]. */
725
0
  const auto &vmtx = *ot_face->vmtx;
726
0
  const auto &glyf = *ot_face->glyf;
727
0
  if (origin_cache && vmtx.has_data() && glyf.has_data ())
728
0
  {
729
0
    auto *scratch = glyf.acquire_scratch ();
730
0
    if (unlikely (!scratch))
731
0
    {
732
0
      ot_font->v_origin.release_origin_cache (origin_cache);
733
0
      return false;
734
0
    }
735
0
    OT::hb_scalar_cache_t *gvar_cache = font->has_nonzero_coords ?
736
0
          ot_font->draw.acquire_gvar_cache (*ot_face->gvar) :
737
0
          nullptr;
738
739
0
    for (unsigned i = 0; i < count; i++)
740
0
    {
741
0
      hb_position_t origin;
742
0
      unsigned cv;
743
0
      if (origin_cache->get (*first_glyph, &cv))
744
0
  origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
745
0
      else
746
0
      {
747
0
  origin = font->em_scalef_y (glyf.get_v_origin_with_var_unscaled (*first_glyph, font, *scratch, gvar_cache));
748
0
  origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
749
0
      }
750
751
0
      *first_y = origin;
752
753
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
754
0
      first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride);
755
0
    }
756
757
0
    if (gvar_cache)
758
0
      ot_font->draw.release_gvar_cache (gvar_cache);
759
0
    glyf.release_scratch (scratch);
760
0
    ot_font->v_origin.release_origin_cache (origin_cache);
761
0
    return true;
762
0
  }
763
764
  /* Otherwise, use glyph extents to center the glyph vertically.
765
   * If getting glyph extents failed, just use the font ascender. */
766
0
  if (origin_cache && font->has_glyph_extents_func ())
767
0
  {
768
0
    hb_font_extents_t font_extents;
769
0
    font->get_h_extents_with_fallback (&font_extents);
770
0
    hb_position_t font_advance = font_extents.ascender - font_extents.descender;
771
772
0
    for (unsigned i = 0; i < count; i++)
773
0
    {
774
0
      hb_position_t origin;
775
0
      unsigned cv;
776
777
0
      if (origin_cache->get (*first_glyph, &cv))
778
0
  origin = font->y_scale < 0 ? -static_cast<hb_position_t>(cv) : static_cast<hb_position_t>(cv);
779
0
      else
780
0
      {
781
0
  hb_glyph_extents_t extents = {0};
782
0
  if (likely (font->get_glyph_extents (*first_glyph, &extents)))
783
0
    origin = extents.y_bearing + ((font_advance - -extents.height) >> 1);
784
0
  else
785
0
    origin = font_extents.ascender;
786
787
0
  origin_cache->set (*first_glyph, font->y_scale < 0 ? -origin : origin);
788
0
      }
789
790
0
      *first_y = origin;
791
792
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
793
0
      first_y = &StructAtOffsetUnaligned<hb_position_t> (first_y, y_stride);
794
0
    }
795
0
  }
796
797
0
  ot_font->v_origin.release_origin_cache (origin_cache);
798
0
  return true;
799
0
}
800
#endif
801
802
static hb_bool_t
803
hb_ot_get_glyph_extents (hb_font_t *font,
804
       void *font_data,
805
       hb_codepoint_t glyph,
806
       hb_glyph_extents_t *extents,
807
       void *user_data HB_UNUSED)
808
0
{
809
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
810
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
811
812
0
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
813
0
  if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
814
0
  if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
815
0
#endif
816
0
#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
817
0
  if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
818
0
#endif
819
0
#ifndef HB_NO_VAR_COMPOSITES
820
0
  if (ot_face->VARC->get_extents (font, glyph, extents)) return true;
821
0
#endif
822
0
  if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
823
0
#ifndef HB_NO_OT_FONT_CFF
824
0
  if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
825
0
  if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
826
0
#endif
827
828
0
  return false;
829
0
}
830
831
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
832
static hb_bool_t
833
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
834
          void *font_data,
835
          hb_codepoint_t glyph,
836
          char *name, unsigned int size,
837
          void *user_data HB_UNUSED)
838
0
{
839
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
840
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
841
842
0
  if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
843
0
#ifndef HB_NO_OT_FONT_CFF
844
0
  if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
845
0
#endif
846
0
  return false;
847
0
}
848
static hb_bool_t
849
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
850
         void *font_data,
851
         const char *name, int len,
852
         hb_codepoint_t *glyph,
853
         void *user_data HB_UNUSED)
854
0
{
855
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
856
0
  const hb_ot_face_t *ot_face = ot_font->ot_face;
857
858
0
  if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
859
0
#ifndef HB_NO_OT_FONT_CFF
860
0
    if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
861
0
#endif
862
0
  return false;
863
0
}
864
#endif
865
866
static hb_bool_t
867
hb_ot_get_font_h_extents (hb_font_t *font,
868
        void *font_data HB_UNUSED,
869
        hb_font_extents_t *metrics,
870
        void *user_data HB_UNUSED)
871
0
{
872
0
  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
873
0
   _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
874
0
   _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
875
0
}
876
877
#ifndef HB_NO_VERTICAL
878
static hb_bool_t
879
hb_ot_get_font_v_extents (hb_font_t *font,
880
        void *font_data HB_UNUSED,
881
        hb_font_extents_t *metrics,
882
        void *user_data HB_UNUSED)
883
0
{
884
0
  return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
885
0
   _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
886
0
   _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
887
0
}
888
#endif
889
890
#ifndef HB_NO_DRAW
891
static hb_bool_t
892
hb_ot_draw_glyph_or_fail (hb_font_t *font,
893
        void *font_data HB_UNUSED,
894
        hb_codepoint_t glyph,
895
        hb_draw_funcs_t *draw_funcs, void *draw_data,
896
        void *user_data)
897
0
{
898
0
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
899
0
  hb_draw_session_t draw_session {draw_funcs, draw_data};
900
0
  bool ret = false;
901
902
0
  OT::hb_scalar_cache_t *gvar_cache = nullptr;
903
0
  if (font->num_coords)
904
0
  {
905
0
    ot_font->check_serial (font);
906
0
    gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar);
907
0
  }
908
909
0
#ifndef HB_NO_VAR_COMPOSITES
910
0
  if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; }
911
0
#endif
912
  // Keep the following in synch with VARC::get_path_at()
913
0
  if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; }
914
915
0
#ifndef HB_NO_CFF
916
0
  if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; }
917
0
  if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; }
918
0
#endif
919
920
0
done:
921
922
0
  ot_font->draw.release_gvar_cache (gvar_cache);
923
924
0
  return ret;
925
0
}
926
#endif
927
928
#ifndef HB_NO_PAINT
929
static hb_bool_t
930
hb_ot_paint_glyph_or_fail (hb_font_t *font,
931
         void *font_data,
932
         hb_codepoint_t glyph,
933
         hb_paint_funcs_t *paint_funcs, void *paint_data,
934
         unsigned int palette,
935
         hb_color_t foreground,
936
         void *user_data)
937
0
{
938
0
#ifndef HB_NO_COLOR
939
0
  if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true;
940
0
  if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
941
0
#ifndef HB_NO_OT_FONT_BITMAP
942
0
  if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
943
0
  if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true;
944
0
#endif
945
0
#endif
946
0
  return false;
947
0
}
948
#endif
949
950
static inline void free_static_ot_funcs ();
951
952
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
953
{
954
  static hb_font_funcs_t *create ()
955
1
  {
956
1
    hb_font_funcs_t *funcs = hb_font_funcs_create ();
957
958
1
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
959
1
    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
960
1
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
961
962
1
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
963
1
    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
964
965
1
#ifndef HB_NO_VERTICAL
966
1
    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
967
1
    hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
968
1
    hb_font_funcs_set_glyph_v_origins_func (funcs, hb_ot_get_glyph_v_origins, nullptr, nullptr);
969
1
#endif
970
971
1
#ifndef HB_NO_DRAW
972
1
    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ot_draw_glyph_or_fail, nullptr, nullptr);
973
1
#endif
974
975
1
#ifndef HB_NO_PAINT
976
1
    hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ot_paint_glyph_or_fail, nullptr, nullptr);
977
1
#endif
978
979
1
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
980
    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
981
982
1
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
983
1
    hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
984
1
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
985
1
#endif
986
987
1
    hb_font_funcs_make_immutable (funcs);
988
989
1
    hb_atexit (free_static_ot_funcs);
990
991
1
    return funcs;
992
1
  }
993
} static_ot_funcs;
994
995
static inline
996
void free_static_ot_funcs ()
997
1
{
998
1
  static_ot_funcs.free_instance ();
999
1
}
1000
1001
static hb_font_funcs_t *
1002
_hb_ot_get_font_funcs ()
1003
10.1k
{
1004
10.1k
  return static_ot_funcs.get_unconst ();
1005
10.1k
}
1006
1007
1008
/**
1009
 * hb_ot_font_set_funcs:
1010
 * @font: #hb_font_t to work upon
1011
 *
1012
 * Sets the font functions to use when working with @font to
1013
 * the HarfBuzz's native implementation. This is the default
1014
 * for fonts newly created.
1015
 *
1016
 * Since: 0.9.28
1017
 **/
1018
void
1019
hb_ot_font_set_funcs (hb_font_t *font)
1020
10.1k
{
1021
10.1k
  hb_ot_font_t *ot_font = _hb_ot_font_create (font);
1022
10.1k
  if (unlikely (!ot_font))
1023
0
    return;
1024
1025
10.1k
  hb_font_set_funcs (font,
1026
10.1k
         _hb_ot_get_font_funcs (),
1027
10.1k
         ot_font,
1028
10.1k
         _hb_ot_font_destroy);
1029
10.1k
}
1030
1031
#endif