Coverage Report

Created: 2026-08-14 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-ft.cc
Line
Count
Source
1
/*
2
 * Copyright © 2009  Red Hat, Inc.
3
 * Copyright © 2009  Keith Stribley
4
 * Copyright © 2015  Google, Inc.
5
 *
6
 *  This is part of HarfBuzz, a text shaping library.
7
 *
8
 * Permission is hereby granted, without written agreement and without
9
 * license or royalty fees, to use, copy, modify, and distribute this
10
 * software and its documentation for any purpose, provided that the
11
 * above copyright notice and the following two paragraphs appear in
12
 * all copies of this software.
13
 *
14
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18
 * DAMAGE.
19
 *
20
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25
 *
26
 * Red Hat Author(s): Behdad Esfahbod
27
 * Google Author(s): Behdad Esfahbod
28
 */
29
30
#include "hb.hh"
31
32
#ifdef HAVE_FREETYPE
33
34
#include "hb-ft.h"
35
36
#include "hb-cache.hh"
37
#include "hb-draw.hh"
38
#include "hb-font.hh"
39
#include "hb-machinery.hh"
40
#include "hb-ot-os2-table.hh"
41
#include "hb-ot-shaper-arabic-pua.hh"
42
#include "hb-paint.hh"
43
44
#include FT_MODULE_H
45
#include FT_ADVANCES_H
46
#include FT_MULTIPLE_MASTERS_H
47
#include FT_OUTLINE_H
48
#include FT_TRUETYPE_TABLES_H
49
#include FT_SYNTHESIS_H
50
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
51
#include FT_COLOR_H
52
#endif
53
54
55
/**
56
 * SECTION:hb-ft
57
 * @title: hb-ft
58
 * @short_description: FreeType integration
59
 * @include: hb-ft.h
60
 *
61
 * Functions for using HarfBuzz with the FreeType library.
62
 *
63
 * HarfBuzz supports using FreeType to provide face and
64
 * font data.
65
 *
66
 * <note>Note that FreeType is not thread-safe, therefore these
67
 * functions are not thread-safe either.</note>
68
 **/
69
70
71
/* TODO:
72
 *
73
 * In general, this file does a fine job of what it's supposed to do.
74
 * There are, however, things that need more work:
75
 *
76
 *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
77
 *     would work fine.  However, we also abuse this API for performing in font-space,
78
 *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
79
 *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
80
 *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
81
 *     ourselves.
82
 *
83
 *   - We don't handle / allow for emboldening / obliqueing.
84
 *
85
 *   - In the future, we should add constructors to create fonts in font space?
86
 */
87
88
89
using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
90
91
struct hb_ft_font_t
92
{
93
  int load_flags;
94
  bool symbol; /* Whether selected cmap is symbol cmap. */
95
  bool unref; /* Whether to destroy ft_face when done. */
96
  bool transform; /* Whether to apply FT_Face's transform. */
97
98
  mutable hb_mutex_t lock; /* Protects members below. */
99
  FT_Face ft_face;
100
  mutable hb_atomic_t<unsigned> cached_serial;
101
  mutable hb_ft_advance_cache_t advance_cache;
102
};
103
104
static hb_ft_font_t *
105
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
106
0
{
107
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t));
108
0
  if (unlikely (!ft_font)) return nullptr;
109
110
0
  ft_font->lock.init ();
111
0
  ft_font->ft_face = ft_face;
112
0
  ft_font->symbol = symbol;
113
0
  ft_font->unref = unref;
114
115
0
  ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
116
117
0
  ft_font->cached_serial = UINT_MAX;
118
0
  new (&ft_font->advance_cache) hb_ft_advance_cache_t;
119
120
0
  return ft_font;
121
0
}
122
123
static void
124
_hb_ft_face_destroy (void *data)
125
0
{
126
0
  FT_Done_Face ((FT_Face) data);
127
0
}
128
129
static void
130
_hb_ft_font_destroy (void *data)
131
0
{
132
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
133
134
0
  if (ft_font->unref)
135
0
    _hb_ft_face_destroy (ft_font->ft_face);
136
137
0
  ft_font->lock.fini ();
138
139
0
  hb_free (ft_font);
140
0
}
141
142
143
/* hb_font changed, update FT_Face. */
144
static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
145
0
{
146
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
147
0
    return;
148
149
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
150
151
0
  float x_mult = 1.f, y_mult = 1.f;
152
153
0
  if (font->x_scale < 0) x_mult = -x_mult;
154
0
  if (font->y_scale < 0) y_mult = -y_mult;
155
156
0
  if (FT_Set_Char_Size (ft_face,
157
0
      abs (font->x_scale), abs (font->y_scale),
158
0
      0, 0
159
#if 0
160
        font->x_ppem * 72 * 64 / font->x_scale,
161
        font->y_ppem * 72 * 64 / font->y_scale
162
#endif
163
0
     ) && ft_face->num_fixed_sizes)
164
0
  {
165
#ifdef HAVE_FT_GET_TRANSFORM
166
    /* Bitmap font, eg. bitmap color emoji. */
167
    /* Pick largest size? */
168
    int x_scale  = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem;
169
    int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem;
170
    FT_Set_Char_Size (ft_face,
171
          x_scale, y_scale,
172
          0, 0);
173
174
    /* This contains the sign that was previously in x_mult/y_mult. */
175
    x_mult = (float) font->x_scale / x_scale;
176
    y_mult = (float) font->y_scale / y_scale;
177
#endif
178
0
  }
179
0
  else
180
0
  { /* Shrug */ }
181
182
183
0
  if (x_mult != 1.f || y_mult != 1.f)
184
0
  {
185
0
    FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
186
0
        0, (int) roundf (y_mult * (1<<16))};
187
0
    FT_Set_Transform (ft_face, &matrix, nullptr);
188
0
    ft_font->transform = true;
189
0
  }
190
0
  else
191
0
    FT_Set_Transform (ft_face, nullptr, nullptr);
192
193
0
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
194
0
  if (font->has_nonzero_coords)
195
0
  {
196
0
    unsigned int num_coords;
197
0
    const float *coords = hb_font_get_var_coords_design (font, &num_coords);
198
0
    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
199
0
    if (ft_coords)
200
0
    {
201
0
      for (unsigned int i = 0; i < num_coords; i++)
202
0
    ft_coords[i] = coords[i] * 65536.f;
203
0
      FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
204
0
      hb_free (ft_coords);
205
0
    }
206
0
  }
207
0
  else if (font->num_coords)
208
0
  {
209
    // Some old versions of FreeType crash if we
210
    // call this function on non-variable fonts.
211
0
    FT_Set_Var_Design_Coordinates (ft_face, 0, nullptr);
212
0
  }
213
0
#endif
214
0
}
215
216
/* Check if hb_font changed, update FT_Face. */
217
static inline bool
218
_hb_ft_hb_font_check_changed (hb_font_t *font,
219
            const hb_ft_font_t *ft_font)
