Coverage Report

Created: 2025-10-13 06:24

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
  hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
770
0
  if (ret && (size && !*name))
771
0
    ret = false;
772
773
0
  return ret;
774
0
}
775
776
static hb_bool_t
777
hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
778
         void *font_data,
779
         const char *name, int len, /* -1 means nul-terminated */
780
         hb_codepoint_t *glyph,
781
         void *user_data HB_UNUSED)
782
0
{
783
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
784
0
  hb_lock_t lock (ft_font->lock);
785
0
  FT_Face ft_face = ft_font->ft_face;
786
787
0
  if (len < 0)
788
0
    *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
789
0
  else {
790
    /* Make a nul-terminated version. */
791
0
    char buf[128];
792
0
    len = hb_min (len, (int) sizeof (buf) - 1);
793
0
    strncpy (buf, name, len);
794
0
    buf[len] = '\0';
795
0
    *glyph = FT_Get_Name_Index (ft_face, buf);
796
0
  }
797
798
0
  if (*glyph == 0)
799
0
  {
800
    /* Check whether the given name was actually the name of glyph 0. */
801
0
    char buf[128];
802
0
    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
803
0
  len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
804
0
      return true;
805
0
  }
806
807
0
  return *glyph != 0;
808
0
}
809
810
static hb_bool_t
811
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
812
        void *font_data,
813
        hb_font_extents_t *metrics,
814
        void *user_data HB_UNUSED)
815
0
{
816
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
817
0
  _hb_ft_hb_font_check_changed (font, ft_font);
818
819
0
  hb_lock_t lock (ft_font->lock);
820
0
  FT_Face ft_face = ft_font->ft_face;
821
0
  float y_mult;
822
#ifdef HAVE_FT_GET_TRANSFORM
823
  if (ft_font->transform)
824
  {
825
    FT_Matrix matrix;
826
    FT_Get_Transform (ft_face, &matrix, nullptr);
827
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
828
    y_mult *= font->y_scale < 0 ? -1 : +1;
829
  }
830
  else
831
#endif
832
0
  {
833
0
    y_mult = font->y_scale < 0 ? -1 : +1;
834
0
  }
835
836
0
  if (ft_face->units_per_EM != 0)
837
0
  {
838
0
    metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
839
0
    metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
840
0
    metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
841
0
  }
842
0
  else
843
0
  {
844
    /* Bitmap-only font, eg. color bitmap font. */
845
0
    metrics->ascender = ft_face->size->metrics.ascender;
846
0
    metrics->descender = ft_face->size->metrics.descender;
847
0
    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
848
0
  }
849
850
0
  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
851
0
  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
852
0
  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
853
854
0
  return true;
855
0
}
856
857
#ifndef HB_NO_DRAW
858
859
static int
860
_hb_ft_move_to (const FT_Vector *to,
861
    void *arg)
862
0
{
863
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
864
0
  drawing->move_to (to->x, to->y);
865
0
  return FT_Err_Ok;
866
0
}
867
868
static int
869
_hb_ft_line_to (const FT_Vector *to,
870
    void *arg)
871
0
{
872
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
873
0
  drawing->line_to (to->x, to->y);
874
0
  return FT_Err_Ok;
875
0
}
876
877
static int
878
_hb_ft_conic_to (const FT_Vector *control,
879
     const FT_Vector *to,
880
     void *arg)
881
0
{
882
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
883
0
  drawing->quadratic_to (control->x, control->y,
884
0
       to->x, to->y);
885
0
  return FT_Err_Ok;
886
0
}
887
888
static int
889
_hb_ft_cubic_to (const FT_Vector *control1,
890
     const FT_Vector *control2,
891
     const FT_Vector *to,
892
     void *arg)
893
0
{
894
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
895
0
  drawing->cubic_to (control1->x, control1->y,
896
0
         control2->x, control2->y,
897
0
         to->x, to->y);
898
0
  return FT_Err_Ok;
899
0
}
900
901
static hb_bool_t
902
hb_ft_draw_glyph_or_fail (hb_font_t *font,
903
        void *font_data,
904
        hb_codepoint_t glyph,
905
        hb_draw_funcs_t *draw_funcs, void *draw_data,
906
        void *user_data HB_UNUSED)
