• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   FT_Long load_flags = ft_font->load_flags | FT_LOAD_NO_BITMAP | FT_LOAD_COLOR;
935 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21301
936   load_flags |= FT_LOAD_NO_SVG;
937 #endif
938 
939   /* We release the lock before calling into glyph callbacks, such that
940    * eg. draw API can call back into the face.*/
941 
942   if (unlikely (FT_Load_Glyph (ft_face, gid, load_flags)))
943     return;
944 
945   if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
946   {
947     if (hb_ft_paint_glyph_colr (font, font_data, gid,
948 				paint_funcs, paint_data,
949 				palette_index, foreground,
950 				user_data))
951       return;
952 
953     /* Simple outline. */
954     ft_font->lock.unlock ();
955     paint_funcs->push_clip_glyph (paint_data, gid, font);
956     ft_font->lock.lock ();
957     paint_funcs->color (paint_data, true, foreground);
958     paint_funcs->pop_clip (paint_data);
959 
960     return;
961   }
962 
963   auto *glyph = ft_face->glyph;
964   if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
965   {
966     auto &bitmap = glyph->bitmap;
967     if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
968     {
969       if (bitmap.pitch != (signed) bitmap.width * 4)
970         return;
971 
972       ft_font->lock.unlock ();
973 
974       hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer,
975 					bitmap.pitch * bitmap.rows,
976 					HB_MEMORY_MODE_DUPLICATE,
977 					nullptr, nullptr);
978 
979       hb_glyph_extents_t extents;
980       if (!hb_font_get_glyph_extents (font, gid, &extents))
981 	goto out;
982 
983       if (!paint_funcs->image (paint_data,
984 			       blob,
985 			       bitmap.width,
986 			       bitmap.rows,
987 			       HB_PAINT_IMAGE_FORMAT_BGRA,
988 			       font->slant_xy,
989 			       &extents))
990       {
991         /* TODO Try a forced outline load and paint? */
992       }
993 
994     out:
995       hb_blob_destroy (blob);
996       ft_font->lock.lock ();
997     }
998 
999     return;
1000   }
1001 }
1002 #endif
1003 #endif
1004 
1005 
1006 static inline void free_static_ft_funcs ();
1007 
1008 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
1009 {
createhb_ft_font_funcs_lazy_loader_t1010   static hb_font_funcs_t *create ()
1011   {
1012     hb_font_funcs_t *funcs = hb_font_funcs_create ();
1013 
1014     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
1015     hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
1016     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
1017 
1018     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
1019     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
1020     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
1021 
1022 #ifndef HB_NO_VERTICAL
1023     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
1024     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
1025     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
1026 #endif
1027 
1028 #ifndef HB_NO_OT_SHAPE_FALLBACK
1029     hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
1030 #endif
1031     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
1032     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
1033     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
1034     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
1035     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
1036 
1037 #ifndef HB_NO_DRAW
1038     hb_font_funcs_set_draw_glyph_func (funcs, hb_ft_draw_glyph, nullptr, nullptr);
1039 #endif
1040 
1041 #ifndef HB_NO_PAINT
1042 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
1043     hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr);
1044 #endif
1045 #endif
1046 
1047     hb_font_funcs_make_immutable (funcs);
1048 
1049     hb_atexit (free_static_ft_funcs);
1050 
1051     return funcs;
1052   }
1053 } static_ft_funcs;
1054 
1055 static inline
free_static_ft_funcs()1056 void free_static_ft_funcs ()
1057 {
1058   static_ft_funcs.free_instance ();
1059 }
1060 
1061 static hb_font_funcs_t *
_hb_ft_get_font_funcs()1062 _hb_ft_get_font_funcs ()
1063 {
1064   return static_ft_funcs.get_unconst ();
1065 }
1066 
1067 static void
_hb_ft_font_set_funcs(hb_font_t * font,FT_Face ft_face,bool unref)1068 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
1069 {
1070   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
1071 
1072   hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
1073   if (unlikely (!ft_font)) return;
1074 
1075   hb_font_set_funcs (font,
1076 		     _hb_ft_get_font_funcs (),
1077 		     ft_font,
1078 		     _hb_ft_font_destroy);
1079 }
1080 
1081 
1082 static hb_blob_t *
_hb_ft_reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)1083 _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
1084 {
1085   FT_Face ft_face = (FT_Face) user_data;
1086   FT_Byte *buffer;
1087   FT_ULong  length = 0;
1088   FT_Error error;
1089 
1090   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
1091 
1092   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
1093   if (error)
1094     return nullptr;
1095 
1096   buffer = (FT_Byte *) hb_malloc (length);
1097   if (!buffer)
1098     return nullptr;
1099 
1100   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
1101   if (error)
1102   {
1103     hb_free (buffer);
1104     return nullptr;
1105   }
1106 
1107   return hb_blob_create ((const char *) buffer, length,
1108 			 HB_MEMORY_MODE_WRITABLE,
1109 			 buffer, hb_free);
1110 }
1111 
1112 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)1113 _hb_ft_get_table_tags (const hb_face_t *face HB_UNUSED,
1114 		       unsigned int start_offset,
1115 		       unsigned int *table_count,
1116 		       hb_tag_t *table_tags,
1117 		       void *user_data)
1118 {
1119   FT_Face ft_face = (FT_Face) user_data;
1120 
1121   FT_ULong population = 0;
1122   FT_Sfnt_Table_Info (ft_face,
1123 		      0, // table_index; ignored
1124 		      nullptr,
1125                       &population);
1126 
1127   if (!table_count)
1128     return population;
1129   else
1130     *table_count = 0;
1131 
1132   if (unlikely (start_offset >= population))
1133     return population;
1134 
1135   unsigned end_offset = hb_min (start_offset + *table_count, (unsigned) population);
1136   if (unlikely (end_offset < start_offset))
1137     return population;
1138 
1139   *table_count = end_offset - start_offset;
1140   for (unsigned i = start_offset; i < end_offset; i++)
1141   {
1142     FT_ULong tag = 0, length;
1143     FT_Sfnt_Table_Info (ft_face, i, &tag, &length);
1144     table_tags[i - start_offset] = tag;
1145   }
1146 
1147   return population;
1148 }
1149 
1150 
1151 /**
1152  * hb_ft_face_create:
1153  * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
1154  * @destroy: (nullable): A callback to call when the face object is not needed anymore
1155  *
1156  * Creates an #hb_face_t face object from the specified FT_Face.
1157  *
1158  * Note that this is using the FT_Face object just to get at the underlying
1159  * font data, and fonts created from the returned #hb_face_t will use the native
1160  * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1161  *
1162  * This variant of the function does not provide any life-cycle management.
1163  *
1164  * Most client programs should use hb_ft_face_create_referenced()
1165  * (or, perhaps, hb_ft_face_create_cached()) instead.
1166  *
1167  * If you know you have valid reasons not to use hb_ft_face_create_referenced(),
1168  * then it is the client program's responsibility to destroy @ft_face
1169  * after the #hb_face_t face object has been destroyed.
1170  *
1171  * Return value: (transfer full): the new #hb_face_t face object
1172  *
1173  * Since: 0.9.2
1174  **/
1175 hb_face_t *
hb_ft_face_create(FT_Face ft_face,hb_destroy_func_t destroy)1176 hb_ft_face_create (FT_Face           ft_face,
1177 		   hb_destroy_func_t destroy)
1178 {
1179   hb_face_t *face;
1180 
1181   if (!ft_face->stream->read) {
1182     hb_blob_t *blob;
1183 
1184     blob = hb_blob_create ((const char *) ft_face->stream->base,
1185 			   (unsigned int) ft_face->stream->size,
1186 			   HB_MEMORY_MODE_READONLY,
1187 			   ft_face, destroy);
1188     face = hb_face_create (blob, ft_face->face_index);
1189     hb_blob_destroy (blob);
1190   } else {
1191     face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
1192     hb_face_set_get_table_tags_func (face, _hb_ft_get_table_tags, ft_face, nullptr);
1193   }
1194 
1195   hb_face_set_index (face, ft_face->face_index);
1196   hb_face_set_upem (face, ft_face->units_per_EM);
1197 
1198   return face;
1199 }
1200 
1201 /**
1202  * hb_ft_face_create_referenced:
1203  * @ft_face: FT_Face to work upon
1204  *
1205  * Creates an #hb_face_t face object from the specified FT_Face.
1206  *
1207  * Note that this is using the FT_Face object just to get at the underlying
1208  * font data, and fonts created from the returned #hb_face_t will use the native
1209  * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1210  *
1211  * This is the preferred variant of the hb_ft_face_create*
1212  * function family, because it calls FT_Reference_Face() on @ft_face,
1213  * ensuring that @ft_face remains alive as long as the resulting
1214  * #hb_face_t face object remains alive. Also calls FT_Done_Face()
1215  * when the #hb_face_t face object is destroyed.
1216  *
1217  * Use this version unless you know you have good reasons not to.
1218  *
1219  * Return value: (transfer full): the new #hb_face_t face object
1220  *
1221  * Since: 0.9.38
1222  **/
1223 hb_face_t *
hb_ft_face_create_referenced(FT_Face ft_face)1224 hb_ft_face_create_referenced (FT_Face ft_face)
1225 {
1226   FT_Reference_Face (ft_face);
1227   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
1228 }
1229 
1230 static void
hb_ft_face_finalize(void * arg)1231 hb_ft_face_finalize (void *arg)
1232 {
1233   FT_Face ft_face = (FT_Face) arg;
1234   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
1235 }
1236 
1237 /**
1238  * hb_ft_face_create_cached:
1239  * @ft_face: FT_Face to work upon
1240  *
1241  * Creates an #hb_face_t face object from the specified FT_Face.
1242  *
1243  * Note that this is using the FT_Face object just to get at the underlying
1244  * font data, and fonts created from the returned #hb_face_t will use the native
1245  * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them.
1246  *
1247  * This variant of the function caches the newly created #hb_face_t
1248  * face object, using the @generic pointer of @ft_face. Subsequent function
1249  * calls that are passed the same @ft_face parameter will have the same
1250  * #hb_face_t returned to them, and that #hb_face_t will be correctly
1251  * reference counted.
1252  *
1253  * However, client programs are still responsible for destroying
1254  * @ft_face after the last #hb_face_t face object has been destroyed.
1255  *
1256  * Return value: (transfer full): the new #hb_face_t face object
1257  *
1258  * Since: 0.9.2
1259  **/
1260 hb_face_t *
hb_ft_face_create_cached(FT_Face ft_face)1261 hb_ft_face_create_cached (FT_Face ft_face)
1262 {
1263   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
1264   {
1265     if (ft_face->generic.finalizer)
1266       ft_face->generic.finalizer (ft_face);
1267 
1268     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
1269     ft_face->generic.finalizer = hb_ft_face_finalize;
1270   }
1271 
1272   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
1273 }
1274 
1275 /**
1276  * hb_ft_font_create:
1277  * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
1278  * @destroy: (nullable): A callback to call when the font object is not needed anymore
1279  *
1280  * Creates an #hb_font_t font object from the specified FT_Face.
1281  *
1282  * <note>Note: You must set the face size on @ft_face before calling
1283  * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will
1284  * access `size` member of FT_Face unconditionally.</note>
1285  *
1286  * This variant of the function does not provide any life-cycle management.
1287  *
1288  * Most client programs should use hb_ft_font_create_referenced()
1289  * instead.
1290  *
1291  * If you know you have valid reasons not to use hb_ft_font_create_referenced(),
1292  * then it is the client program's responsibility to destroy @ft_face
1293  * after the #hb_font_t font object has been destroyed.
1294  *
1295  * HarfBuzz will use the @destroy callback on the #hb_font_t font object
1296  * if it is supplied when you use this function. However, even if @destroy
1297  * is provided, it is the client program's responsibility to destroy @ft_face,
1298  * and it is the client program's responsibility to ensure that @ft_face is
1299  * destroyed only after the #hb_font_t font object has been destroyed.
1300  *
1301  * Return value: (transfer full): the new #hb_font_t font object
1302  *
1303  * Since: 0.9.2
1304  **/
1305 hb_font_t *
hb_ft_font_create(FT_Face ft_face,hb_destroy_func_t destroy)1306 hb_ft_font_create (FT_Face           ft_face,
1307 		   hb_destroy_func_t destroy)
1308 {
1309   hb_font_t *font;
1310   hb_face_t *face;
1311 
1312   face = hb_ft_face_create (ft_face, destroy);
1313   font = hb_font_create (face);
1314   hb_face_destroy (face);
1315   _hb_ft_font_set_funcs (font, ft_face, false);
1316   hb_ft_font_changed (font);
1317   return font;
1318 }
1319 
1320 /**
1321  * hb_ft_font_changed:
1322  * @font: #hb_font_t to work upon
1323  *
1324  * Refreshes the state of @font when the underlying FT_Face has changed.
1325  * This function should be called after changing the size or
1326  * variation-axis settings on the FT_Face.
1327  *
1328  * Since: 1.0.5
1329  **/
1330 void
hb_ft_font_changed(hb_font_t * font)1331 hb_ft_font_changed (hb_font_t *font)
1332 {
1333   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1334     return;
1335 
1336   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1337 
1338   FT_Face ft_face = ft_font->ft_face;
1339 
1340   hb_font_set_scale (font,
1341 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
1342 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
1343 #if 0 /* hb-ft works in no-hinting model */
1344   hb_font_set_ppem (font,
1345 		    ft_face->size->metrics.x_ppem,
1346 		    ft_face->size->metrics.y_ppem);
1347 #endif
1348 
1349 #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
1350   FT_MM_Var *mm_var = nullptr;
1351   if (!FT_Get_MM_Var (ft_face, &mm_var))
1352   {
1353     FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
1354     int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
1355     if (coords && ft_coords)
1356     {
1357       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
1358       {
1359 	bool nonzero = false;
1360 
1361 	for (unsigned int i = 0; i < mm_var->num_axis; ++i)
1362 	 {
1363 	  coords[i] = ft_coords[i] >>= 2;
1364 	  nonzero = nonzero || coords[i];
1365 	 }
1366 
1367 	if (nonzero)
1368 	  hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
1369 	else
1370 	  hb_font_set_var_coords_normalized (font, nullptr, 0);
1371       }
1372     }
1373     hb_free (coords);
1374     hb_free (ft_coords);
1375 #ifdef HAVE_FT_DONE_MM_VAR
1376     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
1377 #else
1378     hb_free (mm_var);
1379 #endif
1380   }
1381 #endif
1382 
1383   ft_font->advance_cache.clear ();
1384   ft_font->cached_serial = font->serial;
1385 }
1386 
1387 /**
1388  * hb_ft_hb_font_changed:
1389  * @font: #hb_font_t to work upon
1390  *
1391  * Refreshes the state of the underlying FT_Face of @font when the hb_font_t
1392  * @font has changed.
1393  * This function should be called after changing the size or
1394  * variation-axis settings on the @font.
1395  * This call is fast if nothing has changed on @font.
1396  *
1397  * Return value: true if changed, false otherwise
1398  *
1399  * Since: 4.4.0
1400  **/
1401 hb_bool_t
hb_ft_hb_font_changed(hb_font_t * font)1402 hb_ft_hb_font_changed (hb_font_t *font)
1403 {
1404   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
1405     return false;
1406 
1407   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
1408 
1409   return _hb_ft_hb_font_check_changed (font, ft_font);
1410 }
1411 
1412 /**
1413  * hb_ft_font_create_referenced:
1414  * @ft_face: FT_Face to work upon
1415  *
1416  * Creates an #hb_font_t font object from the specified FT_Face.
1417  *
1418  * <note>Note: You must set the face size on @ft_face before calling
1419  * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set
1420  * and will access `size` member of FT_Face unconditionally.</note>
1421  *
1422  * This is the preferred variant of the hb_ft_font_create*
1423  * function family, because it calls FT_Reference_Face() on @ft_face,
1424  * ensuring that @ft_face remains alive as long as the resulting
1425  * #hb_font_t font object remains alive.
1426  *
1427  * Use this version unless you know you have good reasons not to.
1428  *
1429  * Return value: (transfer full): the new #hb_font_t font object
1430  *
1431  * Since: 0.9.38
1432  **/
1433 hb_font_t *
hb_ft_font_create_referenced(FT_Face ft_face)1434 hb_ft_font_create_referenced (FT_Face ft_face)
1435 {
1436   FT_Reference_Face (ft_face);
1437   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
1438 }
1439 
1440 
_hb_ft_alloc(FT_Memory memory,long size)1441 static void * _hb_ft_alloc (FT_Memory memory, long size)
1442 { return hb_malloc (size); }
1443 
_hb_ft_free(FT_Memory memory,void * block)1444 static void _hb_ft_free (FT_Memory memory, void *block)
1445 { hb_free (block); }
1446 
_hb_ft_realloc(FT_Memory memory,long cur_size,long new_size,void * block)1447 static void * _hb_ft_realloc (FT_Memory memory, long cur_size, long new_size, void *block)
1448 { return hb_realloc (block, new_size); }
1449 
1450 static FT_MemoryRec_ m =
1451 {
1452   nullptr,
1453   _hb_ft_alloc,
1454   _hb_ft_free,
1455   _hb_ft_realloc
1456 };
1457 
1458 static inline void free_static_ft_library ();
1459 
1460 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
1461 							     hb_ft_library_lazy_loader_t>
1462 {
createhb_ft_library_lazy_loader_t1463   static FT_Library create ()
1464   {
1465     FT_Library l;
1466     if (FT_New_Library (&m, &l))
1467       return nullptr;
1468 
1469     FT_Add_Default_Modules (l);
1470     FT_Set_Default_Properties (l);
1471 
1472     hb_atexit (free_static_ft_library);
1473 
1474     return l;
1475   }
destroyhb_ft_library_lazy_loader_t1476   static void destroy (FT_Library l)
1477   {
1478     FT_Done_Library (l);
1479   }
get_nullhb_ft_library_lazy_loader_t1480   static FT_Library get_null ()
1481   {
1482     return nullptr;
1483   }
1484 } static_ft_library;
1485 
1486 static inline
free_static_ft_library()1487 void free_static_ft_library ()
1488 {
1489   static_ft_library.free_instance ();
1490 }
1491 
1492 static FT_Library
reference_ft_library()1493 reference_ft_library ()
1494 {
1495   FT_Library l = static_ft_library.get_unconst ();
1496   if (unlikely (FT_Reference_Library (l)))
1497   {
1498     DEBUG_MSG (FT, l, "FT_Reference_Library() failed");
1499     return nullptr;
1500   }
1501   return l;
1502 }
1503 
1504 static hb_user_data_key_t ft_library_key = {0};
1505 
1506 static void
finalize_ft_library(void * arg)1507 finalize_ft_library (void *arg)
1508 {
1509   FT_Face ft_face = (FT_Face) arg;
1510   FT_Done_Library ((FT_Library) ft_face->generic.data);
1511 }
1512 
1513 static void
destroy_ft_library(void * arg)1514 destroy_ft_library (void *arg)
1515 {
1516   FT_Done_Library ((FT_Library) arg);
1517 }
1518 
1519 /**
1520  * hb_ft_face_create_from_file_or_fail:
1521  * @file_name: A font filename
1522  * @index: The index of the face within the file
1523  *
1524  * Creates an #hb_face_t face object from the specified
1525  * font file and face index.
1526  *
1527  * This is similar in functionality to hb_face_create_from_file_or_fail(),
1528  * but uses the FreeType library for loading the font file.
1529  *
1530  * Return value: (transfer full): The new face object, or `NULL` if
1531  * no face is found at the specified index or the file cannot be read.
1532  *
1533  * Since: 10.1.0
1534  */
1535 hb_face_t *
hb_ft_face_create_from_file_or_fail(const char * file_name,unsigned int index)1536 hb_ft_face_create_from_file_or_fail (const char   *file_name,
1537 				     unsigned int  index)
1538 {
1539   FT_Library ft_library = reference_ft_library ();
1540   if (unlikely (!ft_library))
1541   {
1542     DEBUG_MSG (FT, ft_library, "reference_ft_library failed");
1543     return nullptr;
1544   }
1545 
1546   FT_Face ft_face;
1547   if (unlikely (FT_New_Face (ft_library,
1548 			     file_name,
1549 			     index,
1550 			     &ft_face)))
1551     return nullptr;
1552 
1553   hb_face_t *face = hb_ft_face_create_referenced (ft_face);
1554   FT_Done_Face (ft_face);
1555 
1556   ft_face->generic.data = ft_library;
1557   ft_face->generic.finalizer = finalize_ft_library;
1558 
1559   if (hb_face_is_immutable (face))
1560     return nullptr;
1561 
1562   return face;
1563 }
1564 
1565 static void
_release_blob(void * arg)1566 _release_blob (void *arg)
1567 {
1568   FT_Face ft_face = (FT_Face) arg;
1569   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
1570 }
1571 
1572 /**
1573  * hb_ft_font_set_funcs:
1574  * @font: #hb_font_t to work upon
1575  *
1576  * Configures the font-functions structure of the specified
1577  * #hb_font_t font object to use FreeType font functions.
1578  *
1579  * In particular, you can use this function to configure an
1580  * existing #hb_face_t face object for use with FreeType font
1581  * functions even if that #hb_face_t face object was initially
1582  * created with hb_face_create(), and therefore was not
1583  * initially configured to use FreeType font functions.
1584  *
1585  * An #hb_font_t object created with hb_ft_font_create()
1586  * is preconfigured for FreeType font functions and does not
1587  * require this function to be used.
1588  *
1589  * Note that if you modify the underlying #hb_font_t after
1590  * calling this function, you need to call hb_ft_hb_font_changed()
1591  * to update the underlying FT_Face.
1592  *
1593  * <note>Note: Internally, this function creates an FT_Face.
1594 * </note>
1595  *
1596  * Since: 1.0.5
1597  **/
1598 void
hb_ft_font_set_funcs(hb_font_t * font)1599 hb_ft_font_set_funcs (hb_font_t *font)
1600 {
1601   hb_blob_t *blob = hb_face_reference_blob (font->face);
1602   unsigned int blob_length;
1603   const char *blob_data = hb_blob_get_data (blob, &blob_length);
1604   if (unlikely (!blob_length))
1605     DEBUG_MSG (FT, font, "Font face has empty blob");
1606 
1607   FT_Library ft_library = reference_ft_library ();
1608   if (unlikely (!ft_library))
1609   {
1610     hb_blob_destroy (blob);
1611     DEBUG_MSG (FT, font, "reference_ft_library failed");
1612     return;
1613   }
1614 
1615   FT_Face ft_face = nullptr;
1616   if (unlikely (FT_New_Memory_Face (ft_library,
1617 				    (const FT_Byte *) blob_data,
1618 				    blob_length,
1619 				    hb_face_get_index (font->face),
1620 				    &ft_face)))
1621   {
1622     hb_blob_destroy (blob);
1623     DEBUG_MSG (FT, font, "FT_New_Memory_Face() failed");
1624     return;
1625   }
1626 
1627   if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
1628     FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
1629 
1630   // Hook the blob to the FT_Face
1631   ft_face->generic.data = blob;
1632   ft_face->generic.finalizer = _release_blob;
1633 
1634   // And the FT_Library to the blob
1635   hb_blob_set_user_data (blob, &ft_library_key, ft_library, destroy_ft_library, true);
1636 
1637   _hb_ft_font_set_funcs (font, ft_face, true);
1638   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
1639 
1640   _hb_ft_hb_font_changed (font, ft_face);
1641 }
1642 
1643 #endif
1644