220
0
{
221
0
  if (font->serial != ft_font->cached_serial)
222
0
  {
223
0
    hb_lock_t lock (ft_font->lock);
224
0
    _hb_ft_hb_font_changed (font, ft_font->ft_face);
225
0
    ft_font->advance_cache.clear ();
226
0
    ft_font->cached_serial.set_release (font->serial.get_acquire ());
227
0
    return true;
228
0
  }
229
0
  return false;
230
0
}
231
232
233
/**
234
 * hb_ft_font_set_load_flags:
235
 * @font: #hb_font_t to work upon
236
 * @load_flags: The FreeType load flags to set
237
 *
238
 * Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
239
 *
240
 * For more information, see
241
 * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
242
 *
243
 * This function works with #hb_font_t objects created by
244
 * hb_ft_font_create() or hb_ft_font_create_referenced().
245
 *
246
 * Since: 1.0.5
247
 **/
248
void
249
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
250
0
{
251
0
  if (hb_object_is_immutable (font))
252
0
    return;
253
254
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
255
0
    return;
256
257
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
258
259
0
  ft_font->load_flags = load_flags;
260
0
}
261
262
/**
263
 * hb_ft_font_get_load_flags:
264
 * @font: #hb_font_t to work upon
265
 *
266
 * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
267
 *
268
 * For more information, see
269
 * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
270
 *
271
 * This function works with #hb_font_t objects created by
272
 * hb_ft_font_create() or hb_ft_font_create_referenced().
273
 *
274
 * Return value: FT_Load_Glyph flags found, or 0
275
 *
276
 * Since: 1.0.5
277
 **/
278
int
279
hb_ft_font_get_load_flags (hb_font_t *font)
280
0
{
281
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
282
0
    return 0;
283
284
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
285
286
0
  return ft_font->load_flags;
287
0
}
288
289
/**
290
 * hb_ft_font_get_ft_face: (skip)
291
 * @font: #hb_font_t to work upon
292
 *
293
 * Fetches the FT_Face associated with the specified #hb_font_t
294
 * font object.
295
 *
296
 * This function works with #hb_font_t objects created by
297
 * hb_ft_font_create() or hb_ft_font_create_referenced().
298
 *
299
 * Return value: (nullable): the FT_Face found or `NULL`
300
 *
301
 * Since: 10.4.0
302
 **/
303
FT_Face
304
hb_ft_font_get_ft_face (hb_font_t *font)
305
0
{
306
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
307
0
    return nullptr;
308
309
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
310
311
0
  return ft_font->ft_face;
312
0
}
313
314
#ifndef HB_DISABLE_DEPRECATED
315
316
/**
317
 * hb_ft_font_get_face: (skip)
318
 * @font: #hb_font_t to work upon
319
 *
320
 * Fetches the FT_Face associated with the specified #hb_font_t
321
 * font object.
322
 *
323
 * This function works with #hb_font_t objects created by
324
 * hb_ft_font_create() or hb_ft_font_create_referenced().
325
 *
326
 * Return value: (nullable): the FT_Face found or `NULL`
327
 *
328
 * Since: 0.9.2
329
 * Deprecated: 10.4.0: Use hb_ft_font_get_ft_face() instead.
330
 **/
331
FT_Face
332
hb_ft_font_get_face (hb_font_t *font)
333
0
{
334
0
  return hb_ft_font_get_ft_face (font);
335
0
}
336
337
#endif
338
339
/**
340
 * hb_ft_font_lock_face: (skip)
341
 * @font: #hb_font_t to work upon
342
 *
343
 * Gets the FT_Face associated with @font.
344
 *
345
 * This face will be kept around and access to the FT_Face object
346
 * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face().
347
 *
348
 * This function works with #hb_font_t objects created by
349
 * hb_ft_font_create() or hb_ft_font_create_referenced().
350
 *
351
 * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
352
 * Since: 2.6.5
353
 **/
354
FT_Face
355
hb_ft_font_lock_face (hb_font_t *font)
356
0
{
357
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
358
0
    return nullptr;
359
360
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
361
362
0
  ft_font->lock.lock ();
363
364
0
  return ft_font->ft_face;
365
0
}
366
367
/**
368
 * hb_ft_font_unlock_face: (skip)
369
 * @font: #hb_font_t to work upon
370
 *
371
 * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
372
 *
373
 * Since: 2.6.5
374
 **/
375
void
376
hb_ft_font_unlock_face (hb_font_t *font)
377
0
{
378
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
379
0
    return;
380
381
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
382
383
0
  ft_font->lock.unlock ();
384
0
}
385
386
387
static hb_bool_t
388
hb_ft_get_nominal_glyph (hb_font_t *font,
389
       void *font_data,
390
       hb_codepoint_t unicode,
391
       hb_codepoint_t *glyph,
392
       void *user_data HB_UNUSED)
393
0
{
394
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
395
0
  hb_lock_t lock (ft_font->lock);
396
0
  unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
397
398
0
  if (unlikely (!g))
399
0
  {
400
0
    if (unlikely (ft_font->symbol))
401
0
    {
402
0
      switch ((unsigned) font->face->table.OS2->get_font_page ()) {
403
0
      case OT::OS2::font_page_t::FONT_PAGE_NONE:
404
0
  if (unicode <= 0x00FFu)
405
    /* For symbol-encoded OpenType fonts, we duplicate the
406
     * U+F000..F0FF range at U+0000..U+00FF.  That's what
407
     * Windows seems to do, and that's hinted about at:
408
     * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
409
     * under "Non-Standard (Symbol) Fonts". */
410
0
    g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
411
0
  break;
412
0
#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
413
0
      case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
414
0
  g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode));
415
0
  break;
416
0
      case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
417
0
  g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode));
418
0
  break;
419
0
#endif
420
0
      default:
421
0
  break;
422
0
      }
423
0
      if (!g)
424
0
  return false;
425
0
    }
426
0
    else
427
0
      return false;
428
0
  }
429
430
0
  *glyph = g;
431
0
  return true;
432
0
}
433
434
static unsigned int
435
hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
436
        void *font_data,
437
        unsigned int count,
438
        const hb_codepoint_t *first_unicode,
439
        unsigned int unicode_stride,
440
        hb_codepoint_t *first_glyph,
441
        unsigned int glyph_stride,
442
        void *user_data HB_UNUSED)
443
0
{
444
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
445
0
  hb_lock_t lock (ft_font->lock);
446
0
  unsigned int done;
447
0
  for (done = 0;
448
0
       done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
449
0
       done++)
450
0
  {
451
0
    first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
452
0
    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
453
0
  }
454
  /* We don't need to do ft_font->symbol dance here, since HB calls the singular
455
   * nominal_glyph() for what we don't handle here. */
456
0
  return done;
457
0
}
458
459
460
static hb_bool_t
461
hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
462
         void *font_data,
463
         hb_codepoint_t unicode,
464
         hb_codepoint_t variation_selector,
465
         hb_codepoint_t *glyph,
466
         void *user_data HB_UNUSED)
467
0
{
468
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
469
0
  hb_lock_t lock (ft_font->lock);
470
0
  unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
471
472
0
  if (unlikely (!g))
473
0
    return false;
474
475
0
  *glyph = g;
476
0
  return true;
477
0
}
478
479
static void
480
hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
481
          unsigned count,
482
          const hb_codepoint_t *first_glyph,
483
          unsigned glyph_stride,
484
          hb_position_t *first_advance,