907
0
{
908
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
909
0
  _hb_ft_hb_font_check_changed (font, ft_font);
910
911
0
  hb_lock_t lock (ft_font->lock);
912
0
  FT_Face ft_face = ft_font->ft_face;
913
914
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph,
915
0
             FT_LOAD_NO_BITMAP | ft_font->load_flags)))
916
0
    return false;
917
918
0
  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
919
0
    return false;
920
921
0
  const FT_Outline_Funcs outline_funcs = {
922
0
    _hb_ft_move_to,
923
0
    _hb_ft_line_to,
924
0
    _hb_ft_conic_to,
925
0
    _hb_ft_cubic_to,
926
0
    0, /* shift */
927
0
    0, /* delta */
928
0
  };
929
930
0
  hb_draw_session_t draw_session {draw_funcs, draw_data};
931
932
0
  FT_Outline_Decompose (&ft_face->glyph->outline,
933
0
      &outline_funcs,
934
0
      &draw_session);
935
936
0
  return true;
937
0
}
938
#endif
939
940
#ifndef HB_NO_PAINT
941
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
942
943
#include "hb-ft-colr.hh"
944
945
static hb_bool_t
946
hb_ft_paint_glyph_or_fail (hb_font_t *font,
947
         void *font_data,
948
         hb_codepoint_t gid,
949
         hb_paint_funcs_t *paint_funcs, void *paint_data,
950
         unsigned int palette_index,
951
         hb_color_t foreground,
952
         void *user_data)
953
{
954
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
955
  _hb_ft_hb_font_check_changed (font, ft_font);
956
957
  hb_lock_t lock (ft_font->lock);
958
  FT_Face ft_face = ft_font->ft_face;
959
960
  FT_Long load_flags = ft_font->load_flags | FT_LOAD_COLOR;
961
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301
962
  load_flags |= FT_LOAD_NO_SVG;
963
#endif
964
965
  /* We release the lock before calling into glyph callbacks, such that
966
   * eg. draw API can call back into the face.*/
967
968
  if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags)))
969
    return false;
970
971
  if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
972
  {
973
    if (hb_ft_paint_glyph_colr (font, font_data, gid,
974
        paint_funcs, paint_data,
975
        palette_index, foreground,
976
        user_data))
977
      return true;
978
979
    // Outline glyph
980
    return false;
981
  }
982
983
  auto *glyph = ft_face->glyph;
984
  if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
985
  {
986
    bool ret = false;
987
    auto &bitmap = glyph->bitmap;
988
    if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
989
    {
990
      if (bitmap.pitch != (signed) bitmap.width * 4)
991
        return ret;
992
993
      ft_font->lock.unlock ();
994
995
      hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
996
          bitmap.pitch * bitmap.rows,
997
          HB_MEMORY_MODE_DUPLICATE,
998
          nullptr, nullptr);
999
1000
      hb_glyph_extents_t extents;
1001
      if (!font->get_glyph_extents (gid, &extents, false))
1002
  goto out;
1003
1004
      if (paint_funcs->image (paint_data,
1005
            blob,
1006
            bitmap.width,
1007
            bitmap.rows,
1008
            HB_PAINT_IMAGE_FORMAT_BGRA,
1009
            0.f,
1010
            &extents))
1011
        ret = true;
1012
1013
    out:
1014
      hb_blob_destroy (blob);
1015
      ft_font->lock.lock ();
1016
    }
1017
1018
    return ret;
1019
  }
1020
  return false;
