Coverage Report

Created: 2025-01-28 06:17

/src/mupdf/thirdparty/harfbuzz/src/hb-ft.cc
Line
Count
Source (jump to first uncovered line)
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-draw.hh"
37
#include "hb-font.hh"
38
#include "hb-machinery.hh"
39
#include "hb-cache.hh"
40
#include "hb-ot-os2-table.hh"
41
#include "hb-ot-shaper-arabic-pua.hh"
42
43
#include FT_ADVANCES_H
44
#include FT_MULTIPLE_MASTERS_H
45
#include FT_OUTLINE_H
46
#include FT_TRUETYPE_TABLES_H
47
48
49
/**
50
 * SECTION:hb-ft
51
 * @title: hb-ft
52
 * @short_description: FreeType integration
53
 * @include: hb-ft.h
54
 *
55
 * Functions for using HarfBuzz with the FreeType library.
56
 *
57
 * HarfBuzz supports using FreeType to provide face and
58
 * font data.
59
 *
60
 * <note>Note that FreeType is not thread-safe, therefore these
61
 * functions are not thread-safe either.</note>
62
 **/
63
64
65
/* TODO:
66
 *
67
 * In general, this file does a fine job of what it's supposed to do.
68
 * There are, however, things that need more work:
69
 *
70
 *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
71
 *     would work fine.  However, we also abuse this API for performing in font-space,
72
 *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
73
 *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
74
 *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
75
 *     ourselves.
76
 *
77
 *   - We don't handle / allow for emboldening / obliqueing.
78
 *
79
 *   - In the future, we should add constructors to create fonts in font space?
80
 */
81
82
83
using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
84
85
struct hb_ft_font_t
86
{
87
  int load_flags;
88
  bool symbol; /* Whether selected cmap is symbol cmap. */
89
  bool unref; /* Whether to destroy ft_face when done. */
90
  bool transform; /* Whether to apply FT_Face's transform. */
91
92
  mutable hb_mutex_t lock; /* Protects members below. */
93
  FT_Face ft_face;
94
  mutable unsigned cached_serial;
95
  mutable hb_ft_advance_cache_t advance_cache;
96
};
97
98
static hb_ft_font_t *
99
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
100
6.12k
{
101
6.12k
  hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t));
102
6.12k
  if (unlikely (!ft_font)) return nullptr;
103
104
6.12k
  ft_font->lock.init ();
105
6.12k
  ft_font->ft_face = ft_face;
106
6.12k
  ft_font->symbol = symbol;
107
6.12k
  ft_font->unref = unref;
108
109
6.12k
  ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
110
111
6.12k
  ft_font->cached_serial = (unsigned) -1;
112
6.12k
  ft_font->advance_cache.init ();
113
114
6.12k
  return ft_font;
115
6.12k
}
116
117
static void
118
_hb_ft_face_destroy (void *data)
119
0
{
120
0
  FT_Done_Face ((FT_Face) data);
121
0
}
122
123
static void
124
_hb_ft_font_destroy (void *data)
125
6.12k
{
126
6.12k
  hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
127
128
6.12k
  ft_font->advance_cache.fini ();
129
130
6.12k
  if (ft_font->unref)
131
0
    _hb_ft_face_destroy (ft_font->ft_face);
132
133
6.12k
  ft_font->lock.fini ();
134
135
6.12k
  hb_free (ft_font);
136
6.12k
}
137
138
139
/* hb_font changed, update FT_Face. */
140
static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face)
141
0
{
142
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
143
144
0
  float x_mult = 1.f, y_mult = 1.f;
145
146
0
  if (font->x_scale < 0) x_mult = -x_mult;
147
0
  if (font->y_scale < 0) y_mult = -y_mult;
148
149
0
  if (FT_Set_Char_Size (ft_face,
150
0
      abs (font->x_scale), abs (font->y_scale),
151
0
      0, 0
152
#if 0
153
        font->x_ppem * 72 * 64 / font->x_scale,
154
        font->y_ppem * 72 * 64 / font->y_scale
155
#endif
156
0
     ) && ft_face->num_fixed_sizes)
157
0
  {
158
#ifdef HAVE_FT_GET_TRANSFORM
159
    /* Bitmap font, eg. bitmap color emoji. */
160
    /* TODO Pick largest size? */
161
    int x_scale  = ft_face->available_sizes[0].x_ppem;
162
    int y_scale = ft_face->available_sizes[0].y_ppem;
163
    FT_Set_Char_Size (ft_face,
164
          x_scale, y_scale,
165
          0, 0);
166
167
    /* This contains the sign that was previously in x_mult/y_mult. */
168
    x_mult = (float) font->x_scale / x_scale;
169
    y_mult = (float) font->y_scale / y_scale;
170
#endif
171
0
  }
172
0
  else
173
0
  { /* Shrug */ }
174
175
176
0
  if (x_mult != 1.f || y_mult != 1.f)
177
0
  {
178
0
    FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0,
179
0
        0, (int) roundf (y_mult * (1<<16))};
180
0
    FT_Set_Transform (ft_face, &matrix, nullptr);
181
0
    ft_font->transform = true;
182
0
  }