485
          unsigned advance_stride,
486
          void *user_data HB_UNUSED)
487
0
{
488
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
489
0
  _hb_ft_hb_font_check_changed (font, ft_font);
490
491
0
  hb_lock_t lock (ft_font->lock);
492
0
  FT_Face ft_face = ft_font->ft_face;
493
0
  int load_flags = ft_font->load_flags;
494
0
  float x_mult;
495
#ifdef HAVE_FT_GET_TRANSFORM
496
  if (ft_font->transform)
497
  {
498
    FT_Matrix matrix;
499
    FT_Get_Transform (ft_face, &matrix, nullptr);
500
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
501
    x_mult *= font->x_scale < 0 ? -1 : +1;
502
  }
503
  else
504
#endif
505
0
  {
506
0
    x_mult = font->x_scale < 0 ? -1 : +1;
507
0
  }
508
509
0
  for (unsigned int i = 0; i < count; i++)
510
0
  {
511
0
    FT_Fixed v = 0;
512
0
    hb_codepoint_t glyph = *first_glyph;
513
514
0
    unsigned int cv;
515
0
    if (ft_font->advance_cache.get (glyph, &cv))
516
0
      v = cv;
517
0
    else
518
0
    {
519
0
      FT_Get_Advance (ft_face, glyph, load_flags, &v);
520
      /* Work around bug that FreeType seems to return negative advance
521
       * for variable-set fonts if x_scale is negative! */
522
0
      v = abs (v);
523
0
      v = (int) (v * x_mult + (1<<9)) >> 10;
524
0
      ft_font->advance_cache.set (glyph, v);
525
0
    }
526
527
0
    *first_advance = v;
528
0
    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
529
0
    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
530
0
  }
531
0
}
532
533
#ifndef HB_NO_VERTICAL
534
static hb_position_t
535
hb_ft_get_glyph_v_advance (hb_font_t *font,
536
         void *font_data,
537
         hb_codepoint_t glyph,
538
         void *user_data HB_UNUSED)
539
0
{
540
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
541
0
  _hb_ft_hb_font_check_changed (font, ft_font);
542
543
0
  hb_lock_t lock (ft_font->lock);
544
0
  FT_Fixed v;
545
0
  float y_mult;
546
#ifdef HAVE_FT_GET_TRANSFORM
547
  if (ft_font->transform)
548
  {
549
    FT_Matrix matrix;
550
    FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
551
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
552
    y_mult *= font->y_scale < 0 ? -1 : +1;
553
  }
554
  else
555
#endif
556
0
  {
557
0
    y_mult = font->y_scale < 0 ? -1 : +1;
558
0
  }
559
560
0
  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
561
0
    return 0;
562
563
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
564
   * have a Y growing upward.  Hence the extra negation. */
565
0
  v = ((-v + (1<<9)) >> 10);
566
567
0
  return (hb_position_t) (y_mult * v);
568
0
}
569
#endif
570
571
#ifndef HB_NO_VERTICAL
572
static hb_bool_t
573
hb_ft_get_glyph_v_origin (hb_font_t *font,
574
        void *font_data,
575
        hb_codepoint_t glyph,
576
        hb_position_t *x,
577
        hb_position_t *y,
578
        void *user_data HB_UNUSED)
579
0
{
580
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
581
0
  _hb_ft_hb_font_check_changed (font, ft_font);
582
583
0
  hb_lock_t lock (ft_font->lock);
584
0
  FT_Face ft_face = ft_font->ft_face;
585
0
  float x_mult, y_mult;
586
#ifdef HAVE_FT_GET_TRANSFORM
587
  if (ft_font->transform)
588
  {
589
    FT_Matrix matrix;
590
    FT_Get_Transform (ft_face, &matrix, nullptr);
591
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
592
    x_mult *= font->x_scale < 0 ? -1 : +1;
593
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
594
    y_mult *= font->y_scale < 0 ? -1 : +1;
595
  }
596
  else
597
#endif
598
0
  {
599
0
    x_mult = font->x_scale < 0 ? -1 : +1;
600
0
    y_mult = font->y_scale < 0 ? -1 : +1;
601
0
  }
602
603
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
604
0
    return false;
605
606
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
607
   * have a Y growing upward.  Hence the extra negation. */
608
0
  *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
609
0
  *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
610
611
0
  *x = (hb_position_t) (x_mult * *x);
612
0
  *y = (hb_position_t) (y_mult * *y);
613
614
0
  return true;
615
0
}
616
#endif
617
618
#ifndef HB_NO_OT_SHAPE_FALLBACK
619
static hb_position_t
620
hb_ft_get_glyph_h_kerning (hb_font_t *font,
621
         void *font_data,
622
         hb_codepoint_t left_glyph,
623
         hb_codepoint_t right_glyph,
624
         void *user_data HB_UNUSED)
625
0
{
626
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
627
0
  _hb_ft_hb_font_check_changed (font, ft_font);
628
629
0
  hb_lock_t lock (ft_font->lock);
630
0
  FT_Vector kerningv;
631
632
0
  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
633
0
  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
634
0
    return 0;
635
636
0
  return kerningv.x;
637
0
}
638
#endif
639
640
static bool
641
hb_ft_is_colr_glyph (hb_font_t *font,
642
         void *font_data,
643
         hb_codepoint_t gid)
644
0
{
645
0
#ifndef HB_NO_PAINT
646
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
647
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
648
  FT_Face ft_face = ft_font->ft_face;
649
650
651
  /* COLRv1 */
652
  FT_OpaquePaint paint = {0};
653
  if (FT_Get_Color_Glyph_Paint (ft_face, gid,
654
              FT_COLOR_NO_ROOT_TRANSFORM,
655
              &paint))
656
    return true;
657
658
  /* COLRv0 */
659
  FT_LayerIterator  iterator;
660
  FT_UInt  layer_glyph_index;
661
  FT_UInt  layer_color_index;
662
  iterator.p  = NULL;
663
  if (FT_Get_Color_Glyph_Layer (ft_face,
664
        gid,
665
        &layer_glyph_index,
666
        &layer_color_index,
667
        &iterator))
668
    return true;
669
#endif
670
0
#endif
671
672
0
  return false;
673
0
}
674
675
static hb_bool_t
676
hb_ft_get_glyph_extents (hb_font_t *font,
677
       void *font_data,
678
       hb_codepoint_t glyph,
679
       hb_glyph_extents_t *extents,
680
       void *user_data HB_UNUSED)