1021
}
1022
#endif
1023
#endif
1024
1025
1026
static inline void free_static_ft_funcs ();
1027
1028
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
1029
{
1030
  static hb_font_funcs_t *create ()
1031
0
  {
1032
0
    hb_font_funcs_t *funcs = hb_font_funcs_create ();
1033
1034
0
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
1035
0
    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
1036
0
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
1037
1038
0
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
1039
0
    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
1040
1041
0
#ifndef HB_NO_VERTICAL
1042
0
    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
1043
0
    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
1044
0
#endif
1045
1046
0
#ifndef HB_NO_OT_SHAPE_FALLBACK
1047
0
    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
1048
0
#endif
1049
0
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
1050
0
    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
1051
0
    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
1052
0
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
1053
1054
0
#ifndef HB_NO_DRAW
1055
0
    hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_ft_draw_glyph_or_fail, nullptr, nullptr);
1056
0
#endif
1057
1058
0
#ifndef HB_NO_PAINT
1059
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
1060
    hb_font_funcs_set_paint_glyph_or_fail_func (funcs, hb_ft_paint_glyph_or_fail, nullptr, nullptr);
1061
#endif
1062
0
#endif
1063
1064
0
    hb_font_funcs_make_immutable (funcs);
1065
1066
0
    hb_atexit (free_static_ft_funcs);
1067
1068
0
    return funcs;
1069
0
  }
1070
} static_ft_funcs;
1071
1072
static inline
1073
void free_static_ft_funcs ()
1074
0
{
1075
0
  static_ft_funcs.free_instance ();
1076
0
}
1077
1078
static hb_font_funcs_t *
1079
_hb_ft_get_font_funcs ()
1080
0
{
1081
0
  return static_ft_funcs.get_unconst ();
1082
0
}
1083
1084
static void
1085
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
1086
0
{
1087
0
  bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
1088
1089
0
  hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
1090
0
  if (unlikely (!ft_font)) return;
1091
1092
0
  hb_font_set_funcs (font,
1093
0
         _hb_ft_get_font_funcs (),
1094
0
         ft_font,
1095
0
         _hb_ft_font_destroy);
1096
0
}
1097
1098
1099
static hb_blob_t *
1100
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
1101
0
{
1102
0
  FT_Face ft_face = (FT_Face) user_data;
1103
0
  FT_Byte *buffer;
1104
0
  FT_ULong  length = 0;
1105
0
  FT_Error error;
1106
1107
  /* In new FreeType, a tag value of 1 loads the SFNT table directory. Reject it. */
1108
0
  if (tag == 1)
1109
0
    return nullptr;
1110
1111
  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
1112
1113
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
1114
0
  if (error)
1115
0
    return nullptr;
1116
1117
0
  buffer = (FT_Byte *) hb_malloc (length);
1118
0
  if (!buffer)
1119
0
    return nullptr;
1120
1121
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
1122
0
  if (error)
1123
0
  {
1124
0
    hb_free (buffer);
1125
0
    return nullptr;
1126
0
  }
1127
1128
0
  return hb_blob_create ((const char *) buffer, length,
1129
0
       HB_MEMORY_MODE_WRITABLE,
1130
0
       buffer, hb_free);
1131
0
}
1132
1133
static unsigned
1134
_hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED,
1135
           unsigned int start_offset,
1136
           unsigned int *table_count,
1137
           hb_tag_t *table_tags,
1138
           void *user_data)
1139
0
{
1140
0
  FT_Face ft_face = (FT_Face) user_data;
1141
1142
0
  FT_ULong population = 0;
1143
0
  FT_Sfnt_Table_Info (ft_face,
1144
0
          0, // table_index; ignored
1145
0
          nullptr,
1146
0
                      &population);
1147
1148
0
  if (!table_count)
1149
0
    return population;
1150
0
  else
1151
0
    *table_count = 0;
1152
1153
0
  if (unlikely (start_offset >= population))
1154
0
    return population;
1155
1156
0
  unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population);
1157
0
  if (unlikely (end_offset < start_offset))
1158
0
    return population;
1159
1160
0
  *table_count = end_offset - start_offset;
1161
0
  for (unsigned i = start_offset; i < end_offset; i++)
1162
0
  {
1163
0
    FT_ULong tag = 0, length;
1164
0
    FT_Sfnt_Table_Info (ft_face, i, &tag, &length);
1165
0
    table_tags[i - start_offset] = tag;
1166
0
  }
1167
1168
0
  return population;