183
184
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
185
  unsigned int num_coords;
186
  const float *coords = hb_font_get_var_coords_design (font, &num_coords);
187
  if (num_coords)
188
  {
189
    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
190
    if (ft_coords)
191
    {
192
      for (unsigned int i = 0; i < num_coords; i++)
193
    ft_coords[i] = coords[i] * 65536.f;
194
      FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords);
195
      hb_free (ft_coords);
196
    }
197
  }
198
#endif
199
0
}
200
201
/* Check if hb_font changed, update FT_Face. */
202
static inline bool
203
_hb_ft_hb_font_check_changed (hb_font_t *font,
204
            const hb_ft_font_t *ft_font)
205
0
{
206
0
  if (font->serial != ft_font->cached_serial)
207
0
  {
208
0
    _hb_ft_hb_font_changed (font, ft_font->ft_face);
209
0
    ft_font->advance_cache.clear ();
210
0
    ft_font->cached_serial = font->serial;
211
0
    return true;
212
0
  }
213
0
  return false;
214
0
}
215
216
217
/**
218
 * hb_ft_font_set_load_flags:
219
 * @font: #hb_font_t to work upon
220
 * @load_flags: The FreeType load flags to set
221
 *
222
 * Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
223
 *
224
 * For more information, see 
225
 * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
226
 *
227
 * Since: 1.0.5
228
 **/
229
void
230
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
231
0
{
232
0
  if (hb_object_is_immutable (font))
233
0
    return;
234
235
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
236
0
    return;
237
238
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
239
240
0
  ft_font->load_flags = load_flags;
241
0
}
242
243
/**
244
 * hb_ft_font_get_load_flags:
245
 * @font: #hb_font_t to work upon
246
 *
247
 * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
248
 *
249
 * For more information, see 
250
 * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
251
 *
252
 * Return value: FT_Load_Glyph flags found
253
 *
254
 * Since: 1.0.5
255
 **/
256
int
257
hb_ft_font_get_load_flags (hb_font_t *font)
258
0
{
259
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
260
0
    return 0;
261
262
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
263
264
0
  return ft_font->load_flags;
265
0
}
266
267
/**
268
 * hb_ft_font_get_face: (skip)
269
 * @font: #hb_font_t to work upon
270
 *
271
 * Fetches the FT_Face associated with the specified #hb_font_t
272
 * font object.
273
 *
274
 * Return value: (nullable): the FT_Face found or `NULL`
275
 *
276
 * Since: 0.9.2
277
 **/
278
FT_Face
279
hb_ft_font_get_face (hb_font_t *font)
280
0
{
281
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
282
0
    return nullptr;
283
284
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
285
286
0
  return ft_font->ft_face;
287
0
}
288
289
/**
290
 * hb_ft_font_lock_face: (skip)
291
 * @font: #hb_font_t to work upon
292
 *
293
 * Gets the FT_Face associated with @font, This face will be kept around until
294
 * you call hb_ft_font_unlock_face().
295
 *
296
 * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL`
297
 * Since: 2.6.5
298
 **/
299
FT_Face
300
hb_ft_font_lock_face (hb_font_t *font)
301
0
{
302
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
303
0
    return nullptr;
304
305
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
306
307
0
  ft_font->lock.lock ();
308
309
0
  return ft_font->ft_face;
310
0
}
311
312
/**
313
 * hb_ft_font_unlock_face: (skip)
314
 * @font: #hb_font_t to work upon
315
 *
316
 * Releases an FT_Face previously obtained with hb_ft_font_lock_face().
317
 *
318
 * Since: 2.6.5
319
 **/
320
void
321
hb_ft_font_unlock_face (hb_font_t *font)
322
0
{
323
0
  if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
324
0
    return;
325
326
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
327
328
0
  ft_font->lock.unlock ();
329
0
}
330
331
332
static hb_bool_t
333
hb_ft_get_nominal_glyph (hb_font_t *font,
334
       void *font_data,
335
       hb_codepoint_t unicode,
336
       hb_codepoint_t *glyph,
337
       void *user_data HB_UNUSED)
338
80.8k
{
339
80.8k
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
340
80.8k
  hb_lock_t lock (ft_font->lock);
341
80.8k
  unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
342
343
80.8k
  if (unlikely (!g))
344
53.1k
  {
345
53.1k
    if (unlikely (ft_font->symbol))
346
0
    {
347
0
      switch ((unsigned) font->face->table.OS2->get_font_page ()) {
348
0
      case OT::OS2::font_page_t::FONT_PAGE_NONE:
349
0
  if (unicode <= 0x00FFu)
350
    /* For symbol-encoded OpenType fonts, we duplicate the
351
     * U+F000..F0FF range at U+0000..U+00FF.  That's what
352
     * Windows seems to do, and that's hinted about at:
353
     * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
354
     * under "Non-Standard (Symbol) Fonts". */
355
0
    g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
356
0
  break;
357
0
#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
358
0
      case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
359
0
  g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode));
360
0
  break;
361
0
      case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
362
0
  g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode));
