Merge branch 'master' into cff-subset

This commit is contained in:
Michiharu Ariza 2018-08-15 15:00:55 -07:00
commit 25b8310b2a
17 changed files with 485 additions and 412 deletions

18
NEWS
View File

@ -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 Overview of changes leading to 1.8.7
Wednesday, August 8, 2018 Wednesday, August 8, 2018
==================================== ====================================

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64]) AC_PREREQ([2.64])
AC_INIT([HarfBuzz], AC_INIT([HarfBuzz],
[1.8.7], [1.8.8],
[https://github.com/harfbuzz/harfbuzz/issues/new], [https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz], [harfbuzz],
[http://harfbuzz.org/]) [http://harfbuzz.org/])

View File

@ -216,7 +216,7 @@ hb_buffer_t::reset (void)
return; return;
hb_unicode_funcs_destroy (unicode); 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; flags = HB_BUFFER_FLAG_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
@ -908,7 +908,6 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
if (!unicode_funcs) if (!unicode_funcs)
unicode_funcs = hb_unicode_funcs_get_default (); unicode_funcs = hb_unicode_funcs_get_default ();
hb_unicode_funcs_reference (unicode_funcs); hb_unicode_funcs_reference (unicode_funcs);
hb_unicode_funcs_destroy (buffer->unicode); hb_unicode_funcs_destroy (buffer->unicode);
buffer->unicode = unicode_funcs; buffer->unicode = unicode_funcs;

View File

@ -28,6 +28,7 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-machinery-private.hh"
#include <locale.h> #include <locale.h>
#ifdef HAVE_XLOCALE_H #ifdef HAVE_XLOCALE_H
@ -730,47 +731,47 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
#ifdef USE_XLOCALE #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 #ifdef HB_USE_ATEXIT
static void atexit (free_static_C_locale);
free_C_locale (void) #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: static_C_locale.free_instance ();
HB_LOCALE_T locale = C_locale.get ();
if (unlikely (!C_locale.cmpexch (locale, nullptr)))
goto retry;
if (locale)
HB_FREE_LOCALE (locale);
} }
#endif #endif
static HB_LOCALE_T static HB_LOCALE_T
get_C_locale (void) get_C_locale (void)
{ {
retry: return static_C_locale.get_unconst ();
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;
} }
#endif #endif /* USE_XLOCALE */
static bool static bool
parse_float (const char **pp, const char *end, float *pv) 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; const char *p = *pp;
while (*pp < end && ISALNUM(**pp)) while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
(*pp)++; (*pp)++;
if (p == *pp || *pp - p > 4) if (p == *pp || *pp - p > 4)

View File

@ -32,6 +32,7 @@
#include "hb-ft.h" #include "hb-ft.h"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-machinery-private.hh"
#include FT_ADVANCES_H #include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H #include FT_MULTIPLE_MASTERS_H
@ -416,30 +417,15 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true; return true;
} }
static hb_atomic_ptr_t<hb_font_funcs_t> static_ft_funcs;
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
static static void free_static_ft_funcs (void);
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);
}
#endif #endif
static void static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
{ {
retry: static inline hb_font_funcs_t *create (void)
hb_font_funcs_t *funcs = static_ft_funcs.get ();
if (unlikely (!funcs))
{ {
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_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_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
@ -458,21 +444,35 @@ retry:
hb_font_funcs_make_immutable (funcs); hb_font_funcs_make_immutable (funcs);
if (unlikely (!static_ft_funcs. cmpexch (nullptr, funcs))) #ifdef HB_USE_ATEXIT
{ atexit (free_static_ft_funcs);
hb_font_funcs_destroy (funcs); #endif
goto retry;
return funcs;
} }
} static_ft_funcs;
#ifdef HB_USE_ATEXIT #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 #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; bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font, hb_font_set_funcs (font,
funcs, _hb_ft_get_font_funcs (),
_hb_ft_font_create (ft_face, symbol, unref), _hb_ft_font_create (ft_face, symbol, unref),
_hb_ft_font_destroy); _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); 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 #ifdef HB_USE_ATEXIT
static static
void free_ft_library (void) void free_static_ft_library (void)
{ {
retry: static_ft_library.free_instance ();
FT_Library library = ft_library.get ();
if (unlikely (!ft_library.cmpexch (library, nullptr)))
goto retry;
FT_Done_FreeType (library);
} }
#endif #endif
static FT_Library static FT_Library
get_ft_library (void) get_ft_library (void)
{ {
retry: return static_ft_library.get_unconst ();
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;
} }
static void static void