1169
0
}
1170
1171
1172
/**
1173
 * hb_ft_face_create:
1174
 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
1175
 * @destroy: (nullable): A callback to call when the face object is not needed anymore
1176
 *
1177
 * Creates an #hb_face_t face object from the specified FT_Face.
1178
 *
1179
 * Note that this is using the FT_Face object just to get at the underlying
1180
 * font data, and fonts created from the returned #hb_face_t will use the native
1181
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1182
 *
1183
 * This variant of the function does not provide any life-cycle management.
1184
 *
1185
 * Most client programs should use hb_ft_face_create_referenced()
1186
 * (or, perhaps, hb_ft_face_create_cached()) instead.
1187
 *
1188
 * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
1189
 * then it is the client program's responsibility to destroy @ft_face
1190
 * after the #hb_face_t face object has been destroyed.
1191
 *
1192
 * Return value: (transfer full): the new #hb_face_t face object
1193
 *
1194
 * Since: 0.9.2
1195
 **/
1196
hb_face_t *
1197
hb_ft_face_create (FT_Face           ft_face,
1198
       hb_destroy_func_t destroy)
1199
0
{
1200
0
  hb_face_t *face;
1201
1202
0
  if (!ft_face->stream->read) {
1203
0
    hb_blob_t *blob;
1204
1205
0
    blob = hb_blob_create ((const char *) ft_face->stream->base,
1206
0
         (unsigned int) ft_face->stream->size,
1207
0
         HB_MEMORY_MODE_READONLY,
1208
0
         ft_face, destroy);
1209
0
    face = hb_face_create (blob, ft_face->face_index);
1210
0
    hb_blob_destroy (blob);
1211
0
  } else {
1212
0
    face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
1213
0
    hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr);
1214
0
  }
1215
1216
0
  hb_face_set_index (face, ft_face->face_index);
1217
0
  hb_face_set_upem (face, ft_face->units_per_EM);
1218
1219
0
  return face;
1220
0
}
1221
1222
/**
1223
 * hb_ft_face_create_referenced:
1224
 * @ft_face: FT_Face to work upon
1225
 *
1226
 * Creates an #hb_face_t face object from the specified FT_Face.
1227
 *
1228
 * Note that this is using the FT_Face object just to get at the underlying
1229
 * font data, and fonts created from the returned #hb_face_t will use the native
1230
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1231
 *
1232
 * This is the preferred variant of the hb_ft_face_create*
1233
 * function family, because it calls FT_Reference_Face() on @ft_face,
1234
 * ensuring that @ft_face remains alive as long as the resulting
1235
 * #hb_face_t face object remains alive. Also calls FT_Done_Face()
1236
 * when the #hb_face_t face object is destroyed.
1237
 *
1238
 * Use this version unless you know you have good reasons not to.
1239
 *
1240
 * Return value: (transfer full): the new #hb_face_t face object
1241
 *
1242
 * Since: 0.9.38
1243
 **/
1244
hb_face_t *
1245
hb_ft_face_create_referenced (FT_Face ft_face)
1246
0
{
1247
0
  FT_Reference_Face (ft_face);
1248
0
  return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
1249
0
}
1250
1251
static void
1252
hb_ft_face_finalize (void *arg)
1253
0
{
1254
0
  FT_Face ft_face = (FT_Face) arg;
1255
0
  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
1256
0
}
1257
1258
/**
1259
 * hb_ft_face_create_cached:
1260
 * @ft_face: FT_Face to work upon
1261
 *
1262
 * Creates an #hb_face_t face object from the specified FT_Face.
1263
 *
1264
 * Note that this is using the FT_Face object just to get at the underlying
1265
 * font data, and fonts created from the returned #hb_face_t will use the native
1266
 * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1267
 *
1268
 * This variant of the function caches the newly created #hb_face_t
1269
 * face object, using the @generic pointer of @ft_face. Subsequent function
1270
 * calls that are passed the same @ft_face parameter will have the same
1271
 * #hb_face_t returned to them, and that #hb_face_t will be correctly
1272
 * reference counted.
1273
 *
1274
 * However, client programs are still responsible for destroying
1275
 * @ft_face after the last #hb_face_t face object has been destroyed.
1276
 *
1277
 * Return value: (transfer full): the new #hb_face_t face object
1278
 *
1279
 * Since: 0.9.2
1280
 **/