363
0
  break;
364
0
#endif
365
0
      default:
366
0
  break;
367
0
      }
368
0
      if (!g)
369
0
  return false;
370
0
    }
371
53.1k
    else
372
53.1k
      return false;
373
53.1k
  }
374
375
27.6k
  *glyph = g;
376
27.6k
  return true;
377
80.8k
}
378
379
static unsigned int
380
hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
381
        void *font_data,
382
        unsigned int count,
383
        const hb_codepoint_t *first_unicode,
384
        unsigned int unicode_stride,
385
        hb_codepoint_t *first_glyph,
386
        unsigned int glyph_stride,
387
        void *user_data HB_UNUSED)
388
196k
{
389
196k
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
390
196k
  hb_lock_t lock (ft_font->lock);
391
196k
  unsigned int done;
392
196k
  for (done = 0;
393
415k
       done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
394
219k
       done++)
395
219k
  {
396
219k
    first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
397
219k
    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
398
219k
  }
399
  /* We don't need to do ft_font->symbol dance here, since HB calls the singular
400
   * nominal_glyph() for what we don't handle here. */
401
196k
  return done;
402
196k
}
403
404
405
static hb_bool_t
406
hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
407
         void *font_data,
408
         hb_codepoint_t unicode,
409
         hb_codepoint_t variation_selector,
410
         hb_codepoint_t *glyph,
411
         void *user_data HB_UNUSED)
412
0
{
413
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
414
0
  hb_lock_t lock (ft_font->lock);
415
0
  unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
416
417
0
  if (unlikely (!g))
418
0
    return false;
419
420
0
  *glyph = g;
421
0
  return true;
422
0
}
423
424
static void
425
hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
426
          unsigned count,
427
          const hb_codepoint_t *first_glyph,
428
          unsigned glyph_stride,
429
          hb_position_t *first_advance,
430
          unsigned advance_stride,
431
          void *user_data HB_UNUSED)
432
205k
{
433
205k
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
434
205k
  hb_lock_t lock (ft_font->lock);
435
205k
  FT_Face ft_face = ft_font->ft_face;
436
205k
  int load_flags = ft_font->load_flags;
437
205k
  float x_mult;
438
#ifdef HAVE_FT_GET_TRANSFORM
439
  if (ft_font->transform)
440
  {
441
    FT_Matrix matrix;
442
    FT_Get_Transform (ft_face, &matrix, nullptr);
443
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
444
  }
445
  else
446
#endif
447
205k
  {
448
205k
    x_mult = font->x_scale < 0 ? -1 : +1;
449
205k
  }
450
451
479k
  for (unsigned int i = 0; i < count; i++)
452
274k
  {
453
274k
    FT_Fixed v = 0;
454
274k
    hb_codepoint_t glyph = *first_glyph;
455
456
274k
    unsigned int cv;
457
274k
    if (ft_font->advance_cache.get (glyph, &cv))
458
177k
      v = cv;
459
96.6k
    else
460
96.6k
    {
461
96.6k
      FT_Get_Advance (ft_face, glyph, load_flags, &v);
462
96.6k
      ft_font->advance_cache.set (glyph, v);
463
96.6k
    }
464
465
274k
    *first_advance = (int) (v * x_mult + (1<<9)) >> 10;
466
274k
    first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
467
274k
    first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
468
274k
  }
469
205k
}
470
471
#ifndef HB_NO_VERTICAL
472
static hb_position_t
473
hb_ft_get_glyph_v_advance (hb_font_t *font,
474
         void *font_data,
475
         hb_codepoint_t glyph,
476
         void *user_data HB_UNUSED)
477
0
{
478
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
479
0
  hb_lock_t lock (ft_font->lock);
480
0
  FT_Fixed v;
481
0
  float y_mult;
482
#ifdef HAVE_FT_GET_TRANSFORM
483
  if (ft_font->transform)
484
  {
485
    FT_Matrix matrix;
486
    FT_Get_Transform (ft_font->ft_face, &matrix, nullptr);
487
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
488
  }
489
  else
490
#endif
491
0
  {
492
0
    y_mult = font->y_scale < 0 ? -1 : +1;
493
0
  }
494
495
0
  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
496
0
    return 0;
497
498
0
  v = (int) (y_mult * v);
499
500
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
501
   * have a Y growing upward.  Hence the extra negation. */
502
503
0
  return (-v + (1<<9)) >> 10;
504
0
}
505
#endif
506
507
#ifndef HB_NO_VERTICAL
508
static hb_bool_t
509
hb_ft_get_glyph_v_origin (hb_font_t *font,
510
        void *font_data,
511
        hb_codepoint_t glyph,
512
        hb_position_t *x,
513
        hb_position_t *y,
514
        void *user_data HB_UNUSED)