681
0
{
682
  // FreeType doesn't return COLR glyph extents.
683
0
  if (hb_ft_is_colr_glyph (font, font_data, glyph))
684
0
    return false;
685
686
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
687
0
  _hb_ft_hb_font_check_changed (font, ft_font);
688
689
0
  hb_lock_t lock (ft_font->lock);
690
0
  FT_Face ft_face = ft_font->ft_face;
691
0
  float x_mult, y_mult;
692
693
#ifdef HAVE_FT_GET_TRANSFORM
694
  if (ft_font->transform)
695
  {
696
    FT_Matrix matrix;
697
    FT_Get_Transform (ft_face, &matrix, nullptr);
698
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
699
    x_mult *= font->x_scale < 0 ? -1 : +1;
700
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
701
    y_mult *= font->y_scale < 0 ? -1 : +1;
702
  }
703
  else
704
#endif
705
0
  {
706
0
    x_mult = font->x_scale < 0 ? -1 : +1;
707
0
    y_mult = font->y_scale < 0 ? -1 : +1;
708
0
  }
709
710
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
711
0
    return false;
712
713
  /* Copied from hb_font_t::scale_glyph_extents. */
714
715
0
  float x1 = x_mult * ft_face->glyph->metrics.horiBearingX;
716
0
  float y1 = y_mult * ft_face->glyph->metrics.horiBearingY;
717
0
  float x2 = x1 + x_mult *  ft_face->glyph->metrics.width;
718
0
  float y2 = y1 + y_mult * -ft_face->glyph->metrics.height;
719
720
0
  extents->x_bearing = roundf (x1);
721
0
  extents->y_bearing = roundf (y1);
722
0
  extents->width = roundf (x2) - extents->x_bearing;
723
0
  extents->height = roundf (y2) - extents->y_bearing;
724
725
0
  return true;
726
0
}
727
728
static hb_bool_t
729
hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
730
             void *font_data,
731
             hb_codepoint_t glyph,
732
             unsigned int point_index,
733
             hb_position_t *x,
734
             hb_position_t *y,
735
             void *user_data HB_UNUSED)
736
0
{
737
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
738
0
  _hb_ft_hb_font_check_changed (font, ft_font);
739
740
0
  hb_lock_t lock (ft_font->lock);
741
0
  FT_Face ft_face = ft_font->ft_face;
742
743
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
744
0
      return false;
745
746
0
  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
747
0
      return false;
748
749
0
  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
750
0
      return false;
751
752
0
  *x = ft_face->glyph->outline.points[point_index].x;
753
0
  *y = ft_face->glyph->outline.points[point_index].y;
754
755
0
  return true;
756
0
}
757
758
static hb_bool_t
759
hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
760
          void *font_data,
761
          hb_codepoint_t glyph,
762
          char *name, unsigned int size,
763
          void *user_data HB_UNUSED)
764
0
{
765
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
766
0
  hb_lock_t lock (ft_font->lock);
767
0
  FT_Face ft_face = ft_font->ft_face;
768
769
0
  if (!size)
770
0
  {
771
0
    char buf[128];
772
0
    return !FT_Get_Glyph_Name (ft_face, glyph, buf, sizeof (buf)) && *buf;
773
0
  }
774
775
0
  hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
776
0
  if (ret && (size && !*name))
777
0
    ret = false;
778
779
0
  return ret;
780
0
}
781
782
static hb_bool_t
783
hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
784
         void *font_data,
785
         const char *name, int len, /* -1 means nul-terminated */
786
         hb_codepoint_t *glyph,
787
         void *user_data HB_UNUSED)
788
0
{
789
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
790
0
  hb_lock_t lock (ft_font->lock);
791
0
  FT_Face ft_face = ft_font->ft_face;
792
793
0
  if (len < 0)
794
0
    *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
795
0
  else {
796
    /* Make a nul-terminated version. */
797
0
    char buf[128];
798
0
    len = hb_min (len, (int) sizeof (buf) - 1);
799
0
    strncpy (buf, name, len);
800
0
    buf[len] = '\0';
801
0
    *glyph = FT_Get_Name_Index (ft_face, buf);
802
0
  }
803
804
0
  if (*glyph == 0)
805
0
  {
806
    /* Check whether the given name was actually the name of glyph 0. */
807
0
    char buf[128];
808
0
    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
809
0
  len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
810
0
      return true;
811
0
  }
812
813
0
  return *glyph != 0;
814
0
}
815
816
static hb_bool_t
817
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
818
        void *font_data,
819
        hb_font_extents_t *metrics,
820
        void *user_data HB_UNUSED)
821
0
{
822
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
823
0
  _hb_ft_hb_font_check_changed (font, ft_font);
824
825
0
  hb_lock_t lock (ft_font->lock);
826
0
  FT_Face ft_face = ft_font->ft_face;
827
0
  float y_mult;
828
#ifdef HAVE_FT_GET_TRANSFORM
829
  if (ft_font->transform)
830
  {
831
    FT_Matrix matrix;
832
    FT_Get_Transform (ft_face, &matrix, nullptr);
833
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
834
    y_mult *= font->y_scale < 0 ? -1 : +1;
835
  }
836
  else
837
#endif
838
0
  {
839
0
    y_mult = font->y_scale < 0 ? -1 : +1;
840
0
  }
841
842
0
  if (ft_face->units_per_EM != 0)
843
0
  {
844
0
    metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
845
0
    metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
846
0
    metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
847
0
  }
848
0
  else
849
0
  {
850
    /* Bitmap-only font, eg. color bitmap font. */
851
0
    metrics->ascender = ft_face->size->metrics.ascender;
852
0
    metrics->descender = ft_face->size->metrics.descender;
853
0
    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
854
0
  }
855
856
0
  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
857
0
  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
858
0
  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
859
860
0
  return true;
861
0
}
862
863
#ifndef HB_NO_DRAW
864
865
static int
866
_hb_ft_move_to (const FT_Vector *to,
867
    void *arg)
868
0
{
869
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
870
0
  drawing->move_to (to->x, to->y);
871
0
  return FT_Err_Ok;
872
0
}
873
874
static int
875
_hb_ft_line_to (const FT_Vector *to,
876
    void *arg)
877
0
{
878
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
879
0
  drawing->line_to (to->x, to->y);
880
0
  return FT_Err_Ok;
881
0
}
882
883
static int
884
_hb_ft_conic_to (const FT_Vector *control,
885
     const FT_Vector *to,
886
     void *arg)
887
0
{
888
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
889
0
  drawing->quadratic_to (control->x, control->y,
890
0
       to->x, to->y);
891
0
  return FT_Err_Ok;
892
0
}
893
894
static int
895
_hb_ft_cubic_to (const FT_Vector *control1,
896
     const FT_Vector *control2,
897
     const FT_Vector *to,
898
     void *arg)
899
0
{
900
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
901
0
  drawing->cubic_to (control1->x, control1->y,
902
0
         control2->x, control2->y,
903
0
         to->x, to->y);
904
0
  return FT_Err_Ok;
905
0
}
906
907
static hb_bool_t
908
hb_ft_draw_glyph_or_fail (hb_font_t *font,
909
        void *font_data,
910
        hb_codepoint_t glyph,
911
        hb_draw_funcs_t *draw_funcs, void *draw_data,
912
        void *user_data HB_UNUSED)
913
0
{
914
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
915
0
  _hb_ft_hb_font_check_changed (font, ft_font);
916
917
0
  hb_lock_t lock (ft_font->lock);
918
0
  FT_Face ft_face = ft_font->ft_face;
919
920
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph,
921
0
             FT_LOAD_NO_BITMAP | ft_font->load_flags)))
922
0
    return false;
923
924
0
  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
925
0
    return false;
926
927
0
  const FT_Outline_Funcs outline_funcs = {
928
0
    _hb_ft_move_to,
929
0
    _hb_ft_line_to,
930
0
    _hb_ft_conic_to,
931
0
    _hb_ft_cubic_to,
932
0
    0, /* shift */
933
0
    0, /* delta */
934
0
  };
