• 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 #include "hb-ft.h"
33 
34 #include "hb-font.hh"
35 #include "hb-machinery.hh"
36 #include "hb-cache.hh"
37 
38 #include FT_ADVANCES_H
39 #include FT_MULTIPLE_MASTERS_H
40 #include FT_TRUETYPE_TABLES_H
41 
42 
43 /**
44  * SECTION:hb-ft
45  * @title: hb-ft
46  * @short_description: FreeType integration
47  * @include: hb-ft.h
48  *
49  * Functions for using HarfBuzz with the FreeType library to provide face and
50  * font data.
51  **/
52 
53 
54 /* TODO:
55  *
56  * In general, this file does a fine job of what it's supposed to do.
57  * There are, however, things that need more work:
58  *
59  *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
60  *     would work fine.  However, we also abuse this API for performing in font-space,
61  *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
62  *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
63  *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
64  *     ourselves.
65  *
66  *   - We don't handle / allow for emboldening / obliqueing.
67  *
68  *   - In the future, we should add constructors to create fonts in font space?
69  */
70 
71 
72 struct hb_ft_font_t
73 {
74   mutable hb_mutex_t lock;
75   FT_Face ft_face;
76   int load_flags;
77   bool symbol; /* Whether selected cmap is symbol cmap. */
78   bool unref; /* Whether to destroy ft_face when done. */
79 
80   mutable hb_atomic_int_t cached_x_scale;
81   mutable hb_advance_cache_t advance_cache;
82 };
83 
84 static hb_ft_font_t *
_hb_ft_font_create(FT_Face ft_face,bool symbol,bool unref)85 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
86 {
87   hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
88 
89   if (unlikely (!ft_font))
90     return nullptr;
91 
92   ft_font->lock.init ();
93   ft_font->ft_face = ft_face;
94   ft_font->symbol = symbol;
95   ft_font->unref = unref;
96 
97   ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
98 
99   ft_font->cached_x_scale.set (0);
100   ft_font->advance_cache.init ();
101 
102   return ft_font;
103 }
104 
105 static void
_hb_ft_face_destroy(void * data)106 _hb_ft_face_destroy (void *data)
107 {
108   FT_Done_Face ((FT_Face) data);
109 }
110 
111 static void
_hb_ft_font_destroy(void * data)112 _hb_ft_font_destroy (void *data)
113 {
114   hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
115 
116   ft_font->advance_cache.fini ();
117 
118   if (ft_font->unref)
119     _hb_ft_face_destroy (ft_font->ft_face);
120 
121   ft_font->lock.fini ();
122 
123   free (ft_font);
124 }
125 
126 /**
127  * hb_ft_font_set_load_flags:
128  * @font:
129  * @load_flags:
130  *
131  *
132  *
133  * Since: 1.0.5
134  **/
135 void
hb_ft_font_set_load_flags(hb_font_t * font,int load_flags)136 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
137 {
138   if (hb_object_is_immutable (font))
139     return;
140 
141   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
142     return;
143 
144   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
145 
146   ft_font->load_flags = load_flags;
147 }
148 
149 /**
150  * hb_ft_font_get_load_flags:
151  * @font:
152  *
153  *
154  *
155  * Return value:
156  * Since: 1.0.5
157  **/
158 int
hb_ft_font_get_load_flags(hb_font_t * font)159 hb_ft_font_get_load_flags (hb_font_t *font)
160 {
161   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
162     return 0;
163 
164   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
165 
166   return ft_font->load_flags;
167 }
168 
169 FT_Face
hb_ft_font_get_face(hb_font_t * font)170 hb_ft_font_get_face (hb_font_t *font)
171 {
172   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
173     return nullptr;
174 
175   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
176 
177   return ft_font->ft_face;
178 }
179 
180 
181 
182 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)183 hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
184 			 void *font_data,
185 			 hb_codepoint_t unicode,
186 			 hb_codepoint_t *glyph,
187 			 void *user_data HB_UNUSED)
188 {
189   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
190   hb_lock_t lock (ft_font->lock);
191   unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
192 
193   if (unlikely (!g))
194   {
195     if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
196     {
197       /* For symbol-encoded OpenType fonts, we duplicate the
198        * U+F000..F0FF range at U+0000..U+00FF.  That's what
199        * Windows seems to do, and that's hinted about at:
200        * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
201        * under "Non-Standard (Symbol) Fonts". */
202       g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
203       if (!g)
204 	return false;
205     }
206     else
207       return false;
208   }
209 
210   *glyph = g;
211   return true;
212 }
213 
214 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)215 hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
216 			  void *font_data,
217 			  unsigned int count,
218 			  const hb_codepoint_t *first_unicode,
219 			  unsigned int unicode_stride,
220 			  hb_codepoint_t *first_glyph,
221 			  unsigned int glyph_stride,
222 			  void *user_data HB_UNUSED)
223 {
224   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
225   hb_lock_t lock (ft_font->lock);
226   unsigned int done;
227   for (done = 0;
228        done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
229        done++)
230   {
231     first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
232     first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
233   }
234   /* We don't need to do ft_font->symbol dance here, since HB calls the singular
235    * nominal_glyph() for what we don't handle here. */
236   return done;
237 }
238 
239 
240 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)241 hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
242 			   void *font_data,
243 			   hb_codepoint_t unicode,
244 			   hb_codepoint_t variation_selector,
245 			   hb_codepoint_t *glyph,
246 			   void *user_data HB_UNUSED)
247 {
248   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
249   hb_lock_t lock (ft_font->lock);
250   unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
251 
252   if (unlikely (!g))
253     return false;
254 
255   *glyph = g;
256   return true;
257 }
258 
259 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)260 hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
261 			    unsigned count,
262 			    const hb_codepoint_t *first_glyph,
263 			    unsigned glyph_stride,
264 			    hb_position_t *first_advance,
265 			    unsigned advance_stride,
266 			    void *user_data HB_UNUSED)
267 {
268   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
269   hb_lock_t lock (ft_font->lock);
270   FT_Face ft_face = ft_font->ft_face;
271   int load_flags = ft_font->load_flags;
272   int mult = font->x_scale < 0 ? -1 : +1;
273 
274   if (font->x_scale != ft_font->cached_x_scale.get ())
275   {
276     ft_font->advance_cache.clear ();
277     ft_font->cached_x_scale.set (font->x_scale);
278   }
279 
280   for (unsigned int i = 0; i < count; i++)
281   {
282     FT_Fixed v = 0;
283     hb_codepoint_t glyph = *first_glyph;
284 
285     unsigned int cv;
286     if (ft_font->advance_cache.get (glyph, &cv))
287       v = cv;
288     else
289     {
290       FT_Get_Advance (ft_face, glyph, load_flags, &v);
291       ft_font->advance_cache.set (glyph, v);
292     }
293 
294     *first_advance = (v * mult + (1<<9)) >> 10;
295     first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
296     first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
297   }
298 }
299 
300 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)301 hb_ft_get_glyph_v_advance (hb_font_t *font,
302 			   void *font_data,
303 			   hb_codepoint_t glyph,
304 			   void *user_data HB_UNUSED)
305 {
306   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
307   hb_lock_t lock (ft_font->lock);
308   FT_Fixed v;
309 
310   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
311     return 0;
312 
313   if (font->y_scale < 0)
314     v = -v;
315 
316   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
317    * have a Y growing upward.  Hence the extra negation. */
318   return (-v + (1<<9)) >> 10;
319 }
320 
321 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)322 hb_ft_get_glyph_v_origin (hb_font_t *font,
323 			  void *font_data,
324 			  hb_codepoint_t glyph,
325 			  hb_position_t *x,
326 			  hb_position_t *y,
327 			  void *user_data HB_UNUSED)
328 {
329   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
330   hb_lock_t lock (ft_font->lock);
331   FT_Face ft_face = ft_font->ft_face;
332 
333   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
334     return false;
335 
336   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
337    * have a Y growing upward.  Hence the extra negation. */
338   *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
339   *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
340 
341   if (font->x_scale < 0)
342     *x = -*x;
343   if (font->y_scale < 0)
344     *y = -*y;
345 
346   return true;
347 }
348 
349 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)350 hb_ft_get_glyph_extents (hb_font_t *font,
351 			 void *font_data,
352 			 hb_codepoint_t glyph,
353 			 hb_glyph_extents_t *extents,
354 			 void *user_data HB_UNUSED)
355 {
356   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
357   hb_lock_t lock (ft_font->lock);
358   FT_Face ft_face = ft_font->ft_face;
359 
360   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
361     return false;
362 
363   extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
364   extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
365   extents->width = ft_face->glyph->metrics.width;
366   extents->height = -ft_face->glyph->metrics.height;
367   if (font->x_scale < 0)
368   {
369     extents->x_bearing = -extents->x_bearing;
370     extents->width = -extents->width;
371   }
372   if (font->y_scale < 0)
373   {
374     extents->y_bearing = -extents->y_bearing;
375     extents->height = -extents->height;
376   }
377   return true;
378 }
379 
380 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)381 hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
382 			       void *font_data,
383 			       hb_codepoint_t glyph,
384 			       unsigned int point_index,
385 			       hb_position_t *x,
386 			       hb_position_t *y,
387 			       void *user_data HB_UNUSED)
388 {
389   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
390   hb_lock_t lock (ft_font->lock);
391   FT_Face ft_face = ft_font->ft_face;
392 
393   if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
394       return false;
395 
396   if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
397       return false;
398 
399   if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
400       return false;
401 
402   *x = ft_face->glyph->outline.points[point_index].x;
403   *y = ft_face->glyph->outline.points[point_index].y;
404 
405   return true;
406 }
407 
408 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)409 hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
410 		      void *font_data,
411 		      hb_codepoint_t glyph,
412 		      char *name, unsigned int size,
413 		      void *user_data HB_UNUSED)
414 {
415   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
416   hb_lock_t lock (ft_font->lock);
417   FT_Face ft_face = ft_font->ft_face;
418 
419   hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
420   if (ret && (size && !*name))
421     ret = false;
422 
423   return ret;
424 }
425 
426 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)427 hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
428 			   void *font_data,
429 			   const char *name, int len, /* -1 means nul-terminated */
430 			   hb_codepoint_t *glyph,
431 			   void *user_data HB_UNUSED)
432 {
433   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
434   hb_lock_t lock (ft_font->lock);
435   FT_Face ft_face = ft_font->ft_face;
436 
437   if (len < 0)
438     *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
439   else {
440     /* Make a nul-terminated version. */
441     char buf[128];
442     len = MIN (len, (int) sizeof (buf) - 1);
443     strncpy (buf, name, len);
444     buf[len] = '\0';
445     *glyph = FT_Get_Name_Index (ft_face, buf);
446   }
447 
448   if (*glyph == 0)
449   {
450     /* Check whether the given name was actually the name of glyph 0. */
451     char buf[128];
452     if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
453         len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
454       return true;
455   }
456 
457   return *glyph != 0;
458 }
459 
460 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)461 hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
462 			  void *font_data,
463 			  hb_font_extents_t *metrics,
464 			  void *user_data HB_UNUSED)
465 {
466   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
467   hb_lock_t lock (ft_font->lock);
468   FT_Face ft_face = ft_font->ft_face;
469   metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
470   metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
471   metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
472   if (font->y_scale < 0)
473   {
474     metrics->ascender = -metrics->ascender;
475     metrics->descender = -metrics->descender;
476     metrics->line_gap = -metrics->line_gap;
477   }
478   return true;
479 }
480 
481 #if HB_USE_ATEXIT
482 static void free_static_ft_funcs ();
483 #endif
484 
485 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
486 {
createhb_ft_font_funcs_lazy_loader_t487   static hb_font_funcs_t *create ()
488   {
489     hb_font_funcs_t *funcs = hb_font_funcs_create ();
490 
491     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
492     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
493     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
494     hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
495     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
496     hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
497     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
498     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
499     hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
500     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
501     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
502     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
503     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
504 
505     hb_font_funcs_make_immutable (funcs);
506 
507 #if HB_USE_ATEXIT
508     atexit (free_static_ft_funcs);
509 #endif
510 
511     return funcs;
512   }
513 } static_ft_funcs;
514 
515 #if HB_USE_ATEXIT
516 static
free_static_ft_funcs()517 void free_static_ft_funcs ()
518 {
519   static_ft_funcs.free_instance ();
520 }
521 #endif
522 
523 static hb_font_funcs_t *
_hb_ft_get_font_funcs()524 _hb_ft_get_font_funcs ()
525 {
526   return static_ft_funcs.get_unconst ();
527 }
528 
529 static void
_hb_ft_font_set_funcs(hb_font_t * font,FT_Face ft_face,bool unref)530 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
531 {
532   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
533 
534   hb_font_set_funcs (font,
535 		     _hb_ft_get_font_funcs (),
536 		     _hb_ft_font_create (ft_face, symbol, unref),
537 		     _hb_ft_font_destroy);
538 }
539 
540 
541 static hb_blob_t *
reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)542 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
543 {
544   FT_Face ft_face = (FT_Face) user_data;
545   FT_Byte *buffer;
546   FT_ULong  length = 0;
547   FT_Error error;
548 
549   /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
550 
551   error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
552   if (error)
553     return nullptr;
554 
555   buffer = (FT_Byte *) malloc (length);
556   if (!buffer)
557     return nullptr;
558 
559   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
560   if (error)
561   {
562     free (buffer);
563     return nullptr;
564   }
565 
566   return hb_blob_create ((const char *) buffer, length,
567 			 HB_MEMORY_MODE_WRITABLE,
568 			 buffer, free);
569 }
570 
571 /**
572  * hb_ft_face_create:
573  * @ft_face: (destroy destroy) (scope notified):
574  * @destroy:
575  *
576  *
577  *
578  * Return value: (transfer full):
579  * Since: 0.9.2
580  **/
581 hb_face_t *
hb_ft_face_create(FT_Face ft_face,hb_destroy_func_t destroy)582 hb_ft_face_create (FT_Face           ft_face,
583 		   hb_destroy_func_t destroy)
584 {
585   hb_face_t *face;
586 
587   if (!ft_face->stream->read) {
588     hb_blob_t *blob;
589 
590     blob = hb_blob_create ((const char *) ft_face->stream->base,
591 			   (unsigned int) ft_face->stream->size,
592 			   HB_MEMORY_MODE_READONLY,
593 			   ft_face, destroy);
594     face = hb_face_create (blob, ft_face->face_index);
595     hb_blob_destroy (blob);
596   } else {
597     face = hb_face_create_for_tables (reference_table, ft_face, destroy);
598   }
599 
600   hb_face_set_index (face, ft_face->face_index);
601   hb_face_set_upem (face, ft_face->units_per_EM);
602 
603   return face;
604 }
605 
606 /**
607  * hb_ft_face_create_referenced:
608  * @ft_face:
609  *
610  *
611  *
612  * Return value: (transfer full):
613  * Since: 0.9.38
614  **/
615 hb_face_t *
hb_ft_face_create_referenced(FT_Face ft_face)616 hb_ft_face_create_referenced (FT_Face ft_face)
617 {
618   FT_Reference_Face (ft_face);
619   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
620 }
621 
622 static void
hb_ft_face_finalize(FT_Face ft_face)623 hb_ft_face_finalize (FT_Face ft_face)
624 {
625   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
626 }
627 
628 /**
629  * hb_ft_face_create_cached:
630  * @ft_face:
631  *
632  *
633  *
634  * Return value: (transfer full):
635  * Since: 0.9.2
636  **/
637 hb_face_t *
hb_ft_face_create_cached(FT_Face ft_face)638 hb_ft_face_create_cached (FT_Face ft_face)
639 {
640   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
641   {
642     if (ft_face->generic.finalizer)
643       ft_face->generic.finalizer (ft_face);
644 
645     ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
646     ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
647   }
648 
649   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
650 }
651 
652 
653 /**
654  * hb_ft_font_create:
655  * @ft_face: (destroy destroy) (scope notified):
656  * @destroy:
657  *
658  *
659  *
660  * Return value: (transfer full):
661  * Since: 0.9.2
662  **/
663 hb_font_t *
hb_ft_font_create(FT_Face ft_face,hb_destroy_func_t destroy)664 hb_ft_font_create (FT_Face           ft_face,
665 		   hb_destroy_func_t destroy)
666 {
667   hb_font_t *font;
668   hb_face_t *face;
669 
670   face = hb_ft_face_create (ft_face, destroy);
671   font = hb_font_create (face);
672   hb_face_destroy (face);
673   _hb_ft_font_set_funcs (font, ft_face, false);
674   hb_ft_font_changed (font);
675   return font;
676 }
677 
678 void
hb_ft_font_changed(hb_font_t * font)679 hb_ft_font_changed (hb_font_t *font)
680 {
681   if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
682     return;
683 
684   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
685   FT_Face ft_face = ft_font->ft_face;
686 
687   hb_font_set_scale (font,
688 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
689 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
690 #if 0 /* hb-ft works in no-hinting model */
691   hb_font_set_ppem (font,
692 		    ft_face->size->metrics.x_ppem,
693 		    ft_face->size->metrics.y_ppem);
694 #endif
695 
696 #ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
697   FT_MM_Var *mm_var = nullptr;
698   if (!FT_Get_MM_Var (ft_face, &mm_var))
699   {
700     FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
701     int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
702     if (coords && ft_coords)
703     {
704       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
705       {
706 	bool nonzero = false;
707 
708 	for (unsigned int i = 0; i < mm_var->num_axis; ++i)
709 	 {
710 	  coords[i] = ft_coords[i] >>= 2;
711 	  nonzero = nonzero || coords[i];
712 	 }
713 
714 	if (nonzero)
715 	  hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
716 	else
717 	  hb_font_set_var_coords_normalized (font, nullptr, 0);
718       }
719     }
720     free (coords);
721     free (ft_coords);
722 #ifdef HAVE_FT_DONE_MM_VAR
723     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
724 #else
725     free (mm_var);
726 #endif
727   }
728 #endif
729 }
730 
731 /**
732  * hb_ft_font_create_referenced:
733  * @ft_face:
734  *
735  *
736  *
737  * Return value: (transfer full):
738  * Since: 0.9.38
739  **/
740 hb_font_t *
hb_ft_font_create_referenced(FT_Face ft_face)741 hb_ft_font_create_referenced (FT_Face ft_face)
742 {
743   FT_Reference_Face (ft_face);
744   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
745 }
746 
747 #if HB_USE_ATEXIT
748 static void free_static_ft_library ();
749 #endif
750 
751 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
752 							     hb_ft_library_lazy_loader_t>
753 {
createhb_ft_library_lazy_loader_t754   static FT_Library create ()
755   {
756     FT_Library l;
757     if (FT_Init_FreeType (&l))
758       return nullptr;
759 
760 #if HB_USE_ATEXIT
761     atexit (free_static_ft_library);
762 #endif
763 
764     return l;
765   }
destroyhb_ft_library_lazy_loader_t766   static void destroy (FT_Library l)
767   {
768     FT_Done_FreeType (l);
769   }
get_nullhb_ft_library_lazy_loader_t770   static FT_Library get_null ()
771   {
772     return nullptr;
773   }
774 } static_ft_library;
775 
776 #if HB_USE_ATEXIT
777 static
free_static_ft_library()778 void free_static_ft_library ()
779 {
780   static_ft_library.free_instance ();
781 }
782 #endif
783 
784 static FT_Library
get_ft_library()785 get_ft_library ()
786 {
787   return static_ft_library.get_unconst ();
788 }
789 
790 static void
_release_blob(FT_Face ft_face)791 _release_blob (FT_Face ft_face)
792 {
793   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
794 }
795 
796 void
hb_ft_font_set_funcs(hb_font_t * font)797 hb_ft_font_set_funcs (hb_font_t *font)
798 {
799   hb_blob_t *blob = hb_face_reference_blob (font->face);
800   unsigned int blob_length;
801   const char *blob_data = hb_blob_get_data (blob, &blob_length);
802   if (unlikely (!blob_length))
803     DEBUG_MSG (FT, font, "Font face has empty blob");
804 
805   FT_Face ft_face = nullptr;
806   FT_Error err = FT_New_Memory_Face (get_ft_library (),
807 				     (const FT_Byte *) blob_data,
808 				     blob_length,
809 				     hb_face_get_index (font->face),
810 				     &ft_face);
811 
812   if (unlikely (err)) {
813     hb_blob_destroy (blob);
814     DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
815     return;
816   }
817 
818   if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
819     FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
820 
821   FT_Set_Char_Size (ft_face,
822 		    abs (font->x_scale), abs (font->y_scale),
823 		    0, 0);
824 #if 0
825 		    font->x_ppem * 72 * 64 / font->x_scale,
826 		    font->y_ppem * 72 * 64 / font->y_scale);
827 #endif
828   if (font->x_scale < 0 || font->y_scale < 0)
829   {
830     FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
831 			  0, font->y_scale < 0 ? -1 : +1};
832     FT_Set_Transform (ft_face, &matrix, nullptr);
833   }
834 
835 #ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
836   unsigned int num_coords;
837   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
838   if (num_coords)
839   {
840     FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
841     if (ft_coords)
842     {
843       for (unsigned int i = 0; i < num_coords; i++)
844 	ft_coords[i] = coords[i] << 2;
845       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
846       free (ft_coords);
847     }
848   }
849 #endif
850 
851   ft_face->generic.data = blob;
852   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
853 
854   _hb_ft_font_set_funcs (font, ft_face, true);
855   hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
856 }
857