515
0
{
516
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
517
0
  hb_lock_t lock (ft_font->lock);
518
0
  FT_Face ft_face = ft_font->ft_face;
519
0
  float x_mult, y_mult;
520
#ifdef HAVE_FT_GET_TRANSFORM
521
  if (ft_font->transform)
522
  {
523
    FT_Matrix matrix;
524
    FT_Get_Transform (ft_face, &matrix, nullptr);
525
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
526
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
527
  }
528
  else
529
#endif
530
0
  {
531
0
    x_mult = font->x_scale < 0 ? -1 : +1;
532
0
    y_mult = font->y_scale < 0 ? -1 : +1;
533
0
  }
534
535
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
536
0
    return false;
537
538
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
539
   * have a Y growing upward.  Hence the extra negation. */
540
0
  *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
541
0
  *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
542
543
0
  *x = (hb_position_t) (x_mult * *x);
544
0
  *y = (hb_position_t) (y_mult * *y);
545
546
0
  return true;
547
0
}
548
#endif
549
550
#ifndef HB_NO_OT_SHAPE_FALLBACK
551
static hb_position_t
552
hb_ft_get_glyph_h_kerning (hb_font_t *font,
553
         void *font_data,
554
         hb_codepoint_t left_glyph,
555
         hb_codepoint_t right_glyph,
556
         void *user_data HB_UNUSED)
557
24.9k
{
558
24.9k
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
559
24.9k
  hb_lock_t lock (ft_font->lock);
560
24.9k
  FT_Vector kerningv;
561
562
24.9k
  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
563
24.9k
  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
564
0
    return 0;
565
566
24.9k
  return kerningv.x;
567
24.9k
}
568
#endif
569
570
static hb_bool_t
571
hb_ft_get_glyph_extents (hb_font_t *font,
572
       void *font_data,
573
       hb_codepoint_t glyph,
574
       hb_glyph_extents_t *extents,
575
       void *user_data HB_UNUSED)
576
20
{
577
20
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
578
20
  hb_lock_t lock (ft_font->lock);
579
20
  FT_Face ft_face = ft_font->ft_face;
580
20
  float x_mult, y_mult;
581
#ifdef HAVE_FT_GET_TRANSFORM
582
  if (ft_font->transform)
583
  {
584
    FT_Matrix matrix;
585
    FT_Get_Transform (ft_face, &matrix, nullptr);
586
    x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f;
587
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
588
  }
589
  else
590
#endif
591
20
  {
592
20
    x_mult = font->x_scale < 0 ? -1 : +1;
593
20
    y_mult = font->y_scale < 0 ? -1 : +1;
594
20
  }
595
596
20
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
597
0
    return false;
598
599
20
  extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX);
600
20
  extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY);
601
20
  extents->width  = (hb_position_t) (x_mult *  ft_face->glyph->metrics.width);
602
20
  extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height);
603
604
20
  return true;
605
20
}
606
607
static hb_bool_t
608
hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
609
             void *font_data,
610
             hb_codepoint_t glyph,
611
             unsigned int point_index,
612
             hb_position_t *x,
613
             hb_position_t *y,
614
             void *user_data HB_UNUSED)
615
0
{
616
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
617
0
  hb_lock_t lock (ft_font->lock);
618
0
  FT_Face ft_face = ft_font->ft_face;
619
620
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
621
0
      return false;
622
623
0
  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
624
0
      return false;
625
626
0
  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
627
0
      return false;
628
629
0
  *x = ft_face->glyph->outline.points[point_index].x;
630
0
  *y = ft_face->glyph->outline.points[point_index].y;
631
632
0
  return true;
633
0
}
634
635
static hb_bool_t
636
hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
637
          void *font_data,
638
          hb_codepoint_t glyph,
639
          char *name, unsigned int size,
640
          void *user_data HB_UNUSED)
641
0
{
642
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
643
0
  hb_lock_t lock (ft_font->lock);
644
0
  FT_Face ft_face = ft_font->ft_face;
645
646
0
  hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
647
0
  if (ret && (size && !*name))
648
0
    ret = false;
649
650
0
  return ret;
651
0
}
652
653
static hb_bool_t
654
hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
655
         void *font_data,
656
         const char *name, int len, /* -1 means nul-terminated */
657
         hb_codepoint_t *glyph,
658
         void *user_data HB_UNUSED)
659
0
{
660
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
661
0
  hb_lock_t lock (ft_font->lock);
662
0
  FT_Face ft_face = ft_font->ft_face;
663
664
0
  if (len < 0)
665
0
    *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
666
0
  else {
667
    /* Make a nul-terminated version. */
668
0
    char buf[128];
669
0
    len = hb_min (len, (int) sizeof (buf) - 1);
670
0
    strncpy (buf, name, len);
671
0
    buf[len] = '\0';
672
0
    *glyph = FT_Get_Name_Index (ft_face, buf);
673
0
  }
674
675
0
  if (*glyph == 0)
676
0
  {
677
    /* Check whether the given name was actually the name of glyph 0. */
678
0
    char buf[128];
679
0
    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
680
0
  len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
681
0
      return true;
682
0
  }
683
684
0
  return *glyph != 0;
685
0
}
686
687
static hb_bool_t
688
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
689
        void *font_data,