935
936
0
  hb_draw_session_t draw_session {draw_funcs, draw_data};
937
938
0
  FT_Outline_Decompose (&ft_face->glyph->outline,
939
0
      &outline_funcs,
940
0
      &draw_session);
941
942
0
  return true;
943
0
}
944
#endif
945
946
#ifndef HB_NO_PAINT
947
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
948
949
#include "hb-ft-colr.hh"
950
951
static hb_bool_t
952
hb_ft_paint_glyph_or_fail (hb_font_t *font,
953
         void *font_data,
954
         hb_codepoint_t gid,
955
         hb_paint_funcs_t *paint_funcs, void *paint_data,
956
         unsigned int palette_index,
957
         hb_color_t foreground,
958
         void *user_data)
959
{
960
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
961
  _hb_ft_hb_font_check_changed (font, ft_font);
962
963
  hb_lock_t lock (ft_font->lock);
964
  FT_Face ft_face = ft_font->ft_face;
965
966
  FT_Long load_flags = ft_font->load_flags | FT_LOAD_COLOR;
967
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301
968
  load_flags |= FT_LOAD_NO_SVG;
969
#endif
970
971
  /* We release the lock before calling into glyph callbacks, such that
972
   * eg. draw API can call back into the face.*/
973
974
  if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags)))
975
    return false;
976
977
  if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
978
  {
979
    if (hb_ft_paint_glyph_colr (font, font_data, gid,
980
        paint_funcs, paint_data,
981
        palette_index, foreground,
982
        user_data))
983
      return true;
984
985
    // Outline glyph
986
    return false;
987
  }
988
989
  auto *glyph = ft_face->glyph;
990
  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
991
  {
992
    bool ret = false;
993
    auto &bitmap = glyph->bitmap;
994
    if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
995
    {
996
      if (bitmap.pitch != (signed) bitmap.width * 4)
997
        return ret;
998
999
      ft_font->lock.unlock ();
1000
1001
      hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
1002
          bitmap.pitch * bitmap.rows,
1003
          HB_MEMORY_MODE_DUPLICATE,
1004
          nullptr, nullptr);
1005
1006
      hb_glyph_extents_t extents;
1007
      if (!font->get_glyph_extents (gid, &extents, false))
1008
  goto out;
1009
1010
      if (paint_funcs->image (paint_data,
1011
            blob,
1012
            bitmap.width,
1013
            bitmap.rows,
1014
            HB_PAINT_IMAGE_FORMAT_BGRA,
1015
            0.f,
1016
            &extents))
1017
        ret = true;
1018
1019
    out:
1020
      hb_blob_destroy (blob);
1021
      ft_font->lock.lock ();
1022
    }
1023
1024
    return ret;
1025
  }
1026
  return false;
1027
}
1028
#endif
1029
#endif
1030
1031
1032
static inline void free_static_ft_funcs ();
1033
1034
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
1035
{
1036
  static hb_font_funcs_t *create ()
1037
0
  {
1038
0
    hb_font_funcs_t *funcs = hb_font_funcs_create ();
1039
1040
0
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
1041
0
    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
1042
0
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
1043
1044
0
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
1045
0
    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
1046
1047
0
#ifndef HB_NO_VERTICAL
1048
0
    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
1049
0
    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
1050
0
#endif
1051
1052
0
#ifndef HB_NO_OT_SHAPE_FALLBACK
1053
0
    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
1054
0
#endif
1055
0
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
1056
0
    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
1057
0
    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
1058
0
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
1059
1060
0
#ifndef HB_NO_DRAW
1061
0
    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ft_draw_glyph_or_fail, nullptr, nullptr);
1062
0
#endif
1063
1064
0
#ifndef HB_NO_PAINT
1065
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
1066
    hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ft_paint_glyph_or_fail, nullptr, nullptr);
1067
#endif
1068
0
#endif
1069
1070
0
    hb_font_funcs_make_immutable (funcs);
1071
1072
0
    hb_atexit (free_static_ft_funcs);
1073
1074
0
    return funcs;
1075
0
  }
1076
} static_ft_funcs;
1077
1078
static inline
1079
void free_static_ft_funcs ()
1080
0
{
1081
0
  static_ft_funcs.free_instance ();
1082
0
}
1083
1084
static hb_font_funcs_t *
1085
_hb_ft_get_font_funcs ()
1086
0
{
1087
0
  return static_ft_funcs.get_unconst ();
1088
0
}
1089
1090
static void
1091
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
1092
0
{
1093
0
  bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
1094
1095
0
  hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
1096
0
  if (unlikely (!ft_font)) return;
1097
1098
0
  hb_font_set_funcs (font,
1099
0
         _hb_ft_get_font_funcs (),
1100
0
         ft_font,
1101
0
         _hb_ft_font_destroy);
1102
0
}
1103
1104
1105
static hb_blob_t *
1106
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
1107
0
{
1108
0
  FT_Face ft_face = (FT_Face) user_data;
1109
0
  FT_Byte *buffer;
1110
0
  FT_ULong  length = 0;
1111
0
  FT_Error error;
1112
1113
  /* In new FreeType, a tag value of 1 loads the SFNT table directory. Reject it. */
1114
0
  if (tag == 1)
1115
0
    return nullptr;
1116
1117
  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
1118
1119
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
1120
0
  if (error)
1121
0
    return nullptr;
1122
1123
0
  buffer = (FT_Byte *) hb_malloc (length);
1124
0
  if (!buffer)
1125
0
    return nullptr;
1126
0
  auto buffer_guard = hb_make_scope_guard ([&]() { hb_free (buffer); });
1127
1128
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
1129
0
  if (error)
1130
0
    return nullptr;
1131
1132
0
  buffer_guard.release ();
1133
0
  return hb_blob_create ((const char *) buffer, length,
1134
0
       HB_MEMORY_MODE_WRITABLE,
1135
0
       buffer, hb_free);
1136
0
}
1137
1138
static unsigned
1139
_hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED,
1140
           unsigned int start_offset,
1141
           unsigned int *table_count,
1142
           hb_tag_t *table_tags,
1143
           void *user_data)