1281
hb_face_t *
1282
hb_ft_face_create_cached (FT_Face ft_face)
1283
0
{
1284
0
  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
1285
0
  {
1286
0
    if (ft_face->generic.finalizer)
1287
0
      ft_face->generic.finalizer (ft_face);
1288
1289
0
    ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
1290
0
    ft_face->generic.finalizer = hb_ft_face_finalize;
1291
0
  }
1292
1293
0
  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
1294
0
}
1295
1296
/**
1297
 * hb_ft_font_create:
1298
 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
1299
 * @destroy: (nullable): A callback to call when the font object is not needed anymore
1300
 *
1301
 * Creates an #hb_font_t font object from the specified FT_Face.
1302
 *
1303
 * <note>Note: You must set the face size on @ft_face before calling
1304
 * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
1305
 * access `size` member of FT_Face unconditionally.</note>
1306
 *
1307
 * This variant of the function does not provide any life-cycle management.
1308
 *
1309
 * Most client programs should use hb_ft_font_create_referenced()
1310
 * instead.
1311
 *
1312
 * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
1313
 * then it is the client program's responsibility to destroy @ft_face
1314
 * only after the #hb_font_t font object has been destroyed.
1315
 *
1316
 * HarfBuzz will use the @destroy callback on the #hb_font_t font object
1317
 * if it is supplied when you use this function. However, even if @destroy
1318
 * is provided, it is the client program's responsibility to destroy @ft_face,
1319
 * and it is the client program's responsibility to ensure that @ft_face is
1320
 * destroyed only after the #hb_font_t font object has been destroyed.
1321
 *
1322
 * Return value: (transfer full): the new #hb_font_t font object
1323
 *
1324
 * Since: 0.9.2
1325
 **/
1326
hb_font_t *
1327
hb_ft_font_create (FT_Face           ft_face,
1328
       hb_destroy_func_t destroy)
1329
0
{
1330
0
  hb_font_t *font;
1331
0
  hb_face_t *face;
1332
1333
0
  face = hb_ft_face_create (ft_face, destroy);
1334
0
  font = hb_font_create (face);
1335
0
  hb_face_destroy (face);
1336
0
  _hb_ft_font_set_funcs (font, ft_face, false);
1337
0
  hb_ft_font_changed (font);
1338
0
  return font;
1339
0
}
1340
1341
/**
1342
 * hb_ft_font_changed:
1343
 * @font: #hb_font_t to work upon
1344
 *
1345
 * Refreshes the state of @font when the underlying FT_Face has changed.
1346
 * This function should be called after changing the size or
1347
 * variation-axis settings on the FT_Face.
1348
 *
1349
 * Since: 1.0.5
1350
 **/