View File

@ -31,6 +31,7 @@
#include "hb-glib.h" #include "hb-glib.h"
#include "hb-unicode-private.hh" #include "hb-unicode-private.hh"
#include "hb-machinery-private.hh"
#if !GLIB_CHECK_VERSION(2,29,14) #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; return utf8_decomposed_len;
} }
static hb_atomic_ptr_t<hb_unicode_funcs_t> static_glib_funcs;
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
static static void free_static_glib_funcs (void);
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);
}
#endif #endif
hb_unicode_funcs_t * static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
hb_glib_get_unicode_funcs (void)
{ {
retry: static inline hb_unicode_funcs_t *create (void)
hb_unicode_funcs_t *funcs = static_glib_funcs.get ();
if (unlikely (!funcs))
{ {
funcs = hb_unicode_funcs_create (nullptr); hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
#define HB_UNICODE_FUNC_IMPLEMENT(name) \ #define HB_UNICODE_FUNC_IMPLEMENT(name) \
hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr); hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
@ -396,19 +383,29 @@ retry:
hb_unicode_funcs_make_immutable (funcs); hb_unicode_funcs_make_immutable (funcs);
if (unlikely (!static_glib_funcs.cmpexch (nullptr, funcs))) #ifdef HB_USE_ATEXIT
{ atexit (free_static_glib_funcs);
hb_unicode_funcs_destroy (funcs); #endif
goto retry;
return funcs;
} }
} static_glib_funcs;
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
atexit (free_static_glib_funcs); /* First person registers atexit() callback. */ static
#endif void free_static_glib_funcs (void)
}; {
static_glib_funcs.free_instance ();
return hb_unicode_funcs_reference (funcs);
} }
#endif
hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void)
{
return static_glib_funcs.get_unconst ();
}
#if GLIB_CHECK_VERSION(2,31,10) #if GLIB_CHECK_VERSION(2,31,10)

View File