1144
0
{
1145
0
  FT_Face ft_face = (FT_Face) user_data;
1146
1147
0
  FT_ULong population = 0;
1148
0
  FT_Sfnt_Table_Info (ft_face,
1149
0
          0, // table_index; ignored
1150
0
          nullptr,
1151
0
                      &population);
1152
1153
0
  if (!table_count)
1154
0
    return population;
1155
1156
0
  if (unlikely (start_offset >= population))
1157
0
  {
1158
0
    *table_count = 0;
1159
0
    return population;
1160
0
  }
1161
1162
0
  unsigned end_offset = start_offset + *table_count;
1163
0
  if (unlikely (end_offset < start_offset)) /* Overflow. */
1164
0
  {
1165
0
    *table_count = 0;
1166
0
    return population;
1167
0
  }
1168
0
  end_offset = hb_min (end_offset, (unsigned) population);
1169
1170
0
  *table_count = end_offset - start_offset;
1171
0
  if (table_tags)
1172
0
    for (unsigned i = start_offset; i < end_offset; i++)
1173
0
    {
1174
0
      FT_ULong tag = 0, length;
1175
0
      FT_Sfnt_Table_Info (ft_face, i, &tag, &length);
1176
0
      table_tags[i - start_offset] = tag;
1177
0
    }
1178
1179
0
  return population;
1180
0
}
1181
1182
1183
/**
1184
 * hb_ft_face_create:
1185
 * @ft_face: FT_Face to work upon
1186
 * @destroy: (nullable) (scope async): A callback to call when the face object is not needed anymore
1187
 *
1188
 * Creates an #hb_face_t face object from the specified FT_Face.
1189
 *
1190
 * Note that this is using the FT_Face object just to get at the underlying
1191
 * font data, and fonts created from the returned #hb_face_t will use the native
1192
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1193
 *
1194
 * This variant of the function does not provide any life-cycle management.
1195
 *
1196
 * Most client programs should use hb_ft_face_create_referenced()
1197
 * (or, perhaps, hb_ft_face_create_cached()) instead.
1198
 *
1199
 * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
1200
 * then it is the client program's responsibility to destroy @ft_face
1201
 * after the #hb_face_t face object has been destroyed.
1202
 *
1203
 * Return value: (transfer full): the new #hb_face_t face object
1204
 *
1205
 * Since: 0.9.2
1206
 **/
1207
hb_face_t *
1208
hb_ft_face_create (FT_Face           ft_face,
1209
       hb_destroy_func_t destroy)
1210
0
{
1211
0
  hb_face_t *face;
1212
1213
0
  if (!ft_face->stream->read) {
1214
0
    hb_blob_t *blob;
1215
1216
0
    blob = hb_blob_create ((const char *) ft_face->stream->base,
1217
0
         (unsigned int) ft_face->stream->size,
1218
0
         HB_MEMORY_MODE_READONLY,
1219
0
         ft_face, destroy);
1220
0
    face = hb_face_create (blob, ft_face->face_index);
1221
0
    hb_blob_destroy (blob);
1222
0
  } else {
1223
0
    face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
1224
0
    hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr);
1225
0
  }
1226
1227
0
  hb_face_set_index (face, ft_face->face_index);
1228
0
  hb_face_set_upem (face, ft_face->units_per_EM);
1229
1230
0
  return face;
1231
0
}
1232
1233
/**
1234
 * hb_ft_face_create_referenced:
1235
 * @ft_face: FT_Face to work upon
1236
 *
1237
 * Creates an #hb_face_t face object from the specified FT_Face.
1238
 *
1239
 * Note that this is using the FT_Face object just to get at the underlying
1240
 * font data, and fonts created from the returned #hb_face_t will use the native
1241
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1242
 *
1243
 * This is the preferred variant of the hb_ft_face_create*
1244
 * function family, because it calls FT_Reference_Face() on @ft_face,
1245
 * ensuring that @ft_face remains alive as long as the resulting
1246
 * #hb_face_t face object remains alive. Also calls FT_Done_Face()
1247
 * when the #hb_face_t face object is destroyed.
1248
 *
1249
 * Use this version unless you know you have good reasons not to.
1250
 *
1251
 * Return value: (transfer full): the new #hb_face_t face object
1252
 *
1253
 * Since: 0.9.38
1254
 **/
1255
hb_face_t *
1256
hb_ft_face_create_referenced (FT_Face ft_face)
1257
0
{
1258
0
  FT_Reference_Face (ft_face);
1259
0
  return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
1260
0
}
1261
1262
static void
1263
hb_ft_face_finalize (void *arg)
1264
0
{
1265
0
  FT_Face ft_face = (FT_Face) arg;
1266
0
  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
1267
0
}
1268
1269
/**
1270
 * hb_ft_face_create_cached:
1271
 * @ft_face: FT_Face to work upon
1272
 *
1273
 * Creates an #hb_face_t face object from the specified FT_Face.
1274
 *
1275
 * Note that this is using the FT_Face object just to get at the underlying
1276
 * font data, and fonts created from the returned #hb_face_t will use the native
1277
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1278
 *
1279
 * This variant of the function caches the newly created #hb_face_t
1280
 * face object, using the @generic pointer of @ft_face. Subsequent function
1281
 * calls that are passed the same @ft_face parameter will have the same
1282
 * #hb_face_t returned to them, and that #hb_face_t will be correctly
1283
 * reference counted.
1284
 *
1285
 * However, client programs are still responsible for destroying
1286
 * @ft_face after the last #hb_face_t face object has been destroyed.
1287
 *
1288
 * Return value: (transfer full): the new #hb_face_t face object
1289
 *
1290
 * Since: 0.9.2
1291
 **/
1292
hb_face_t *
1293
hb_ft_face_create_cached (FT_Face ft_face)
1294
0
{
1295
0
  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
1296
0
  {
1297
0
    if (ft_face->generic.finalizer)
1298
0
      ft_face->generic.finalizer (ft_face);
1299
1300
0
    ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
1301
0
    ft_face->generic.finalizer = hb_ft_face_finalize;
1302
0
  }
1303
1304
0
  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
1305
0
}
1306
1307
/**
1308
 * hb_ft_font_create:
1309
 * @ft_face: FT_Face to work upon
1310
 * @destroy: (nullable) (scope async): A callback to call when the font object is not needed anymore
1311
 *
1312
 * Creates an #hb_font_t font object from the specified FT_Face.
1313
 *
1314
 * <note>Note: You must set the face size on @ft_face before calling
1315
 * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
1316
 * access `size` member of FT_Face unconditionally.</note>
1317
 *
1318
 * This variant of the function does not provide any life-cycle management.
1319
 *
1320
 * Most client programs should use hb_ft_font_create_referenced()
1321
 * instead.
1322
 *
1323
 * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
1324
 * then it is the client program's responsibility to destroy @ft_face
1325
 * only after the #hb_font_t font object has been destroyed.
1326
 *
1327
 * HarfBuzz will use the @destroy callback on the #hb_font_t font object
1328
 * if it is supplied when you use this function. However, even if @destroy
1329
 * is provided, it is the client program's responsibility to destroy @ft_face,
1330
 * and it is the client program's responsibility to ensure that @ft_face is
1331
 * destroyed only after the #hb_font_t font object has been destroyed.
1332
 *
1333
 * Return value: (transfer full): the new #hb_font_t font object
1334
 *
1335
 * Since: 0.9.2
1336
 **/
1337
hb_font_t *
1338
hb_ft_font_create (FT_Face           ft_face,
1339
       hb_destroy_func_t destroy)
1340
0
{
1341
0
  hb_font_t *font;
1342
0
  hb_face_t *face;
1343
1344
0
  face = hb_ft_face_create (ft_face, destroy);
1345
0
  font = hb_font_create (face);
1346
0
  hb_face_destroy (face);
1347
0
  _hb_ft_font_set_funcs (font, ft_face, false);
1348
0
  hb_ft_font_changed (font);
1349
0
  return font;
1350
0
}
1351
1352
/**
1353
 * hb_ft_font_changed:
1354
 * @font: #hb_font_t to work upon
1355
 *
1356
 * Refreshes the state of @font when the underlying FT_Face has changed.
1357
 * This function should be called after changing the size or
1358
 * variation-axis settings on the FT_Face.
1359
 *
1360
 * Since: 1.0.5
1361
 **/