690
        hb_font_extents_t *metrics,
691
        void *user_data HB_UNUSED)
692
0
{
693
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
694
0
  hb_lock_t lock (ft_font->lock);
695
0
  FT_Face ft_face = ft_font->ft_face;
696
0
  float y_mult;
697
#ifdef HAVE_FT_GET_TRANSFORM
698
  if (ft_font->transform)
699
  {
700
    FT_Matrix matrix;
701
    FT_Get_Transform (ft_face, &matrix, nullptr);
702
    y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f;
703
  }
704
  else
705
#endif
706
0
  {
707
0
    y_mult = font->y_scale < 0 ? -1 : +1;
708
0
  }
709
710
0
  if (ft_face->units_per_EM != 0)
711
0
  {
712
0
    metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
713
0
    metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
714
0
    metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
715
0
  }
716
0
  else
717
0
  {
718
    /* Bitmap-only font, eg. color bitmap font. */
719
0
    metrics->ascender = ft_face->size->metrics.ascender;
720
0
    metrics->descender = ft_face->size->metrics.descender;
721
0
    metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
722
0
  }
723
724
0
  metrics->ascender  = (hb_position_t) (y_mult * metrics->ascender);
725
0
  metrics->descender = (hb_position_t) (y_mult * metrics->descender);
726
0
  metrics->line_gap  = (hb_position_t) (y_mult * metrics->line_gap);
727
728
0
  return true;
729
0
}
730
731
#ifndef HB_NO_DRAW
732
733
static int
734
_hb_ft_move_to (const FT_Vector *to,
735
    void *arg)
736
0
{
737
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
738
0
  drawing->move_to (to->x, to->y);
739
0
  return FT_Err_Ok;
740
0
}
741
742
static int
743
_hb_ft_line_to (const FT_Vector *to,
744
    void *arg)
745
0
{
746
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
747
0
  drawing->line_to (to->x, to->y);
748
0
  return FT_Err_Ok;
749
0
}
750
751
static int
752
_hb_ft_conic_to (const FT_Vector *control,
753
     const FT_Vector *to,
754
     void *arg)
755
0
{
756
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
757
0
  drawing->quadratic_to (control->x, control->y,
758
0
       to->x, to->y);
759
0
  return FT_Err_Ok;
760
0
}
761
762
static int
763
_hb_ft_cubic_to (const FT_Vector *control1,
764
     const FT_Vector *control2,
765
     const FT_Vector *to,
766
     void *arg)
767
0
{
768
0
  hb_draw_session_t *drawing = (hb_draw_session_t *) arg;
769
0
  drawing->cubic_to (control1->x, control1->y,
770
0
         control2->x, control2->y,
771
0
         to->x, to->y);
772
0
  return FT_Err_Ok;
773
0
}
774
775
static void
776
hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED,
777
           void *font_data,
778
           hb_codepoint_t glyph,
779
           hb_draw_funcs_t *draw_funcs, void *draw_data,
780
           void *user_data HB_UNUSED)
781
0
{
782
0
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
783
0
  hb_lock_t lock (ft_font->lock);
784
0
  FT_Face ft_face = ft_font->ft_face;
785
786
0
  if (unlikely (FT_Load_Glyph (ft_face, glyph,
787
0
             FT_LOAD_NO_BITMAP | ft_font->load_flags)))
788
0
    return;
789
790
0
  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
791
0
    return;
792
793
0
  const FT_Outline_Funcs outline_funcs = {
794
0
    _hb_ft_move_to,
795
0
    _hb_ft_line_to,
796
0
    _hb_ft_conic_to,
797
0
    _hb_ft_cubic_to,
798
0
    0, /* shift */
799
0
    0, /* delta */
800
0
  };
801
802
0
  hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
803
804
0
  FT_Outline_Decompose (&ft_face->glyph->outline,
805
0
      &outline_funcs,
806
0
      &draw_session);
807
0
}
808
#endif
809
810
811
static inline void free_static_ft_funcs ();
812
813
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
814
{
815
  static hb_font_funcs_t *create ()
816
1
  {
817
1
    hb_font_funcs_t *funcs = hb_font_funcs_create ();
818
819
1
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
820
1
    hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
821
1
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
822
823
1
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
824
1
    hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
825
    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
826
827
1
#ifndef HB_NO_VERTICAL
828
    //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
829
1
    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
830
1
    hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
831
1
#endif
832
833
1
#ifndef HB_NO_OT_SHAPE_FALLBACK
834
1
    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
835
1
#endif
836
    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
837
1
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
838
1
    hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
839
1
    hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
840
1
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
841
842
1
#ifndef HB_NO_DRAW
843
1
    hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr);
844
1
#endif
845
846
1
    hb_font_funcs_make_immutable (funcs);
847
848
1
    hb_atexit (free_static_ft_funcs);
849
850
1
    return funcs;
851
1
  }