@ -32,6 +32,7 @@
#include "hb-icu.h" #include "hb-icu.h"
#include "hb-unicode-private.hh" #include "hb-unicode-private.hh"
#include "hb-machinery-private.hh"
#include <unicode/uchar.h> #include <unicode/uchar.h>
#include <unicode/unorm2.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); 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 static hb_bool_t
hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t a, 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 #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; if (ret < 0) return false;
*ab = ret; *ab = ret;
return true; return true;
@ -222,10 +220,11 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
{ {
#if U_ICU_VERSION_MAJOR_NUM >= 49 #if U_ICU_VERSION_MAJOR_NUM >= 49
{ {
const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
UChar decomposed[4]; UChar decomposed[4];
int len; int len;
UErrorCode icu_err = U_ZERO_ERROR; UErrorCode icu_err = U_ZERO_ERROR;
len = unorm2_getRawDecomposition (normalizer.get (), ab, decomposed, len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
ARRAY_LENGTH (decomposed), &icu_err); ARRAY_LENGTH (decomposed), &icu_err);
if (U_FAILURE (icu_err) || len < 0) return false; 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; 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 #ifdef HB_USE_ATEXIT
static static
void free_static_icu_funcs (void) void free_static_icu_funcs (void)
{ {
retry: static_icu_funcs.free_instance ();
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);
} }
#endif #endif
hb_unicode_funcs_t * hb_unicode_funcs_t *
hb_icu_get_unicode_funcs (void) hb_icu_get_unicode_funcs (void)
{ {
retry: return static_icu_funcs.get_unconst ();
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);
} }

View File

@ -72,7 +72,7 @@ struct Iter<T *>
array (array_), length (length_) {} array (array_), length (length_) {}
/* Emptiness. */ /* Emptiness. */
inline operator bool (void) const { return bool (length); } explicit_operator inline operator bool (void) const { return bool (length); }
/* Current item. */ /* Current item. */
inline T &operator * (void) inline T &operator * (void)

View File

@ -590,32 +590,82 @@ struct BEInt<Type, 4>
* Lazy loaders. * Lazy loaders.
*/ */
template <unsigned int WheresFace, template <typename Data, unsigned int WheresData>
typename Subclass, struct hb_data_wrapper_t
typename Returned,
typename Stored = Returned>
struct hb_lazy_loader_t
{ {
static_assert (WheresFace > 0, ""); static_assert (WheresData > 0, "");
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ inline Data * get_data (void) const
inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); } {
inline Subclass* thiz (void) { return static_cast<Subclass *> (this); } 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 init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
inline void init (void) inline void init (void) { instance.set_relaxed (nullptr); }
{
instance.set_relaxed (nullptr);
}
inline void fini (void) inline void fini (void)
{ {
Stored *p = this->instance.get (); do_destroy (instance.get ());
if (p) }
thiz ()->destroy (p); 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 Stored * do_create (void) const
inline const Returned & operator * (void) const { return *thiz ()->get (); } {
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 inline Stored * get_stored (void) const
{ {
@ -623,15 +673,10 @@ struct hb_lazy_loader_t
Stored *p = this->instance.get (); Stored *p = this->instance.get ();
if (unlikely (!p)) if (unlikely (!p))
{ {
hb_face_t *face = *(((hb_face_t **) this) - WheresFace); p = do_create ();
if (likely (!p))
p = thiz ()->create (face);
if (unlikely (!p))
p = thiz ()->create (nullptr); /* Produce nil object. */
assert (p);
if (unlikely (!this->instance.cmpexch (nullptr, p))) if (unlikely (!this->instance.cmpexch (nullptr, p)))
{ {
thiz ()->destroy (p); do_destroy (p);
goto retry; goto retry;
} }
} }
@ -644,23 +689,38 @@ struct hb_lazy_loader_t
* However, to make TSan, etc, happy, we using cmpexch. */ * However, to make TSan, etc, happy, we using cmpexch. */
retry: retry:
Stored *p = this->instance.get (); Stored *p = this->instance.get ();
if (p)
{
if (unlikely (!this->instance.cmpexch (p, instance_))) if (unlikely (!this->instance.cmpexch (p, instance_)))
goto retry; goto retry;
thiz ()->destroy (p); do_destroy (p);
}
} }
inline const Returned * get (void) const 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 ())); }
return thiz ()->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; 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: private:
/* Must only have one pointer. */ /* Must only have one pointer. */
@ -670,42 +730,28 @@ struct hb_lazy_loader_t
/* Specializations. */ /* Specializations. */
template <unsigned int WheresFace, typename T> 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> struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
{ hb_face_lazy_loader_t<WheresFace, T>,
static inline T *create (hb_face_t *face) hb_face_t, WheresFace> {};
{
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);
}
}
};
template <unsigned int WheresFace, typename T> template <typename T, unsigned int WheresFace>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_table_lazy_loader_t<WheresFace, T>, T, hb_blob_t> 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) 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); return hb_sanitize_context_t ().reference_table<T> (face);
} }
static inline void destroy (hb_blob_t *p) static inline void destroy (hb_blob_t *p)
{ {
hb_blob_destroy (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) static inline const T* convert (const hb_blob_t *blob)
{ {
return blob->as<T> (); 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 */ #endif /* HB_MACHINERY_PRIVATE_HH */

View File

@ -29,6 +29,7 @@
#include "hb-ot.h" #include "hb-ot.h"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-machinery-private.hh"
#include "hb-ot-cmap-table.hh" #include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh" #include "hb-ot-glyf-table.hh"
@ -72,10 +73,10 @@ struct hb_ot_font_t
OT::vmtx::accelerator_t v_metrics; OT::vmtx::accelerator_t v_metrics;
hb_face_t *face; /* MUST be JUST before the lazy loaders. */ hb_face_t *face; /* MUST be JUST before the lazy loaders. */
hb_object_lazy_loader_t<1, OT::glyf::accelerator_t> glyf; hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
hb_object_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt; hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
hb_object_lazy_loader_t<3, OT::post::accelerator_t> post; hb_face_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<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; return ot_font->v_metrics.has_font_extents;
} }
static hb_atomic_ptr_t <hb_font_funcs_t> static_ot_funcs;
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
static static void free_static_ot_funcs (void);
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);
}
#endif #endif
static hb_font_funcs_t * static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
_hb_ot_get_font_funcs (void)
{ {
retry: static inline hb_font_funcs_t *create (void)
hb_font_funcs_t *funcs = static_ot_funcs.get ();
if (unlikely (!funcs))
{ {
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_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); 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); 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 #ifdef HB_USE_ATEXIT
atexit (free_static_ot_funcs); /* First person registers atexit() callback. */ atexit (free_static_ot_funcs);
#endif #endif
};
return funcs; return funcs;
}
} static_ot_funcs;
#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
static_ot_funcs.free_instance ();
}
#endif
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
return static_ot_funcs.get_unconst ();
} }

