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