852
} static_ft_funcs;
853
854
static inline
855
void free_static_ft_funcs ()
856
0
{
857
0
  static_ft_funcs.free_instance ();
858
0
}
859
860
static hb_font_funcs_t *
861
_hb_ft_get_font_funcs ()
862
6.12k
{
863
6.12k
  return static_ft_funcs.get_unconst ();
864
6.12k
}
865
866
static void
867
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
868
6.12k
{
869
6.12k
  bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
870
871
6.12k
  hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
872
6.12k
  if (unlikely (!ft_font)) return;
873
874
6.12k
  hb_font_set_funcs (font,
875
6.12k
         _hb_ft_get_font_funcs (),
876
6.12k
         ft_font,
877
6.12k
         _hb_ft_font_destroy);
878
6.12k
}
879
880
881
static hb_blob_t *
882
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
883
0
{
884
0
  FT_Face ft_face = (FT_Face) user_data;
885
0
  FT_Byte *buffer;
886
0
  FT_ULong  length = 0;
887
0
  FT_Error error;
888
889
  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
890
891
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
892
0
  if (error)
893
0
    return nullptr;
894
895
0
  buffer = (FT_Byte *) hb_malloc (length);
896
0
  if (!buffer)
897
0
    return nullptr;
898
899
0
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
900
0
  if (error)
901
0
  {
902
0
    hb_free (buffer);
903
0
    return nullptr;
904
0
  }
905
906
0
  return hb_blob_create ((const char *) buffer, length,
907
0
       HB_MEMORY_MODE_WRITABLE,
908
0
       buffer, hb_free);
909
0
}
910
911
/**
912
 * hb_ft_face_create:
913
 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
914
 * @destroy: (nullable): A callback to call when the face object is not needed anymore
915
 *
916
 * Creates an #hb_face_t face object from the specified FT_Face.
917
 *
918
 * This variant of the function does not provide any life-cycle management.
919
 *
920
 * Most client programs should use hb_ft_face_create_referenced()
921
 * (or, perhaps, hb_ft_face_create_cached()) instead. 
922
 *
923
 * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
924
 * then it is the client program's responsibility to destroy @ft_face 
925
 * after the #hb_face_t face object has been destroyed.
926
 *
927
 * Return value: (transfer full): the new #hb_face_t face object
928
 *
929
 * Since: 0.9.2
930
 **/
931
hb_face_t *
932
hb_ft_face_create (FT_Face           ft_face,
933
       hb_destroy_func_t destroy)
934
6.12k
{
935
6.12k
  hb_face_t *face;
936
937
6.12k
  if (!ft_face->stream->read) {
938
6.12k
    hb_blob_t *blob;
939
940
6.12k
    blob = hb_blob_create ((const char *) ft_face->stream->base,
941
6.12k
         (unsigned int) ft_face->stream->size,
942
6.12k
         HB_MEMORY_MODE_READONLY,
943
6.12k
         ft_face, destroy);
944
6.12k
    face = hb_face_create (blob, ft_face->face_index);
945
6.12k
    hb_blob_destroy (blob);
946
6.12k
  } else {
947
0
    face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
948
0
  }
949
950
6.12k
  hb_face_set_index (face, ft_face->face_index);
951
6.12k
  hb_face_set_upem (face, ft_face->units_per_EM);
952
953
6.12k
  return face;
954
6.12k
}
955
956
/**
957
 * hb_ft_face_create_referenced:
958
 * @ft_face: FT_Face to work upon
959
 *
960
 * Creates an #hb_face_t face object from the specified FT_Face.
961
 *
962
 * This is the preferred variant of the hb_ft_face_create*
963
 * function family, because it calls FT_Reference_Face() on @ft_face,
964
 * ensuring that @ft_face remains alive as long as the resulting
965
 * #hb_face_t face object remains alive. Also calls FT_Done_Face()
966
 * when the #hb_face_t face object is destroyed.
967
 *
968
 * Use this version unless you know you have good reasons not to.
969
 *
970
 * Return value: (transfer full): the new #hb_face_t face object
971
 *
972
 * Since: 0.9.38
973
 **/
974
hb_face_t *
975
hb_ft_face_create_referenced (FT_Face ft_face)
976
0
{
977
0
  FT_Reference_Face (ft_face);
978
0
  return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
979
0
}
980
981
static void
982
hb_ft_face_finalize (void *arg)
983
0
{
984
0
  FT_Face ft_face = (FT_Face) arg;
985
0
  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
986
0
}
987
988
/**
989
 * hb_ft_face_create_cached:
990
 * @ft_face: FT_Face to work upon
991
 *
992
 * Creates an #hb_face_t face object from the specified FT_Face.
993
 *
994
 * This variant of the function caches the newly created #hb_face_t
995
 * face object, using the @generic pointer of @ft_face. Subsequent function
996
 * calls that are passed the same @ft_face parameter will have the same
997
 * #hb_face_t returned to them, and that #hb_face_t will be correctly
998
 * reference counted.
999
 *
1000
 * However, client programs are still responsible for destroying
1001
 * @ft_face after the last #hb_face_t face object has been destroyed.
1002
 *
1003
 * Return value: (transfer full): the new #hb_face_t face object
1004
 *
1005
 * Since: 0.9.2
1006
 **/
