Merge branch 'master' into cff-subset
This commit is contained in:
commit
25b8310b2a
18
NEWS
18
NEWS
|
@ -1,3 +1,21 @@
|
|||
Overview of changes leading to 1.8.8
|
||||
Tuesday, August 14, 2018
|
||||
====================================
|
||||
- Fix hb-icu crash on architectures where compare_exchange_weak() can
|
||||
fail falsely. This bug was introduced in 1.8.4.
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=873568
|
||||
- More internal refactoring of atomic operations and singletons.
|
||||
- API changes:
|
||||
The following functions do NOT reference their return value before
|
||||
returning:
|
||||
* hb_unicode_funcs_get_default()
|
||||
* hb_glib_get_unicode_funcs()
|
||||
* hb_icu_get_unicode_funcs()
|
||||
This is consistent with their naming ("get", instead of "reference")
|
||||
as well as how they are used in the wild (ie. no one calls destroy()
|
||||
on their return value.)
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.7
|
||||
Wednesday, August 8, 2018
|
||||
====================================
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[1.8.7],
|
||||
[1.8.8],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
|
|
@ -216,7 +216,7 @@ hb_buffer_t::reset (void)
|
|||
return;
|
||||
|
||||
hb_unicode_funcs_destroy (unicode);
|
||||
unicode = hb_unicode_funcs_get_default ();
|
||||
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
|
||||
flags = HB_BUFFER_FLAG_DEFAULT;
|
||||
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
|
||||
|
||||
|
@ -908,7 +908,6 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
|
|||
if (!unicode_funcs)
|
||||
unicode_funcs = hb_unicode_funcs_get_default ();
|
||||
|
||||
|
||||
hb_unicode_funcs_reference (unicode_funcs);
|
||||
hb_unicode_funcs_destroy (buffer->unicode);
|
||||
buffer->unicode = unicode_funcs;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
|
@ -730,47 +731,47 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
|
|||
|
||||
#ifdef USE_XLOCALE
|
||||
|
||||
static hb_atomic_ptr_t<HB_LOCALE_T> C_locale;
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void free_static_C_locale (void);
|
||||
#endif
|
||||
|
||||
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value,
|
||||
hb_C_locale_lazy_loader_t>
|
||||
{
|
||||
static inline HB_LOCALE_T create (void)
|
||||
{
|
||||
HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void
|
||||
free_C_locale (void)
|
||||
atexit (free_static_C_locale);
|
||||
#endif
|
||||
|
||||
return C_locale;
|
||||
}
|
||||
static inline void destroy (HB_LOCALE_T p)
|
||||
{
|
||||
HB_FREE_LOCALE (p);
|
||||
}
|
||||
static inline HB_LOCALE_T get_null (void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_C_locale;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_C_locale (void)
|
||||
{
|
||||
retry:
|
||||
HB_LOCALE_T locale = C_locale.get ();
|
||||
|
||||
if (unlikely (!C_locale.cmpexch (locale, nullptr)))
|
||||
goto retry;
|
||||
|
||||
if (locale)
|
||||
HB_FREE_LOCALE (locale);
|
||||
static_C_locale.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static HB_LOCALE_T
|
||||
get_C_locale (void)
|
||||
{
|
||||
retry:
|
||||
HB_LOCALE_T C = C_locale.get ();
|
||||
|
||||
if (unlikely (!C))
|
||||
{
|
||||
C = HB_CREATE_LOCALE ("C");
|
||||
|
||||
if (unlikely (!C_locale.cmpexch (nullptr, C)))
|
||||
{
|
||||
HB_FREE_LOCALE (C);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_C_locale); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return C;
|
||||
return static_C_locale.get_unconst ();
|
||||
}
|
||||
#endif
|
||||
#endif /* USE_XLOCALE */
|
||||
|
||||
static bool
|
||||
parse_float (const char **pp, const char *end, float *pv)
|
||||
|
@ -847,7 +848,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
|
|||
}
|
||||
|
||||
const char *p = *pp;
|
||||
while (*pp < end && ISALNUM(**pp))
|
||||
while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
|
||||
(*pp)++;
|
||||
|
||||
if (p == *pp || *pp - p > 4)
|
||||
|
|
113
src/hb-ft.cc
113
src/hb-ft.cc
|
@ -32,6 +32,7 @@
|
|||
#include "hb-ft.h"
|
||||
|
||||
#include "hb-font-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
#include FT_ADVANCES_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
|
@ -416,30 +417,15 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
|
|||
return true;
|
||||
}
|
||||
|
||||
static hb_atomic_ptr_t<hb_font_funcs_t> static_ft_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_ft_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_font_funcs_t *ft_funcs = static_ft_funcs.get ();
|
||||
if (unlikely (!static_ft_funcs.cmpexch (ft_funcs, nullptr)))
|
||||
goto retry;
|
||||
|
||||
hb_font_funcs_destroy (ft_funcs);
|
||||
}
|
||||
static void free_static_ft_funcs (void);
|
||||
#endif
|
||||
|
||||
static void
|
||||
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
|
||||
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
|
||||
{
|
||||
retry:
|
||||
hb_font_funcs_t *funcs = static_ft_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
static inline hb_font_funcs_t *create (void)
|
||||
{
|
||||
funcs = hb_font_funcs_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);
|
||||
|
@ -458,21 +444,35 @@ retry:
|
|||
|
||||
hb_font_funcs_make_immutable (funcs);
|
||||
|
||||
if (unlikely (!static_ft_funcs. cmpexch (nullptr, funcs)))
|
||||
{
|
||||
hb_font_funcs_destroy (funcs);
|
||||
goto retry;
|
||||
}
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ft_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_ft_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
|
||||
static
|
||||
void free_static_ft_funcs (void)
|
||||
{
|
||||
static_ft_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static hb_font_funcs_t *
|
||||
_hb_ft_get_font_funcs (void)
|
||||
{
|
||||
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,
|
||||
funcs,
|
||||
_hb_ft_get_font_funcs (),
|
||||
_hb_ft_font_create (ft_face, symbol, unref),
|
||||
_hb_ft_font_destroy);
|
||||
}
|
||||
|
@ -684,48 +684,47 @@ hb_ft_font_create_referenced (FT_Face ft_face)
|
|||
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void free_static_ft_library (void);
|
||||
#endif
|
||||
|
||||
/* Thread-safe, lock-free, FT_Library */
|
||||
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value,
|
||||
hb_ft_library_lazy_loader_t>
|
||||
{
|
||||
static inline FT_Library create (void)
|
||||
{
|
||||
FT_Library l;
|
||||
if (FT_Init_FreeType (&l))
|
||||
return nullptr;
|
||||
|
||||
static hb_atomic_ptr_t<FT_Library> ft_library;
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ft_library);
|
||||
#endif
|
||||
|
||||
return l;
|
||||
}
|
||||
static inline void destroy (FT_Library l)
|
||||
{
|
||||
FT_Done_FreeType (l);
|
||||
}
|
||||
static inline FT_Library get_null (void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_ft_library;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_ft_library (void)
|
||||
void free_static_ft_library (void)
|
||||
{
|
||||
retry:
|
||||
FT_Library library = ft_library.get ();
|
||||
if (unlikely (!ft_library.cmpexch (library, nullptr)))
|
||||
goto retry;
|
||||
|
||||
FT_Done_FreeType (library);
|
||||
static_ft_library.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static FT_Library
|
||||
get_ft_library (void)
|
||||
{
|
||||
retry:
|
||||
FT_Library library = ft_library.get ();
|
||||
|
||||
if (unlikely (!library))
|
||||
{
|
||||
/* Not found; allocate one. */
|
||||
if (FT_Init_FreeType (&library))
|
||||
return nullptr;
|
||||
|
||||
if (unlikely (!ft_library.cmpexch (nullptr, library)))
|
||||
{
|
||||
FT_Done_FreeType (library);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_ft_library); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return library;
|
||||
return static_ft_library.get_unconst ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hb-glib.h"
|
||||
|
||||
#include "hb-unicode-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,29,14)
|
||||
|
@ -364,30 +365,16 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
return utf8_decomposed_len;
|
||||
}
|
||||
|
||||
static hb_atomic_ptr_t<hb_unicode_funcs_t> static_glib_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_glib_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *glib_funcs = static_glib_funcs.get ();
|
||||
if (unlikely (!static_glib_funcs.cmpexch (glib_funcs, nullptr)))
|
||||
goto retry;
|
||||
|
||||
hb_unicode_funcs_destroy (glib_funcs);
|
||||
}
|
||||
static void free_static_glib_funcs (void);
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_glib_get_unicode_funcs (void)
|
||||
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *funcs = static_glib_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
static inline hb_unicode_funcs_t *create (void)
|
||||
{
|
||||
funcs = hb_unicode_funcs_create (nullptr);
|
||||
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
|
||||
hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
|
||||
|
@ -396,19 +383,29 @@ retry:
|
|||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
if (unlikely (!static_glib_funcs.cmpexch (nullptr, funcs)))
|
||||
{
|
||||
hb_unicode_funcs_destroy (funcs);
|
||||
goto retry;
|
||||
}
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_glib_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_glib_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_glib_funcs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
};
|
||||
|
||||
return hb_unicode_funcs_reference (funcs);
|
||||
static
|
||||
void free_static_glib_funcs (void)
|
||||
{
|
||||
static_glib_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_glib_get_unicode_funcs (void)
|
||||
{
|
||||
return static_glib_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,31,10)
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "hb-icu.h"
|
||||
|
||||
#include "hb-unicode-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/unorm2.h>
|
||||
|
@ -164,10 +165,6 @@ hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
return hb_icu_script_to_script (scriptCode);
|
||||
}
|
||||
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
static hb_atomic_ptr_t <const UNormalizer2> normalizer;
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t a,
|
||||
|
@ -177,7 +174,8 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
{
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
{
|
||||
UChar32 ret = unorm2_composePair (normalizer.get (), a, b);
|
||||
const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
|
||||
UChar32 ret = unorm2_composePair (normalizer, a, b);
|
||||
if (ret < 0) return false;
|
||||
*ab = ret;
|
||||
return true;
|
||||
|
@ -222,10 +220,11 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
{
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
{
|
||||
const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
|
||||
UChar decomposed[4];
|
||||
int len;
|
||||
UErrorCode icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_getRawDecomposition (normalizer.get (), ab, decomposed,
|
||||
len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
|
||||
ARRAY_LENGTH (decomposed), &icu_err);
|
||||
if (U_FAILURE (icu_err) || len < 0) return false;
|
||||
|
||||
|
@ -344,58 +343,48 @@ hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
return utf32_len;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void free_static_icu_funcs (void);
|
||||
#endif
|
||||
|
||||
static hb_atomic_ptr_t<hb_unicode_funcs_t> static_icu_funcs;
|
||||
static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
|
||||
{
|
||||
static inline hb_unicode_funcs_t *create (void)
|
||||
{
|
||||
void *user_data = nullptr;
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
UErrorCode icu_err = U_ZERO_ERROR;
|
||||
user_data = (void *) unorm2_getNFCInstance (&icu_err);
|
||||
assert (user_data);
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
|
||||
hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, user_data, nullptr);
|
||||
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_UNICODE_FUNC_IMPLEMENT
|
||||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_icu_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_icu_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_icu_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *icu_funcs = static_icu_funcs.get ();
|
||||
if (unlikely (!static_icu_funcs.cmpexch (icu_funcs, nullptr)))
|
||||
goto retry;
|
||||
|
||||
hb_unicode_funcs_destroy (icu_funcs);
|
||||
static_icu_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_icu_get_unicode_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *funcs = static_icu_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
{
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
if (!normalizer.get ())
|
||||
{
|
||||
UErrorCode icu_err = U_ZERO_ERROR;
|
||||
/* We ignore failure in getNFCInstace(). */
|
||||
(void) normalizer.cmpexch (nullptr, unorm2_getNFCInstance (&icu_err));
|
||||
}
|
||||
#endif
|
||||
|
||||
funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
|
||||
hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, nullptr, nullptr);
|
||||
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_UNICODE_FUNC_IMPLEMENT
|
||||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
if (unlikely (!static_icu_funcs.cmpexch (nullptr, funcs)))
|
||||
{
|
||||
hb_unicode_funcs_destroy (funcs);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_icu_funcs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
};
|
||||
|
||||
return hb_unicode_funcs_reference (funcs);
|
||||
return static_icu_funcs.get_unconst ();
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ struct Iter<T *>
|
|||
array (array_), length (length_) {}
|
||||
|
||||
/* Emptiness. */
|
||||
inline operator bool (void) const { return bool (length); }
|
||||
explicit_operator inline operator bool (void) const { return bool (length); }
|
||||
|
||||
/* Current item. */
|
||||
inline T &operator * (void)
|
||||
|
|
|
@ -590,32 +590,82 @@ struct BEInt<Type, 4>
|
|||
* Lazy loaders.
|
||||
*/
|
||||
|
||||
template <unsigned int WheresFace,
|
||||
typename Subclass,
|
||||
typename Returned,
|
||||
typename Stored = Returned>
|
||||
struct hb_lazy_loader_t
|
||||
template <typename Data, unsigned int WheresData>
|
||||
struct hb_data_wrapper_t
|
||||
{
|
||||
static_assert (WheresFace > 0, "");
|
||||
static_assert (WheresData > 0, "");
|
||||
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); }
|
||||
inline Subclass* thiz (void) { return static_cast<Subclass *> (this); }
|
||||
inline Data * get_data (void) const
|
||||
{
|
||||
return *(((Data **) (void *) this) - WheresData);
|
||||
}
|
||||
|
||||
template <typename Stored, typename Subclass>
|
||||
inline Stored * call_create (void) const
|
||||
{
|
||||
Data *data = this->get_data ();
|
||||
return likely (data) ? Subclass::create (data) : nullptr;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct hb_data_wrapper_t<void, 0>
|
||||
{
|
||||
template <typename Stored, typename Funcs>
|
||||
inline Stored * call_create (void) const
|
||||
{
|
||||
return Funcs::create ();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; };
|
||||
template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; };
|
||||
|
||||
template <typename Returned,
|
||||
typename Subclass = void,
|
||||
typename Data = void,
|
||||
unsigned int WheresData = 0,
|
||||
typename Stored = Returned>
|
||||
struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
||||
{
|
||||
typedef typename hb_non_void_t<Subclass,
|
||||
hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
|
||||
>::value Funcs;
|
||||
|
||||
inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
|
||||
inline void init (void)
|
||||
{
|
||||
instance.set_relaxed (nullptr);
|
||||
}
|
||||
inline void init (void) { instance.set_relaxed (nullptr); }
|
||||
inline void fini (void)
|
||||
{
|
||||
Stored *p = this->instance.get ();
|
||||
if (p)
|
||||
thiz ()->destroy (p);
|
||||
do_destroy (instance.get ());
|
||||
}
|
||||
inline void free_instance (void)
|
||||
{
|
||||
retry:
|
||||
Stored *p = instance.get ();
|
||||
if (unlikely (p && !this->instance.cmpexch (p, nullptr)))
|
||||
goto retry;
|
||||
do_destroy (p);
|
||||
}
|
||||
|
||||
inline const Returned * operator -> (void) const { return thiz ()->get (); }
|
||||
inline const Returned & operator * (void) const { return *thiz ()->get (); }
|
||||
inline Stored * do_create (void) const
|
||||
{
|
||||
Stored *p = this->template call_create<Stored, Funcs> ();
|
||||
if (unlikely (!p))
|
||||
p = const_cast<Stored *> (Funcs::get_null ());
|
||||
return p;
|
||||
}
|
||||
static inline void do_destroy (Stored *p)
|
||||
{
|
||||
if (p && p != Funcs::get_null ())
|
||||
Funcs::destroy (p);
|
||||
}
|
||||
|
||||
inline const Returned * operator -> (void) const { return get (); }
|
||||
inline const Returned & operator * (void) const { return *get (); }
|
||||
|
||||
inline Data * get_data (void) const
|
||||
{
|
||||
return *(((Data **) this) - WheresData);
|
||||
}
|
||||
|
||||
inline Stored * get_stored (void) const
|
||||
{
|
||||
|
@ -623,15 +673,10 @@ struct hb_lazy_loader_t
|
|||
Stored *p = this->instance.get ();
|
||||
if (unlikely (!p))
|
||||
{
|
||||
hb_face_t *face = *(((hb_face_t **) this) - WheresFace);
|
||||
if (likely (!p))
|
||||
p = thiz ()->create (face);
|
||||
if (unlikely (!p))
|
||||
p = thiz ()->create (nullptr); /* Produce nil object. */
|
||||
assert (p);
|
||||
p = do_create ();
|
||||
if (unlikely (!this->instance.cmpexch (nullptr, p)))
|
||||
{
|
||||
thiz ()->destroy (p);
|
||||
do_destroy (p);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
@ -644,23 +689,38 @@ struct hb_lazy_loader_t
|
|||
* However, to make TSan, etc, happy, we using cmpexch. */
|
||||
retry:
|
||||
Stored *p = this->instance.get ();
|
||||
if (p)
|
||||
{
|
||||
if (unlikely (!this->instance.cmpexch (p, instance_)))
|
||||
goto retry;
|
||||
thiz ()->destroy (p);
|
||||
}
|
||||
if (unlikely (!this->instance.cmpexch (p, instance_)))
|
||||
goto retry;
|
||||
do_destroy (p);
|
||||
}
|
||||
|
||||
inline const Returned * get (void) const
|
||||
{
|
||||
return thiz ()->convert (get_stored ());
|
||||
}
|
||||
inline const Returned * get (void) const { return Funcs::convert (get_stored ()); }
|
||||
inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
|
||||
|
||||
static inline const Returned* convert (const Stored *p)
|
||||
/* To be possibly overloaded by subclasses. */
|
||||
static inline Returned* convert (Stored *p) { return p; }
|
||||
|
||||
/* By default null/init/fini the object. */
|
||||
static inline const Stored* get_null (void) { return &Null(Stored); }
|
||||
static inline Stored *create (Data *data)
|
||||
{
|
||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
||||
if (likely (p))
|
||||
p->init (data);
|
||||
return p;
|
||||
}
|
||||
static inline Stored *create (void)
|
||||
{
|
||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
||||
if (likely (p))
|
||||
p->init ();
|
||||
return p;
|
||||
}
|
||||
static inline void destroy (Stored *p)
|
||||
{
|
||||
p->fini ();
|
||||
free (p);
|
||||
}
|
||||
|
||||
private:
|
||||
/* Must only have one pointer. */
|
||||
|
@ -670,42 +730,28 @@ struct hb_lazy_loader_t
|
|||
/* Specializations. */
|
||||
|
||||
template <unsigned int WheresFace, typename T>
|
||||
struct hb_object_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_object_lazy_loader_t<WheresFace, T>, T>
|
||||
{
|
||||
static inline T *create (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!face))
|
||||
return const_cast<T *> (&Null(T));
|
||||
T *p = (T *) calloc (1, sizeof (T));
|
||||
if (unlikely (!p))
|
||||
p = const_cast<T *> (&Null(T));
|
||||
else
|
||||
p->init (face);
|
||||
return p;
|
||||
}
|
||||
static inline void destroy (T *p)
|
||||
{
|
||||
if (p != &Null(T))
|
||||
{
|
||||
p->fini();
|
||||
free (p);
|
||||
}
|
||||
}
|
||||
};
|
||||
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
|
||||
hb_face_lazy_loader_t<WheresFace, T>,
|
||||
hb_face_t, WheresFace> {};
|
||||
|
||||
template <unsigned int WheresFace, typename T>
|
||||
struct hb_table_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_table_lazy_loader_t<WheresFace, T>, T, hb_blob_t>
|
||||
template <typename T, unsigned int WheresFace>
|
||||
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
|
||||
hb_table_lazy_loader_t<T, WheresFace>,
|
||||
hb_face_t, WheresFace,
|
||||
hb_blob_t>
|
||||
{
|
||||
static inline hb_blob_t *create (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!face))
|
||||
return hb_blob_get_empty ();
|
||||
return hb_sanitize_context_t ().reference_table<T> (face);
|
||||
}
|
||||
static inline void destroy (hb_blob_t *p)
|
||||
{
|
||||
hb_blob_destroy (p);
|
||||
}
|
||||
static inline const hb_blob_t *get_null (void)
|
||||
{
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
static inline const T* convert (const hb_blob_t *blob)
|
||||
{
|
||||
return blob->as<T> ();
|
||||
|
@ -717,5 +763,30 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_table_lazy_loade
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Subclass>
|
||||
struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass>
|
||||
{
|
||||
static inline void destroy (hb_font_funcs_t *p)
|
||||
{
|
||||
hb_font_funcs_destroy (p);
|
||||
}
|
||||
static inline const hb_font_funcs_t *get_null (void)
|
||||
{
|
||||
return hb_font_funcs_get_empty ();
|
||||
}
|
||||
};
|
||||
template <typename Subclass>
|
||||
struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass>
|
||||
{
|
||||
static inline void destroy (hb_unicode_funcs_t *p)
|
||||
{
|
||||
hb_unicode_funcs_destroy (p);
|
||||
}
|
||||
static inline const hb_unicode_funcs_t *get_null (void)
|
||||
{
|
||||
return hb_unicode_funcs_get_empty ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_MACHINERY_PRIVATE_HH */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "hb-ot.h"
|
||||
|
||||
#include "hb-font-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
|
@ -72,10 +73,10 @@ struct hb_ot_font_t
|
|||
OT::vmtx::accelerator_t v_metrics;
|
||||
|
||||
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
|
||||
hb_object_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
|
||||
hb_object_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
|
||||
hb_object_lazy_loader_t<3, OT::post::accelerator_t> post;
|
||||
hb_object_lazy_loader_t<4, OT::kern::accelerator_t> kern;
|
||||
hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
|
||||
hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
|
||||
hb_face_lazy_loader_t<3, OT::post::accelerator_t> post;
|
||||
hb_face_lazy_loader_t<4, OT::kern::accelerator_t> kern;
|
||||
};
|
||||
|
||||
|
||||
|
@ -227,30 +228,15 @@ hb_ot_get_font_v_extents (hb_font_t *font,
|
|||
return ot_font->v_metrics.has_font_extents;
|
||||
}
|
||||
|
||||
static hb_atomic_ptr_t <hb_font_funcs_t> static_ot_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_ot_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_font_funcs_t *ot_funcs = static_ot_funcs.get ();
|
||||
if (unlikely (!static_ot_funcs.cmpexch (ot_funcs, nullptr)))
|
||||
goto retry;
|
||||
|
||||
hb_font_funcs_destroy (ot_funcs);
|
||||
}
|
||||
static void free_static_ot_funcs (void);
|
||||
#endif
|
||||
|
||||
static hb_font_funcs_t *
|
||||
_hb_ot_get_font_funcs (void)
|
||||
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
|
||||
{
|
||||
retry:
|
||||
hb_font_funcs_t *funcs = static_ot_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
static inline hb_font_funcs_t *create (void)
|
||||
{
|
||||
funcs = hb_font_funcs_create ();
|
||||
hb_font_funcs_t *funcs = hb_font_funcs_create ();
|
||||
|
||||
hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
|
||||
|
@ -269,18 +255,26 @@ retry:
|
|||
|
||||
hb_font_funcs_make_immutable (funcs);
|
||||
|
||||
if (unlikely (!static_ot_funcs.cmpexch (nullptr, funcs)))
|
||||
{
|
||||
hb_font_funcs_destroy (funcs);
|
||||
goto retry;
|
||||
}
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ot_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_ot_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
|
||||
static
|
||||
void free_static_ot_funcs (void)
|
||||
{
|
||||
static_ot_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
return funcs;
|
||||
static hb_font_funcs_t *
|
||||
_hb_ot_get_font_funcs (void)
|
||||
{
|
||||
return static_ot_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ struct hb_ot_layout_t
|
|||
|
||||
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
|
||||
hb_table_lazy_loader_t<HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type), struct Namespace::Type> Type;
|
||||
hb_table_lazy_loader_t<struct Namespace::Type, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type;
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
} table;
|
||||
|
|
|
@ -125,7 +125,20 @@ struct _hb_alignof
|
|||
#define alignof(x) (_hb_alignof<x>::value)
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus < 201103L
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
|
||||
#ifndef explicit_operator
|
||||
#define explicit_operator
|
||||
#endif
|
||||
|
||||
#else /* __cplusplus >= 201103L */
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
|
||||
#ifndef explicit_operator
|
||||
#define explicit_operator explicit
|
||||
#endif
|
||||
|
||||
#endif /* __cplusplus < 201103L */
|
||||
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
|
||||
#define likely(expr) (__builtin_expect (!!(expr), 1))
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "hb-shape-plan-private.hh"
|
||||
#include "hb-buffer-private.hh"
|
||||
#include "hb-font-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
/**
|
||||
* SECTION:hb-shape
|
||||
|
@ -45,21 +46,52 @@
|
|||
* contains the output glyphs and their positions.
|
||||
**/
|
||||
|
||||
static hb_atomic_ptr_t <const char **> static_shaper_list;
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void free_static_shaper_list (void);
|
||||
#endif
|
||||
|
||||
static const char *nil_shaper_list[] = {nullptr};
|
||||
|
||||
static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
|
||||
hb_shaper_list_lazy_loader_t>
|
||||
{
|
||||
static inline const char ** create (void)
|
||||
{
|
||||
const char **shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
|
||||
if (unlikely (!shaper_list))
|
||||
return nullptr;
|
||||
|
||||
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
|
||||
unsigned int i;
|
||||
for (i = 0; i < HB_SHAPERS_COUNT; i++)
|
||||
shaper_list[i] = shapers[i].name;
|
||||
shaper_list[i] = nullptr;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shaper_list);
|
||||
#endif
|
||||
|
||||
return shaper_list;
|
||||
}
|
||||
static inline void destroy (const char **l)
|
||||
{
|
||||
free (l);
|
||||
}
|
||||
static inline const char ** get_null (void)
|
||||
{
|
||||
return nil_shaper_list;
|
||||
}
|
||||
} static_shaper_list;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_shaper_list (void)
|
||||
{
|
||||
retry:
|
||||
const char **shaper_list = static_shaper_list.get ();
|
||||
if (unlikely (!static_shaper_list.cmpexch (shaper_list, nullptr)))
|
||||
goto retry;
|
||||
|
||||
free (shaper_list);
|
||||
static_shaper_list.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* hb_shape_list_shapers:
|
||||
*
|
||||
|
@ -73,36 +105,7 @@ retry:
|
|||
const char **
|
||||
hb_shape_list_shapers (void)
|
||||
{
|
||||
retry:
|
||||
const char **shaper_list = static_shaper_list.get ();
|
||||
|
||||
if (unlikely (!shaper_list))
|
||||
{
|
||||
/* Not found; allocate one. */
|
||||
shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
|
||||
if (unlikely (!shaper_list)) {
|
||||
static const char *nil_shaper_list[] = {nullptr};
|
||||
return nil_shaper_list;
|
||||
}
|
||||
|
||||
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
|
||||
unsigned int i;
|
||||
for (i = 0; i < HB_SHAPERS_COUNT; i++)
|
||||
shaper_list[i] = shapers[i].name;
|
||||
shaper_list[i] = nullptr;
|
||||
|
||||
if (unlikely (!static_shaper_list.cmpexch (nullptr, shaper_list)))
|
||||
{
|
||||
free (shaper_list);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shaper_list); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return shaper_list;
|
||||
return static_shaper_list.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
|
||||
static const hb_shaper_pair_t all_shapers[] = {
|
||||
|
@ -35,53 +35,30 @@ static const hb_shaper_pair_t all_shapers[] = {
|
|||
#undef HB_SHAPER_IMPLEMENT
|
||||
};
|
||||
|
||||
|
||||
/* Thread-safe, lock-free, shapers */
|
||||
|
||||
static hb_atomic_ptr_t<const hb_shaper_pair_t> static_shapers;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_shapers (void)
|
||||
{
|
||||
retry:
|
||||
const hb_shaper_pair_t *shapers = static_shapers.get ();
|
||||
if (unlikely (!static_shapers.cmpexch (shapers, nullptr)))
|
||||
goto retry;
|
||||
|
||||
if (unlikely (shapers != all_shapers))
|
||||
free ((void *) shapers);
|
||||
}
|
||||
static void free_static_shapers (void);
|
||||
#endif
|
||||
|
||||
const hb_shaper_pair_t *
|
||||
_hb_shapers_get (void)
|
||||
static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t,
|
||||
hb_shapers_lazy_loader_t>
|
||||
{
|
||||
retry:
|
||||
hb_shaper_pair_t *shapers = const_cast<hb_shaper_pair_t *> (static_shapers.get ());
|
||||
|
||||
if (unlikely (!shapers))
|
||||
static inline hb_shaper_pair_t *create (void)
|
||||
{
|
||||
char *env = getenv ("HB_SHAPER_LIST");
|
||||
if (!env || !*env) {
|
||||
(void) static_shapers.cmpexch (nullptr, &all_shapers[0]);
|
||||
return (const hb_shaper_pair_t *) all_shapers;
|
||||
}
|
||||
if (!env || !*env)
|
||||
return nullptr;
|
||||
|
||||
/* Not found; allocate one. */
|
||||
shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
|
||||
hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
|
||||
if (unlikely (!shapers))
|
||||
{
|
||||
(void) static_shapers.cmpexch (nullptr, &all_shapers[0]);
|
||||
return (const hb_shaper_pair_t *) all_shapers;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
memcpy (shapers, all_shapers, sizeof (all_shapers));
|
||||
|
||||
/* Reorder shaper list to prefer requested shapers. */
|
||||
unsigned int i = 0;
|
||||
char *end, *p = env;
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
end = strchr (p, ',');
|
||||
if (!end)
|
||||
end = p + strlen (p);
|
||||
|
@ -103,16 +80,32 @@ retry:
|
|||
p = end + 1;
|
||||
}
|
||||
|
||||
if (unlikely (!static_shapers.cmpexch (nullptr, shapers)))
|
||||
{
|
||||
free (shapers);
|
||||
goto retry;
|
||||
}
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shapers);
|
||||
#endif
|
||||
|
||||
return shapers;
|
||||
}
|
||||
static inline void destroy (const hb_shaper_pair_t *p)
|
||||
{
|
||||
free ((void *) p);
|
||||
}
|
||||
static inline const hb_shaper_pair_t *get_null (void)
|
||||
{
|
||||
return all_shapers;
|
||||
}
|
||||
} static_shapers;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_shapers); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return shapers;
|
||||
static
|
||||
void free_static_shapers (void)
|
||||
{
|
||||
static_shapers.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
const hb_shaper_pair_t *
|
||||
_hb_shapers_get (void)
|
||||
{
|
||||
return static_shapers.get_unconst ();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-unicode-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
#include "ucdn.h"
|
||||
|
||||
|
@ -238,31 +239,14 @@ hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
|||
return ucdn_compat_decompose(u, decomposed);
|
||||
}
|
||||
|
||||
static hb_atomic_ptr_t<hb_unicode_funcs_t> static_ucdn_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_ucdn_funcs (void)
|
||||
static void free_static_ucdn_funcs (void);
|
||||
|
||||
static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t>
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *ucdn_funcs = static_ucdn_funcs.get ();
|
||||
if (unlikely (!static_ucdn_funcs.cmpexch (ucdn_funcs, nullptr)))
|
||||
goto retry;
|
||||
|
||||
hb_unicode_funcs_destroy (ucdn_funcs);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" HB_INTERNAL
|
||||
hb_unicode_funcs_t *
|
||||
hb_ucdn_get_unicode_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_unicode_funcs_t *funcs = static_ucdn_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
static inline hb_unicode_funcs_t *create (void)
|
||||
{
|
||||
funcs = hb_unicode_funcs_create (nullptr);
|
||||
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
|
||||
hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
|
||||
|
@ -271,16 +255,25 @@ retry:
|
|||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
if (unlikely (!static_ucdn_funcs.cmpexch (nullptr, funcs)))
|
||||
{
|
||||
hb_unicode_funcs_destroy (funcs);
|
||||
goto retry;
|
||||
}
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ucdn_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_ucdn_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
};
|
||||
|
||||
return hb_unicode_funcs_reference (funcs);
|
||||
static
|
||||
void free_static_ucdn_funcs (void)
|
||||
{
|
||||
static_ucdn_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" HB_INTERNAL
|
||||
hb_unicode_funcs_t *
|
||||
hb_ucdn_get_unicode_funcs (void)
|
||||
{
|
||||
return static_ucdn_funcs.get_unconst ();
|
||||
}
|
||||
|
|
|
@ -190,7 +190,8 @@ hb_ScriptPlaceOpenType(
|
|||
}
|
||||
|
||||
|
||||
struct hb_uniscribe_shaper_funcs_t {
|
||||
struct hb_uniscribe_shaper_funcs_t
|
||||
{
|
||||
SIOT ScriptItemizeOpenType;
|
||||
SSOT ScriptShapeOpenType;
|
||||
SPOT ScriptPlaceOpenType;
|
||||
|
@ -220,47 +221,49 @@ struct hb_uniscribe_shaper_funcs_t {
|
|||
}
|
||||
}
|
||||
};
|
||||
static hb_atomic_ptr_t<hb_uniscribe_shaper_funcs_t> uniscribe_funcs;
|
||||
|
||||
|
||||
static void free_static_uniscribe_shaper_funcs (void);
|
||||
|
||||
static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t,
|
||||
hb_uniscribe_shaper_funcs_lazy_loader_t>
|
||||
{
|
||||
static inline hb_uniscribe_shaper_funcs_t *create (void)
|
||||
{
|
||||
hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
|
||||
if (unlikely (!funcs))
|
||||
return nullptr;
|
||||
|
||||
funcs->init ();
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static inline void
|
||||
free_uniscribe_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs = uniscribe_funcs.get ();
|
||||
if (unlikely (!uniscribe_funcs.cmpexch (local_uniscribe_funcs, nullptr)))
|
||||
goto retry;
|
||||
atexit (free_static_uniscribe_shaper_funcs);
|
||||
#endif
|
||||
|
||||
free (local_uniscribe_funcs);
|
||||
return funcs;
|
||||
}
|
||||
static inline void destroy (hb_uniscribe_shaper_funcs_t *p)
|
||||
{
|
||||
free ((void *) p);
|
||||
}
|
||||
static inline hb_uniscribe_shaper_funcs_t *get_null (void)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_uniscribe_shaper_funcs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_uniscribe_shaper_funcs (void)
|
||||
{
|
||||
static_uniscribe_shaper_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_uniscribe_shaper_funcs_t *
|
||||
hb_uniscribe_shaper_get_funcs (void)
|
||||
{
|
||||
retry:
|
||||
hb_uniscribe_shaper_funcs_t *funcs = uniscribe_funcs.get ();
|
||||
|
||||
if (unlikely (!funcs))
|
||||
{
|
||||
funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
|
||||
if (unlikely (!funcs))
|
||||
return nullptr;
|
||||
|
||||
funcs->init ();
|
||||
|
||||
if (unlikely (!uniscribe_funcs.cmpexch (nullptr, funcs)))
|
||||
{
|
||||
free (funcs);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return funcs;
|
||||
return static_uniscribe_shaper_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ HB_BEGIN_DECLS
|
|||
|
||||
#define HB_VERSION_MAJOR 1
|
||||
#define HB_VERSION_MINOR 8
|
||||
#define HB_VERSION_MICRO 7
|
||||
#define HB_VERSION_MICRO 8
|
||||
|
||||
#define HB_VERSION_STRING "1.8.7"
|
||||
#define HB_VERSION_STRING "1.8.8"
|
||||
|
||||
#define HB_VERSION_ATLEAST(major,minor,micro) \
|
||||
((major)*10000+(minor)*100+(micro) <= \
|
||||
|
|
Loading…
Reference in New Issue