xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ft.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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