1351
void
1352
hb_ft_font_changed (hb_font_t *font)
1353
0
{
1354
0
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1355
0
    return;
1356
1357
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1358
1359
0
  FT_Face ft_face = ft_font->ft_face;
1360
1361
0
  hb_font_set_scale (font,
1362
0
         (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
1363
0
         (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
1364
#if 0 /* hb-ft works in no-hinting model */
1365
  hb_font_set_ppem (font,
1366
        ft_face->size->metrics.x_ppem,
1367
        ft_face->size->metrics.y_ppem);
1368
#endif
1369
1370
0
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
1371
0
  FT_MM_Var *mm_var = nullptr;
1372
0
  if (!FT_Get_MM_Var (ft_face, &mm_var))
1373
0
  {
1374
0
    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
1375
0
    int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
1376
0
    if (coords && ft_coords)
1377
0
    {
1378
0
      if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
1379
0
      {
1380
0
  bool nonzero = false;
1381
1382
0
  for (unsigned int i = 0; i < mm_var->num_axis; ++i)
1383
0
   {
1384
0
    coords[i] = (ft_coords[i] + 2) >> 2;
1385
0
    nonzero = nonzero || coords[i];
1386
0
   }
1387
1388
0
  if (nonzero)
1389
0
    hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
1390
0
  else
1391
0
    hb_font_set_var_coords_normalized (font, nullptr, 0);
1392
0
      }
1393
0
    }
1394
0
    hb_free (coords);
1395
0
    hb_free (ft_coords);
1396
0
#ifdef HAVE_FT_DONE_MM_VAR
1397
0
    FT_Done_MM_Var (ft_face->glyph->library, mm_var);
1398
#else
1399
    hb_free (mm_var);
1400
#endif
1401
0
  }
1402
0
#endif
1403
1404
0
  ft_font->advance_cache.clear ();
1405
0
  ft_font->cached_serial = font->serial;
1406
0
}
1407
1408
/**
1409
 * hb_ft_hb_font_changed:
1410
 * @font: #hb_font_t to work upon
1411
 *
1412
 * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
1413
 * @font has changed.
1414
 * This function should be called after changing the size or
1415
 * variation-axis settings on the @font.
1416
 * This call is fast if nothing has changed on @font.
1417
 *
1418
 * Note that as of version 11.0.0, calling this function is not necessary,
1419
 * as HarfBuzz will automatically detect changes to the font and update
1420
 * the underlying FT_Face as needed.
1421
 *
1422
 * Return value: true if changed, false otherwise
1423
 *
1424
 * Since: 4.4.0
1425
 **/
1426
hb_bool_t
1427
hb_ft_hb_font_changed (hb_font_t *font)
1428
0
{
1429
0
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1430
0
    return false;
1431
1432
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1433
1434
0
  return _hb_ft_hb_font_check_changed (font, ft_font);
1435
0
}
1436
1437
/**
1438
 * hb_ft_font_create_referenced:
1439
 * @ft_face: FT_Face to work upon
1440
 *
1441
 * Creates an #hb_font_t font object from the specified FT_Face.
1442
 *
1443
 * <note>Note: You must set the face size on @ft_face before calling
1444
 * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
1445
 * and will access `size` member of FT_Face unconditionally.</note>
1446
 *
1447
 * This is the preferred variant of the hb_ft_font_create*
1448
 * function family, because it calls FT_Reference_Face() on @ft_face,
1449
 * ensuring that @ft_face remains alive as long as the resulting
1450
 * #hb_font_t font object remains alive.
1451
 *
1452
 * Use this version unless you know you have good reasons not to.
1453
 *
1454
 * Return value: (transfer full): the new #hb_font_t font object
1455
 *
1456
 * Since: 0.9.38
1457
 **/
1458
hb_font_t *
1459
hb_ft_font_create_referenced (FT_Face ft_face)
1460
0
{
1461
0
  FT_Reference_Face (ft_face);
1462
0
  return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
1463
0
}
1464
1465
1466
static void * _hb_ft_alloc (FT_Memory memory, long size)
1467
0
{ return hb_malloc (size); }
1468
1469
static void _hb_ft_free (FT_Memory memory, void *block)
1470
0
{ hb_free (block); }
1471
1472
static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block)
1473
0
{ return hb_realloc (block, new_size); }
1474
1475
static FT_MemoryRec_ m =
1476
{
1477
  nullptr,
1478
  _hb_ft_alloc,
1479
  _hb_ft_free,
1480
  _hb_ft_realloc
1481
};
1482
1483
static inline void free_static_ft_library ();
1484
1485
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
1486
                   hb_ft_library_lazy_loader_t>
1487
{
1488
  static FT_Library create ()
1489
0
  {
1490
0
    FT_Library l;
1491
0
    if (FT_New_Library (&m, &l))
1492
0
      return nullptr;
1493
1494
0
    FT_Add_Default_Modules (l);
1495
0
    FT_Set_Default_Properties (l);
1496
1497
0
    hb_atexit (free_static_ft_library);
1498
1499
0
    return l;
1500
0
  }
1501
  static void destroy (FT_Library l)
1502
0
  {
1503
0
    FT_Done_Library (l);
1504
0
  }
1505
  static FT_Library get_null ()
1506
0
  {
1507
0
    return nullptr;
1508
0
  }
1509
} static_ft_library;
1510
1511
static inline
1512
void free_static_ft_library ()
1513
0
{
1514
0
  static_ft_library.free_instance ();
1515
0
}
1516
1517
static FT_Library
1518
reference_ft_library ()
1519
0
{
1520
0
  FT_Library l = static_ft_library.get_unconst ();
1521
0
  if (unlikely (FT_Reference_Library (l)))
1522
0
  {
1523
0
    DEBUG_MSG (FT, l, "FT_Reference_Library() failed");
1524
0
    return nullptr;
1525
0
  }
1526
0
  return l;
1527
0
}
1528
1529
static hb_user_data_key_t ft_library_key = {0};
1530
1531
static void
1532
finalize_ft_library (void *arg)
1533
0
{
1534
0
  FT_Face ft_face = (FT_Face) arg;
1535
0
  FT_Done_Library ((FT_Library) ft_face->generic.data);
1536
0
}
1537
1538
static void
1539
destroy_ft_library (void *arg)
1540
0
{
1541
0
  FT_Done_Library ((FT_Library) arg);
1542
0
}
1543
1544
/**
1545
 * hb_ft_face_create_from_file_or_fail:
1546
 * @file_name: A font filename
1547
 * @index: The index of the face within the file
1548
 *
1549
 * Creates an #hb_face_t face object from the specified
1550
 * font file and face index.
1551
 *
1552
 * This is similar in functionality to hb_face_create_from_file_or_fail(),
1553
 * but uses the FreeType library for loading the font file. This can
1554
 * be useful, for example, to load WOFF and WOFF2 font data.
1555
 *
1556
 * Return value: (transfer full): The new face object, or `NULL` if
1557
 * no face is found at the specified index or the file cannot be read.
1558
 *
1559
 * Since: 10.1.0
1560
 */
1561
hb_face_t *
1562
hb_ft_face_create_from_file_or_fail (const char   *file_name,
1563
             unsigned int  index)
1564
0
{
1565
0
  FT_Library ft_library = reference_ft_library ();
1566
0
  if (unlikely (!ft_library))
1567
0
  {
1568
0
    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
1569
0
    return nullptr;
1570
0
  }
1571
1572
0
  FT_Face ft_face;
1573
0
  if (unlikely (FT_New_Face (ft_library,
1574
0
           file_name,
1575
0
           index,
1576
0
           &ft_face)))
1577
0
    return nullptr;
1578
1579
0
  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
1580
0
  FT_Done_Face (ft_face);
1581
1582
0
  ft_face->generic.data = ft_library;
1583
0
  ft_face->generic.finalizer = finalize_ft_library;
1584
1585
0
  if (hb_face_is_immutable (face))
1586
0
    return nullptr;
1587
1588
0
  return face;
1589
0
}
1590
1591
static hb_user_data_key_t ft_blob_key = {0};
1592
1593
static void
1594
_destroy_blob (void *p)
1595
0
{
1596
0
  hb_blob_destroy ((hb_blob_t *) p);
1597
0
}
1598
1599
/**
1600
 * hb_ft_face_create_from_blob_or_fail:
1601
 * @blob: A blob
1602
 * @index: The index of the face within the blob
1603
 *
1604
 * Creates an #hb_face_t face object from the specified
1605
 * font blob and face index.
1606
 *
1607
 * This is similar in functionality to hb_face_create_from_blob_or_fail(),
1608
 * but uses the FreeType library for loading the font blob. This can
1609
 * be useful, for example, to load WOFF and WOFF2 font data.
1610
 *
1611
 * Return value: (transfer full): The new face object, or `NULL` if
1612
 * loading fails (eg. blob does not contain valid font data).
1613
 *
1614
 * Since: 11.0.0
1615
 */
1616
hb_face_t *
1617
hb_ft_face_create_from_blob_or_fail (hb_blob_t    *blob,
1618
             unsigned int  index)
1619
0
{
1620
0
  FT_Library ft_library = reference_ft_library ();
1621
0
  if (unlikely (!ft_library))
1622
0
  {
1623
0
    DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
1624
0
    return nullptr;
1625
0
  }
1626
1627
0
  hb_blob_make_immutable (blob);
1628
0
  unsigned blob_size;
1629
0
  const char *blob_data = hb_blob_get_data (blob, &blob_size);
1630
1631
0
  FT_Face ft_face;
1632
0
  if (unlikely (FT_New_Memory_Face (ft_library,
1633
0
            (const FT_Byte *) blob_data,
1634
0
            blob_size,
1635
0
            index,
1636
0
            &ft_face)))
1637
0
    return nullptr;
1638
1639
0
  hb_face_t *face = hb_ft_face_create_referenced (ft_face);
1640
0
  FT_Done_Face (ft_face);
1641
1642
0
  ft_face->generic.data = ft_library;
1643
0
  ft_face->generic.finalizer = finalize_ft_library;
1644
1645
0
  if (hb_face_is_immutable (face))
1646
0
    return nullptr;
1647
1648
  // Hook the blob to the hb_face_t, since FT_Face still needs it.
1649
0
  hb_blob_reference (blob);
1650
0
  if (!hb_face_set_user_data (face, &ft_blob_key, blob, _destroy_blob, true))
1651
0
  {
1652
0
    hb_blob_destroy (blob);
1653
0
    hb_face_destroy (face);
1654
0
    return nullptr;
1655
0
  }
1656
1657
0
  return face;
1658
0
}
1659
1660
static void
1661
_release_blob (void *arg)
1662
0
{
1663
0
  FT_Face ft_face = (FT_Face) arg;
1664
0
  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
1665
0
}
1666
1667
/**
1668
 * hb_ft_font_set_funcs:
1669
 * @font: #hb_font_t to work upon
1670
 *
1671
 * Configures the font-functions structure of the specified
1672
 * #hb_font_t font object to use FreeType font functions.
1673
 *
1674
 * In particular, you can use this function to configure an
1675
 * existing #hb_face_t face object for use with FreeType font
1676
 * functions even if that #hb_face_t face object was initially
1677
 * created with hb_face_create(), and therefore was not
1678
 * initially configured to use FreeType font functions.
1679
 *
1680
 * An #hb_font_t object created with hb_ft_font_create()
1681
 * is preconfigured for FreeType font functions and does not
1682
 * require this function to be used.
1683
 *
1684
 * Note that if you modify the underlying #hb_font_t after
1685
 * calling this function, you need to call hb_ft_hb_font_changed()
1686
 * to update the underlying FT_Face.
1687
 *
1688
 * <note>Note: Internally, this function creates an FT_Face.
1689
* </note>
1690
 *
1691
 * Since: 1.0.5
1692
 **/
1693
void
1694
hb_ft_font_set_funcs (hb_font_t *font)
1695
0
{
1696
  // In case of failure...
1697
0
  hb_font_set_funcs (font,
1698
0
         hb_font_funcs_get_empty (),
1699
0
         nullptr, nullptr);
1700
1701
0
  hb_blob_t *blob = hb_face_reference_blob (font->face);
1702
0
  unsigned int blob_length;
1703
0
  const char *blob_data = hb_blob_get_data (blob, &blob_length);
1704
0
  if (unlikely (!blob_length))
1705
0
    DEBUG_MSG (FT, font, "Font face has empty blob");
1706
1707
0
  FT_Library ft_library = reference_ft_library ();
1708
0
  if (unlikely (!ft_library))
1709
0
  {
1710
0
    hb_blob_destroy (blob);
1711
0
    DEBUG_MSG (FT, font, "reference_ft_library failed");
1712
0
    return;
1713
0
  }
1714
1715
0
  FT_Face ft_face = nullptr;
1716
0
  if (unlikely (FT_New_Memory_Face (ft_library,
1717
0
            (const FT_Byte *) blob_data,
1718
0
            blob_length,
1719
0
            hb_face_get_index (font->face),
1720
0
            &ft_face)))
1721
0
  {
1722
0
    hb_blob_destroy (blob);
1723
0
    DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed");
1724
0
    return;
1725
0
  }
1726
1727
0
  if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
1728
0
    FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
1729
1730
  // Hook the blob to the FT_Face
1731
0
  ft_face->generic.data = blob;
1732
0
  ft_face->generic.finalizer = _release_blob;
1733
1734
  // And the FT_Library to the blob
1735
0
  if (unlikely (!hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true)))
1736
0
  {
1737
0
    DEBUG_MSG (FT, font, "hb_blob_set_user_data() failed");
1738
0
    FT_Done_Face (ft_face);
1739
0
    return;
1740
0
  }
1741
1742
0
  _hb_ft_font_set_funcs (font, ft_face, true);
1743
0
  hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
1744
1745
0
  _hb_ft_hb_font_changed (font, ft_face);
1746
0
}
1747
1748
#endif