< prev index next >
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc
Print this page
*** 25,91 ****
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
! #include "hb-private.hh"
! #include "hb-debug.hh"
#include "hb-ft.h"
! #include "hb-font-private.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
- * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
- * Have not investigated.
- *
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
* would work fine. However, we also abuse this API for performing in font-space,
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
* for that, such that no rounding etc happens. As such, we don't set ppem, and
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
! * ourselves, like we do in uniscribe, etc.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
- *
- * - FT_Load_Glyph() is extremely costly. Do something about it?
*/
struct hb_ft_font_t
{
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
};
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font))
return nullptr;
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
return ft_font;
}
static void
_hb_ft_face_destroy (void *data)
--- 25,106 ----
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
! #include "hb.hh"
#include "hb-ft.h"
! #include "hb-font.hh"
! #include "hb-machinery.hh"
! #include "hb-cache.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
+ /**
+ * SECTION:hb-ft
+ * @title: hb-ft
+ * @short_description: FreeType integration
+ * @include: hb-ft.h
+ *
+ * Functions for using HarfBuzz with the FreeType library to provide face and
+ * font data.
+ **/
+
+
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
* would work fine. However, we also abuse this API for performing in font-space,
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
* for that, such that no rounding etc happens. As such, we don't set ppem, and
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
! * ourselves.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
*/
struct hb_ft_font_t
{
+ mutable hb_mutex_t lock;
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
+
+ mutable hb_atomic_int_t cached_x_scale;
+ mutable hb_advance_cache_t advance_cache;
};
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font))
return nullptr;
+ ft_font->lock.init ();
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+ ft_font->cached_x_scale.set (0);
+ ft_font->advance_cache.init ();
+
return ft_font;
}
static void
_hb_ft_face_destroy (void *data)
*** 96,108 ****
--- 111,127 ----
static void
_hb_ft_font_destroy (void *data)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
+ ft_font->advance_cache.fini ();
+
if (ft_font->unref)
_hb_ft_face_destroy (ft_font->ft_face);
+ ft_font->lock.fini ();
+
free (ft_font);
}
/**
* hb_ft_font_set_load_flags:
*** 114,124 ****
* Since: 1.0.5
**/
void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
! if (font->immutable)
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return;
--- 133,143 ----
* Since: 1.0.5
**/
void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
! if (hb_object_is_immutable (font))
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return;
*** 166,175 ****
--- 185,195 ----
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
{
if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
*** 189,241 ****
*glyph = g;
return true;
}
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
return false;
*glyph = g;
return true;
}
! static hb_position_t
! hb_ft_get_glyph_h_advance (hb_font_t *font,
! void *font_data,
! hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
! FT_Fixed v;
! if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
! return 0;
! if (font->x_scale < 0)
! v = -v;
! return (v + (1<<9)) >> 10;
}
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
--- 209,312 ----
*glyph = g;
return true;
}
+ 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)
+ {
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ unsigned int done;
+ for (done = 0;
+ done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
+ done++)
+ {
+ first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ }
+ /* We don't need to do ft_font->symbol dance here, since HB calls the singular
+ * nominal_glyph() for what we don't handle here. */
+ return done;
+ }
+
+
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
return false;
*glyph = g;
return true;
}
! 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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
! hb_lock_t lock (ft_font->lock);
! FT_Face ft_face = ft_font->ft_face;
! int load_flags = ft_font->load_flags;
! int mult = font->x_scale < 0 ? -1 : +1;
! if (font->x_scale != ft_font->cached_x_scale.get ())
! {
! ft_font->advance_cache.clear ();
! ft_font->cached_x_scale.set (font->x_scale);
! }
! for (unsigned int i = 0; i < count; i++)
! {
! FT_Fixed v = 0;
! hb_codepoint_t glyph = *first_glyph;
!
! unsigned int cv;
! if (ft_font->advance_cache.get (glyph, &cv))
! v = cv;
! else
! {
! FT_Get_Advance (ft_face, glyph, load_flags, &v);
! ft_font->advance_cache.set (glyph, v);
! }
! *first_advance = (v * mult + (1<<9)) >> 10;
! first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
! first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
! }
}
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
*** 254,263 ****
--- 325,335 ----
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
*** 272,306 ****
*y = -*y;
return true;
}
- 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)
- {
- const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
- FT_Vector kerningv;
-
- FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
- if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
- return 0;
-
- return kerningv.x;
- }
-
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
--- 344,362 ----
*y = -*y;
return true;
}
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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
*** 329,338 ****
--- 385,395 ----
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
*** 354,365 ****
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
! hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
return ret;
}
--- 411,424 ----
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
! hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
return ret;
}
*** 370,379 ****
--- 429,439 ----
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (len < 0)
*glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
else {
*** 402,480 ****
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
! metrics->ascender = ft_face->size->metrics.ascender;
! metrics->descender = ft_face->size->metrics.descender;
! metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
metrics->descender = -metrics->descender;
metrics->line_gap = -metrics->line_gap;
}
return true;
}
! static hb_font_funcs_t *static_ft_funcs = nullptr;
!
! #ifdef HB_USE_ATEXIT
! static
! void free_static_ft_funcs (void)
! {
! retry:
! hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
! if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr))
! goto retry;
!
! hb_font_funcs_destroy (ft_funcs);
! }
#endif
! static void
! _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
{
! retry:
! hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
!
! if (unlikely (!funcs))
{
! funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
! hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable (funcs);
! if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
! hb_font_funcs_destroy (funcs);
! goto retry;
}
! #ifdef HB_USE_ATEXIT
! atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
#endif
- };
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font,
! funcs,
_hb_ft_font_create (ft_face, symbol, unref),
_hb_ft_font_destroy);
}
--- 462,540 ----
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
! metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
! metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
! metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
metrics->descender = -metrics->descender;
metrics->line_gap = -metrics->line_gap;
}
return true;
}
! #if HB_USE_ATEXIT
! static void free_static_ft_funcs ();
#endif
! static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
! static hb_font_funcs_t *create ()
{
! hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
! hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable (funcs);
! #if HB_USE_ATEXIT
! atexit (free_static_ft_funcs);
! #endif
!
! return funcs;
}
+ } static_ft_funcs;
! #if HB_USE_ATEXIT
! static
! void free_static_ft_funcs ()
! {
! static_ft_funcs.free_instance ();
! }
#endif
+ static hb_font_funcs_t *
+ _hb_ft_get_font_funcs ()
+ {
+ return static_ft_funcs.get_unconst ();
+ }
+
+ static void
+ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+ {
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font,
! _hb_ft_get_font_funcs (),
_hb_ft_font_create (ft_face, symbol, unref),
_hb_ft_font_destroy);
}
*** 495,505 ****
buffer = (FT_Byte *) malloc (length);
if (!buffer)
return nullptr;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
! if (error) {
free (buffer);
return nullptr;
}
return hb_blob_create ((const char *) buffer, length,
--- 555,566 ----
buffer = (FT_Byte *) malloc (length);
if (!buffer)
return nullptr;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
! if (error)
! {
free (buffer);
return nullptr;
}
return hb_blob_create ((const char *) buffer, length,
*** 681,731 ****
{
FT_Reference_Face (ft_face);
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
! /* Thread-safe, lock-free, FT_Library */
!
! static FT_Library ft_library;
!
! #ifdef HB_USE_ATEXIT
! static
! void free_ft_library (void)
{
! retry:
! FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
! if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
! goto retry;
! FT_Done_FreeType (library);
! }
#endif
! static FT_Library
! get_ft_library (void)
! {
! retry:
! FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
!
! if (unlikely (!library))
{
- /* Not found; allocate one. */
- if (FT_Init_FreeType (&library))
return nullptr;
-
- if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
- FT_Done_FreeType (library);
- goto retry;
}
! #ifdef HB_USE_ATEXIT
! atexit (free_ft_library); /* First person registers atexit() callback. */
#endif
- }
! return library;
}
static void
_release_blob (FT_Face ft_face)
{
--- 742,792 ----
{
FT_Reference_Face (ft_face);
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
+ #if HB_USE_ATEXIT
+ static void free_static_ft_library ();
+ #endif
! static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
! hb_ft_library_lazy_loader_t>
{
! static FT_Library create ()
! {
! FT_Library l;
! if (FT_Init_FreeType (&l))
! return nullptr;
! #if HB_USE_ATEXIT
! atexit (free_static_ft_library);
#endif
! return l;
! }
! static void destroy (FT_Library l)
! {
! FT_Done_FreeType (l);
! }
! static FT_Library get_null ()
{
return nullptr;
}
+ } static_ft_library;
! #if HB_USE_ATEXIT
! static
! void free_static_ft_library ()
! {
! static_ft_library.free_instance ();
! }
#endif
! static FT_Library
! get_ft_library ()
! {
! return static_ft_library.get_unconst ();
}
static void
_release_blob (FT_Face ft_face)
{
< prev index next >