1007
hb_face_t *
1008
hb_ft_face_create_cached (FT_Face ft_face)
1009
0
{
1010
0
  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
1011
0
  {
1012
0
    if (ft_face->generic.finalizer)
1013
0
      ft_face->generic.finalizer (ft_face);
1014
1015
0
    ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
1016
0
    ft_face->generic.finalizer = hb_ft_face_finalize;
1017
0
  }
1018
1019
0
  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
1020
0
}
1021
1022
/**
1023
 * hb_ft_font_create:
1024
 * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
1025
 * @destroy: (nullable): A callback to call when the font object is not needed anymore
1026
 *
1027
 * Creates an #hb_font_t font object from the specified FT_Face.
1028
 *
1029
 * <note>Note: You must set the face size on @ft_face before calling
1030
 * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
1031
 * access `size` member of FT_Face unconditionally.</note>
1032
 *
1033
 * This variant of the function does not provide any life-cycle management.
1034
 *
1035
 * Most client programs should use hb_ft_font_create_referenced()
1036
 * instead. 
1037
 *
1038
 * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
1039
 * then it is the client program's responsibility to destroy @ft_face 
1040
 * after the #hb_font_t font object has been destroyed.
1041
 *
1042
 * HarfBuzz will use the @destroy callback on the #hb_font_t font object 
1043
 * if it is supplied when you use this function. However, even if @destroy
1044
 * is provided, it is the client program's responsibility to destroy @ft_face,
1045
 * and it is the client program's responsibility to ensure that @ft_face is
1046
 * destroyed only after the #hb_font_t font object has been destroyed.
1047
 *
1048
 * Return value: (transfer full): the new #hb_font_t font object
1049
 *
1050
 * Since: 0.9.2
1051
 **/
1052
hb_font_t *
1053
hb_ft_font_create (FT_Face           ft_face,
1054
       hb_destroy_func_t destroy)
1055
6.12k
{
1056
6.12k
  hb_font_t *font;
1057
6.12k
  hb_face_t *face;
1058
1059
6.12k
  face = hb_ft_face_create (ft_face, destroy);
1060
6.12k
  font = hb_font_create (face);
1061
6.12k
  hb_face_destroy (face);
1062
6.12k
  _hb_ft_font_set_funcs (font, ft_face, false);
1063
6.12k
  hb_ft_font_changed (font);
1064
6.12k
  return font;
1065
6.12k
}
1066
1067
/**
1068
 * hb_ft_font_changed:
1069
 * @font: #hb_font_t to work upon
1070
 *
1071
 * Refreshes the state of @font when the underlying FT_Face has changed.
1072
 * This function should be called after changing the size or
1073
 * variation-axis settings on the FT_Face.
1074
 *
1075
 * Since: 1.0.5
1076
 **/