1362
void
1363
hb_ft_font_changed (hb_font_t *font)
1364
0
{
1365
0
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1366
0
    return;
1367
1368
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1369
1370
0
  FT_Face ft_face = ft_font->ft_face;
1371
1372
0
  hb_font_set_scale (font,
1373
0
         (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
1374
0
         (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
1375
#if 0 /* hb-ft works in no-hinting model */
1376
  hb_font_set_ppem (font,
1377
        ft_face->size->metrics.x_ppem,
1378
        ft_face->size->metrics.y_ppem);
1379
#endif
1380
1381
0
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
1382
0
  FT_MM_Var *mm_var = nullptr;
1383
0
  if (!FT_Get_MM_Var (ft_face, &mm_var))
1384
0
  {
1385
0
    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
1386
0
    int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
1387
0
    if (coords && ft_coords)
1388
0
    {
1389
0
      if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
1390
0
      {
1391
0
  bool nonzero = false;
1392
1393
0
  for (unsigned int i = 0; i < mm_var->num_axis; ++i)
1394
0
   {
1395
0
    coords[i] = (ft_coords[i] + 2) >> 2;
1396
0
    nonzero = nonzero || coords[i];
1397
0
   }
1398
1399
0
  if (nonzero)
1400
0
    hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
1401
0
  else
1402
0
    hb_font_set_var_coords_normalized (font, nullptr, 0);
1403
0
      }
1404
0
    }
1405
0
    hb_free (coords);
1406
0
    hb_free (ft_coords);
1407
0
#ifdef HAVE_FT_DONE_MM_VAR
1408
0
    FT_Done_MM_Var (ft_face->glyph->library, mm_var);
1409
#else
1410
    hb_free (mm_var);
1411
#endif
1412
0
  }
1413
0
#endif
1414
1415
0
  ft_font->advance_cache.clear ();
1416
0
  ft_font->cached_serial = font->serial;
1417
0
}
1418
1419
/**
1420
 * hb_ft_hb_font_changed:
1421
 * @font: #hb_font_t to work upon
1422
 *
1423
 * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
1424
 * @font has changed.
1425
 * This function should be called after changing the size or
1426
 * variation-axis settings on the @font.
1427
 * This call is fast if nothing has changed on @font.
1428
 *
1429
 * Note that as of version 11.0.0, calling this function is not necessary,
1430
 * as HarfBuzz will automatically detect changes to the font and update
1431
 * the underlying FT_Face as needed.
1432
 *
1433
 * Return value: true if changed, false otherwise
1434
 *
1435
 * Since: 4.4.0
1436
 **/
1437
hb_bool_t
1438
hb_ft_hb_font_changed (hb_font_t *font)
1439
0
{
1440
0
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1441
0
    return false;
1442
1443
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1444
1445
0
  return _hb_ft_hb_font_check_changed (font, ft_font);
1446
0
}
1447
1448
/**
1449
 * hb_ft_font_create_referenced:
1450
 * @ft_face: FT_Face to work upon
1451
 *
1452
 * Creates an #hb_font_t font object from the specified FT_Face.
1453
 *
1454
 * <note>Note: You must set the face size on @ft_face before calling
1455
 * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
1456
 * and will access `size` member of FT_Face unconditionally.</note>
1457
 *
1458
 * This is the preferred variant of the hb_ft_font_create*
1459
 * function family, because it calls FT_Reference_Face() on @ft_face,
1460
 * ensuring that @ft_face remains alive as long as the resulting
1461
 * #hb_font_t font object remains alive.
1462
 *
1463
 * Use this version unless you know you have good reasons not to.
1464
 *
1465
 * Return value: (transfer full): the new #hb_font_t font object
1466
 *
1467
 * Since: 0.9.38
1468
 **/
1469
hb_font_t *
1470
hb_ft_font_create_referenced (FT_Face ft_face)
1471
0
{
1472
0
  FT_Reference_Face (ft_face);
1473
0
  return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
1474
0
}
1475
1476
1477
static void * _hb_ft_alloc (FT_Memory memory, long size)
1478
0
{ return hb_malloc (size); }
1479
1480
static void _hb_ft_free (FT_Memory memory, void *block)
1481
0
{ hb_free (block); }
1482
1483
static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block)
1484
0
{ return hb_realloc (block, new_size); }
1485
1486
static FT_MemoryRec_ m =
1487
{
1488
  nullptr,
1489
  _hb_ft_alloc,
1490
  _hb_ft_free,
1491
  _hb_ft_realloc
1492
};
1493
1494
static inline void free_static_ft_library ();
1495
1496
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
1497
                   hb_ft_library_lazy_loader_t>
1498
{
1499
  static FT_Library create ()
1500
0
  {
1501
0
    FT_Library l;
1502
0
    if (FT_New_Library (&m, &l))
1503
0
      return nullptr;
1504
1505
0
    FT_Add_Default_Modules (l);
1506
0
    FT_Set_Default_Properties (l);
1507
1508
0
    hb_atexit (free_static_ft_library);
1509
1510
0
    return l;
1511
0
  }
1512
  static void destroy (FT_Library l)
1513
0
  {
1514
0
    FT_Done_Library (l);
1515
0
  }
1516
  static FT_Library get_null ()
1517
0
  {
1518
0
    return nullptr;
1519
0
  }
1520
} static_ft_library;
1521
1522
static inline
1523
void free_static_ft_library ()
1524
0
{
1525
0
  static_ft_library.free_instance ();
1526
0
}
1527
1528
static FT_Library
1529
reference_ft_library ()
1530
0
{
1531
0
  FT_Library l = static_ft_library.get_unconst ();
1532
0
  if (unlikely (FT_Reference_Library (l)))
1533
0
  {
1534
0
    DEBUG_MSG (FT, l, "FT_Reference_Library() failed");
1535
0
    return nullptr;
1536
0
  }
1537
0
  return l;
1538
0
}
1539
1540
static hb_user_data_key_t ft_library_key = {0};
1541
1542
static void
1543
finalize_ft_library (void *arg)
1544
0
{
1545
0
  FT_Face ft_face = (FT_Face) arg;
1546
0
  FT_Done_Library ((FT_Library) ft_face->generic.data);
1547
0
}
1548
1549
static void
1550
destroy_ft_library (void *arg)
1551
0
{
1552
0
  FT_Done_Library ((FT_Library) arg);
1553
0
}
1554
1555
/**
1556
 * hb_ft_face_create_from_file_or_fail:
1557
 * @file_name: A font filename
1558
 * @index: The index of the face within the file
1559
 *
1560
 * Creates an #hb_face_t face object from the specified
1561
 * font file and face index.
1562
 *
1563
 * This is similar in functionality to hb_face_create_from_file_or_fail(),
1564
 * but uses the FreeType library for loading the font file. This can
1565
 * be useful, for example, to load WOFF and WOFF2 font data.
1566
 *
1567
 * Return value: (transfer full): The new face object, or `NULL` if
1568
 * no face is found at the specified index or the file cannot be read.
1569
 *
1570
 * Since: 10.1.0
1571
 */
1572
hb_face_t *
1573
hb_ft_face_create_from_file_or_fail (const char   *file_name,
1574
             unsigned int  index)
1575
0
{
1576
0
  FT_Library ft_library = reference_ft_library ();
1577
0
  if (unlikely (!ft_library))
1578
0
  {
1579
0
    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
1580
0
    return nullptr;
1581
0
  }
1582
1583
0
  FT_Face ft_face;
1584
0
  if (unlikely (FT_New_Face (ft_library,
1585
0
           file_name,
1586
0
           index,
1587
0
           &ft_face)))
1588
0
    return nullptr;
1589
1590
0
  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
1591
0
  FT_Done_Face (ft_face);
1592
1593
0
  ft_face->generic.data = ft_library;
1594
0
  ft_face->generic.finalizer = finalize_ft_library;
1595
1596
0
  if (hb_face_is_immutable (face))
1597
0
    return nullptr;
1598
1599
0
  return face;
1600
0
}
1601
1602
static hb_user_data_key_t ft_blob_key = {0};
1603
1604
static void
1605
_destroy_blob (void *p)
1606
0
{
1607
0
  hb_blob_destroy ((hb_blob_t *) p);
1608
0
}
1609
1610
/**
1611
 * hb_ft_face_create_from_blob_or_fail:
1612
 * @blob: A blob
1613
 * @index: The index of the face within the blob
1614
 *
1615
 * Creates an #hb_face_t face object from the specified
1616
 * font blob and face index.
1617
 *
1618
 * This is similar in functionality to hb_face_create_or_fail(),
1619
 * but uses the FreeType library for loading the font blob. This can
1620
 * be useful, for example, to load WOFF and WOFF2 font data.
1621
 *
1622
 * Return value: (transfer full): The new face object, or `NULL` if
1623
 * loading fails (eg. blob does not contain valid font data).
1624
 *
1625
 * Since: 11.0.0
1626
 */
1627
hb_face_t *
1628
hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
1629
             unsigned int  index)
1630
0
{
1631
0
  FT_Library ft_library = reference_ft_library ();
1632
0
  if (unlikely (!ft_library))
1633
0
  {
1634
0
    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
1635
0
    return nullptr;
1636
0
  }
1637
1638
0
  hb_blob_make_immutable (blob);
1639
0
  unsigned blob_size;
1640
0
  const char *blob_data = hb_blob_get_data (blob, &blob_size);
1641
1642
0
  FT_Face ft_face;
1643
0
  if (unlikely (FT_New_Memory_Face (ft_library,
1644
0
            (const FT_Byte *) blob_data,
1645
0
            blob_size,
1646
0
            index,
1647
0
            &ft_face)))
1648
0
    return nullptr;
1649
1650
0
  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
1651
0
  FT_Done_Face (ft_face);
1652
1653
0
  ft_face->generic.data = ft_library;
1654
0
  ft_face->generic.finalizer = finalize_ft_library;
1655
1656
0
  if (hb_face_is_immutable (face))
1657
0
    return nullptr;
1658
1659
  // Hook the blob to the hb_face_t, since FT_Face still needs it.
1660
0
  hb_blob_reference (blob);
1661
0
  if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true))
