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
Wednesday, August 8, 2018
====================================

View File

@ -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/])

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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 ();
}

View File

@ -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)

View File

@ -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 */

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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))

View File

@ -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 ();
}

View File

@ -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 ();
}

View File

@ -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 ();
}

View File

@ -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 ();
}

View File

@ -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) <= \