View File

@ -205,7 +205,7 @@ struct hb_ot_layout_t
hb_face_t *face; /* MUST be JUST before the lazy loaders. */ hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_LAYOUT_TABLE(Namespace, Type) \ #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 HB_OT_LAYOUT_TABLES
#undef HB_OT_LAYOUT_TABLE #undef HB_OT_LAYOUT_TABLE
} table; } table;

View File

@ -125,7 +125,20 @@ struct _hb_alignof
#define alignof(x) (_hb_alignof<x>::value) #define alignof(x) (_hb_alignof<x>::value)
#endif #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__) #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1)) #define likely(expr) (__builtin_expect (!!(expr), 1))

View File

@ -32,6 +32,7 @@
#include "hb-shape-plan-private.hh" #include "hb-shape-plan-private.hh"
#include "hb-buffer-private.hh" #include "hb-buffer-private.hh"
#include "hb-font-private.hh" #include "hb-font-private.hh"
#include "hb-machinery-private.hh"
/** /**
* SECTION:hb-shape * SECTION:hb-shape
@ -45,21 +46,52 @@
* contains the output glyphs and their positions. * 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 #ifdef HB_USE_ATEXIT
static static
void free_static_shaper_list (void) void free_static_shaper_list (void)
{ {
retry: static_shaper_list.free_instance ();
const char **shaper_list = static_shaper_list.get ();
if (unlikely (!static_shaper_list.cmpexch (shaper_list, nullptr)))
goto retry;
free (shaper_list);
} }
#endif #endif
/** /**
* hb_shape_list_shapers: * hb_shape_list_shapers:
* *
@ -73,36 +105,7 @@ retry:
const char ** const char **
hb_shape_list_shapers (void) hb_shape_list_shapers (void)
{ {
retry: return static_shaper_list.get_unconst ();
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;
} }

View File

@ -26,7 +26,7 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-shaper-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[] = { static const hb_shaper_pair_t all_shapers[] = {
@ -35,53 +35,30 @@ static const hb_shaper_pair_t all_shapers[] = {
#undef HB_SHAPER_IMPLEMENT #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 #ifdef HB_USE_ATEXIT
static static void free_static_shapers (void);
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);
}
#endif #endif
const hb_shaper_pair_t * static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t,
_hb_shapers_get (void) hb_shapers_lazy_loader_t>
{ {
retry: static inline hb_shaper_pair_t *create (void)
hb_shaper_pair_t *shapers = const_cast<hb_shaper_pair_t *> (static_shapers.get ());
if (unlikely (!shapers))
{ {
char *env = getenv ("HB_SHAPER_LIST"); char *env = getenv ("HB_SHAPER_LIST");
if (!env || !*env) { if (!env || !*env)
(void) static_shapers.cmpexch (nullptr, &all_shapers[0]); return nullptr;
return (const hb_shaper_pair_t *) all_shapers;
}
/* Not found; allocate one. */ hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
if (unlikely (!shapers)) if (unlikely (!shapers))
{ return nullptr;
(void) static_shapers.cmpexch (nullptr, &all_shapers[0]);
return (const hb_shaper_pair_t *) all_shapers;
}
memcpy (shapers, all_shapers, sizeof (all_shapers)); memcpy (shapers, all_shapers, sizeof (all_shapers));
/* Reorder shaper list to prefer requested shapers. */ /* Reorder shaper list to prefer requested shapers. */
unsigned int i = 0; unsigned int i = 0;
char *end, *p = env; char *end, *p = env;
for (;;) { for (;;)
{
end = strchr (p, ','); end = strchr (p, ',');
if (!end) if (!end)
end = p + strlen (p); end = p + strlen (p);
@ -103,16 +80,32 @@ retry:
p = end + 1; p = end + 1;
} }
if (unlikely (!static_shapers.cmpexch (nullptr, shapers)))
{
free (shapers);
goto retry;
}
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
atexit (free_static_shapers); /* First person registers atexit() callback. */ atexit (free_static_shapers);
#endif #endif
}
return shapers; 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
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 ();
} }