1662
0
  {
1663
0
    hb_blob_destroy (blob);
1664
0
    hb_face_destroy (face);
1665
0
    return nullptr;
1666
0
  }
1667
1668
0
  return face;
1669
0
}
1670
1671
static void
1672
_release_blob (void *arg)
1673
0
{
1674
0
  FT_Face ft_face = (FT_Face) arg;
1675
0
  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
1676
0
}
1677
1678
/**
1679
 * hb_ft_font_set_funcs:
1680
 * @font: #hb_font_t to work upon
1681
 *
1682
 * Configures the font-functions structure of the specified
1683
 * #hb_font_t font object to use FreeType font functions.
1684
 *
1685
 * In particular, you can use this function to configure an
1686
 * existing #hb_face_t face object for use with FreeType font
1687
 * functions even if that #hb_face_t face object was initially
1688
 * created with hb_face_create(), and therefore was not
1689
 * initially configured to use FreeType font functions.
1690
 *
1691
 * An #hb_font_t object created with hb_ft_font_create()
1692
 * is preconfigured for FreeType font functions and does not
1693
 * require this function to be used.
1694
 *
1695
 * Note that if you modify the underlying #hb_font_t after
1696
 * calling this function, you need to call hb_ft_hb_font_changed()
1697
 * to update the underlying FT_Face.
1698
 *
1699
 * <note>Note: Internally, this function creates an FT_Face.
1700
* </note>
1701
 *
1702
 * Since: 1.0.5
1703
 **/
1704
void
1705
hb_ft_font_set_funcs (hb_font_t *font)
1706
0
{
1707
0
  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
1708
0
  if (font->destroy == (hb_destroy_func_t) _hb_ft_font_destroy && font->user_data)
1709
0
  {
1710
0
    const hb_ft_font_t *existing_ft_font = (const hb_ft_font_t *) font->user_data;
1711
0
    load_flags = existing_ft_font->load_flags;
1712
0
  }
1713
1714
  // In case of failure...
1715
0
  hb_font_set_funcs (font,
1716
0
         hb_font_funcs_get_empty (),
1717
0
         nullptr, nullptr);
1718
1719
0
  hb_blob_t *blob = hb_face_reference_blob (font->face);
1720
0
  unsigned int blob_length;
1721
0
  const char *blob_data = hb_blob_get_data (blob, &blob_length);
1722
0
  if (unlikely (!blob_length))
1723
0
    DEBUG_MSG (FT, font, "Font face has empty blob");
1724
1725
0
  FT_Library ft_library = reference_ft_library ();
1726
0
  if (unlikely (!ft_library))
1727
0
  {
1728
0
    hb_blob_destroy (blob);
1729
0
    DEBUG_MSG (FT, font, "reference_ft_library failed");
1730
0
    return;
1731
0
  }
1732
1733
0
  FT_Face ft_face = nullptr;
1734
0
  if (unlikely (FT_New_Memory_Face (ft_library,
1735
0
            (const FT_Byte *) blob_data,
1736
0
            blob_length,
1737
0
            hb_face_get_index (font->face),
1738
0
            &ft_face)))
1739
0
  {
1740
0
    hb_blob_destroy (blob);
1741
0
    DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed");
1742
0
    return;
1743
0
  }
1744
1745
0
  if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
1746
0
    FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
1747
1748
  // Hook the blob to the FT_Face
1749
0
  ft_face->generic.data = blob;
1750
0
  ft_face->generic.finalizer = _release_blob;
1751
1752
  // And the FT_Library to the blob
1753
0
  if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true)))
1754
0
  {
1755
0
    DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed");
1756
0
    FT_Done_Face (ft_face);
1757
0
    return;
1758
0
  }
1759
1760
0
  _hb_ft_font_set_funcs (font, ft_face, true);
1761
0
  hb_ft_font_set_load_flags (font, load_flags);
1762
1763
0
  _hb_ft_hb_font_changed (font, ft_face);
1764
0
}
1765
1766
#endif