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