View File

@ -17,6 +17,7 @@
#include "hb-private.hh" #include "hb-private.hh"
#include "hb-unicode-private.hh" #include "hb-unicode-private.hh"
#include "hb-machinery-private.hh"
#include "ucdn.h" #include "ucdn.h"
@ -238,31 +239,14 @@ hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
return ucdn_compat_decompose(u, decomposed); 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: static inline hb_unicode_funcs_t *create (void)
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))
{ {
funcs = hb_unicode_funcs_create (nullptr); hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
#define HB_UNICODE_FUNC_IMPLEMENT(name) \ #define HB_UNICODE_FUNC_IMPLEMENT(name) \
hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr); hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
@ -271,16 +255,25 @@ retry:
hb_unicode_funcs_make_immutable (funcs); hb_unicode_funcs_make_immutable (funcs);
if (unlikely (!static_ucdn_funcs.cmpexch (nullptr, funcs))) #ifdef HB_USE_ATEXIT
{ atexit (free_static_ucdn_funcs);
hb_unicode_funcs_destroy (funcs); #endif
goto retry;
return funcs;
} }
} static_ucdn_funcs;
#ifdef HB_USE_ATEXIT #ifdef HB_USE_ATEXIT
atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */ static
#endif void free_static_ucdn_funcs (void)
}; {
static_ucdn_funcs.free_instance ();
return hb_unicode_funcs_reference (funcs); }
#endif
extern "C" HB_INTERNAL
hb_unicode_funcs_t *
hb_ucdn_get_unicode_funcs (void)
{
return static_ucdn_funcs.get_unconst ();
} }

View File

@ -190,7 +190,8 @@ hb_ScriptPlaceOpenType(
} }
struct hb_uniscribe_shaper_funcs_t { struct hb_uniscribe_shaper_funcs_t
{
SIOT ScriptItemizeOpenType; SIOT ScriptItemizeOpenType;
SSOT ScriptShapeOpenType; SSOT ScriptShapeOpenType;
SPOT ScriptPlaceOpenType; 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 #ifdef HB_USE_ATEXIT
static inline void atexit (free_static_uniscribe_shaper_funcs);
free_uniscribe_funcs (void) #endif
{
retry:
hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs = uniscribe_funcs.get ();
if (unlikely (!uniscribe_funcs.cmpexch (local_uniscribe_funcs, nullptr)))
goto retry;
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 #endif
static hb_uniscribe_shaper_funcs_t * static hb_uniscribe_shaper_funcs_t *
hb_uniscribe_shaper_get_funcs (void) hb_uniscribe_shaper_get_funcs (void)
{ {
retry: return static_uniscribe_shaper_funcs.get_unconst ();
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;
} }

View File

@ -38,9 +38,9 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1 #define HB_VERSION_MAJOR 1
#define HB_VERSION_MINOR 8 #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) \ #define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \ ((major)*10000+(minor)*100+(micro) <= \