1077
void
1078
hb_ft_font_changed (hb_font_t *font)
1079
6.12k
{
1080
6.12k
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1081
0
    return;
1082
1083
6.12k
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1084
1085
6.12k
  FT_Face ft_face = ft_font->ft_face;
1086
1087
6.12k
  hb_font_set_scale (font,
1088
6.12k
         (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
1089
6.12k
         (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
1090
#if 0 /* hb-ft works in no-hinting model */
1091
  hb_font_set_ppem (font,
1092
        ft_face->size->metrics.x_ppem,
1093
        ft_face->size->metrics.y_ppem);
1094
#endif
1095
1096
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
1097
  FT_MM_Var *mm_var = nullptr;
1098
  if (!FT_Get_MM_Var (ft_face, &mm_var))
1099
  {
1100
    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
1101
    int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
1102
    if (coords && ft_coords)
1103
    {
1104
      if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
1105
      {
1106
  bool nonzero = false;
1107
1108
  for (unsigned int i = 0; i < mm_var->num_axis; ++i)
1109
   {
1110
    coords[i] = ft_coords[i] >>= 2;
1111
    nonzero = nonzero || coords[i];
1112
   }
1113
1114
  if (nonzero)
1115
    hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
1116
  else
1117
    hb_font_set_var_coords_normalized (font, nullptr, 0);
1118
      }
1119
    }
1120
    hb_free (coords);
1121
    hb_free (ft_coords);
1122
#ifdef HAVE_FT_DONE_MM_VAR
1123
    FT_Done_MM_Var (ft_face->glyph->library, mm_var);
1124
#else
1125
    hb_free (mm_var);
1126
#endif
1127
  }
1128
#endif
1129
1130
6.12k
  ft_font->advance_cache.clear ();
1131
6.12k
  ft_font->cached_serial = font->serial;
1132
6.12k
}
1133
1134
/**
1135
 * hb_ft_hb_font_changed:
1136
 * @font: #hb_font_t to work upon
1137
 *
1138
 * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
1139
 * @font has changed.
1140
 * This function should be called after changing the size or
1141
 * variation-axis settings on the @font.
1142
 * This call is fast if nothing has changed on @font.
1143
 *
1144
 * Return value: true if changed, false otherwise
1145
 *
1146
 * Since: 4.4.0
1147
 **/
1148
hb_bool_t
1149
hb_ft_hb_font_changed (hb_font_t *font)
1150
0
{
1151
0
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1152
0
    return false;
1153
1154
0
  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1155
1156
0
  return _hb_ft_hb_font_check_changed (font, ft_font);
1157
0
}
1158
1159
/**
1160
 * hb_ft_font_create_referenced:
1161
 * @ft_face: FT_Face to work upon
1162
 *
1163
 * Creates an #hb_font_t font object from the specified FT_Face.
1164
 *
1165
 * <note>Note: You must set the face size on @ft_face before calling
1166
 * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
1167
 * and will access `size` member of FT_Face unconditionally.</note>
1168
 *
1169
 * This is the preferred variant of the hb_ft_font_create*
1170
 * function family, because it calls FT_Reference_Face() on @ft_face,
1171
 * ensuring that @ft_face remains alive as long as the resulting
1172
 * #hb_font_t font object remains alive.
1173
 *
1174
 * Use this version unless you know you have good reasons not to.
1175
 *
1176
 * Return value: (transfer full): the new #hb_font_t font object
1177
 *
1178
 * Since: 0.9.38
1179
 **/
1180
hb_font_t *
1181
hb_ft_font_create_referenced (FT_Face ft_face)
1182
0
{
1183
0
  FT_Reference_Face (ft_face);
1184
0
  return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
1185
0
}
1186
1187
static inline void free_static_ft_library ();
1188
1189
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
1190
                   hb_ft_library_lazy_loader_t>
1191
{
1192
  static FT_Library create ()
1193
0
  {
1194
0
    FT_Library l;
1195
0
    if (FT_Init_FreeType (&l))
1196
0
      return nullptr;
1197
1198
0
    hb_atexit (free_static_ft_library);
1199
1200
0
    return l;
1201
0
  }
1202
  static void destroy (FT_Library l)
1203
0
  {
1204
0
    FT_Done_FreeType (l);
1205
0
  }
1206
  static FT_Library get_null ()
1207
0
  {
1208
0
    return nullptr;
1209
0
  }
1210
} static_ft_library;
1211
1212
static inline
1213
void free_static_ft_library ()
1214
0
{
1215
0
  static_ft_library.free_instance ();
1216
0
}
1217
1218
static FT_Library
1219
get_ft_library ()
1220
0
{
1221
0
  return static_ft_library.get_unconst ();
1222
0
}
1223
1224
static void
1225
_release_blob (void *arg)
1226
0
{
1227
0
  FT_Face ft_face = (FT_Face) arg;
1228
0
  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
1229
0
}
1230
1231
/**
1232
 * hb_ft_font_set_funcs:
1233
 * @font: #hb_font_t to work upon
1234
 *
1235
 * Configures the font-functions structure of the specified
1236
 * #hb_font_t font object to use FreeType font functions.
1237
 *
1238
 * In particular, you can use this function to configure an
1239
 * existing #hb_face_t face object for use with FreeType font
1240
 * functions even if that #hb_face_t face object was initially
1241
 * created with hb_face_create(), and therefore was not
1242
 * initially configured to use FreeType font functions.
1243
 *
1244
 * An #hb_face_t face object created with hb_ft_face_create()
1245
 * is preconfigured for FreeType font functions and does not
1246
 * require this function to be used.
1247
 *
1248
 * <note>Note: Internally, this function creates an FT_Face.
1249
* </note>
1250
 *
1251
 * Since: 1.0.5
1252
 **/
1253
void
1254
hb_ft_font_set_funcs (hb_font_t *font)
1255
0
{
1256
0
  hb_blob_t *blob = hb_face_reference_blob (font->face);
1257
0
  unsigned int blob_length;
1258
0
  const char *blob_data = hb_blob_get_data (blob, &blob_length);
1259
0
  if (unlikely (!blob_length))
1260
0
    DEBUG_MSG (FT, font, "Font face has empty blob");
1261
1262
0
  FT_Face ft_face = nullptr;
1263
0
  FT_Error err = FT_New_Memory_Face (get_ft_library (),
1264
0
             (const FT_Byte *) blob_data,
1265
0
             blob_length,
1266
0
             hb_face_get_index (font->face),
1267
0
             &ft_face);
1268
1269
0
  if (unlikely (err)) {
1270
0
    hb_blob_destroy (blob);
1271
0
    DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
1272
0
    return;
1273
0
  }
1274
1275
0
  if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
1276
0
    FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
1277
1278
1279
0
  ft_face->generic.data = blob;
1280
0
  ft_face->generic.finalizer = _release_blob;
1281
1282
0
  _hb_ft_font_set_funcs (font, ft_face, true);
1283
0
  hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
1284
1285
0
  _hb_ft_hb_font_changed (font, ft_face);
1286
0
}
1287
1288
1289
#endif