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