Merge branch 'master' into cff-subset

This commit is contained in:
Michiharu Ariza 2018-11-14 13:54:07 -08:00
commit 892ab37e7c
48 changed files with 699 additions and 463 deletions

View File

@ -15,7 +15,6 @@ check_PROGRAMS =
# Convenience targets: # Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la lib: $(BUILT_SOURCES) libharfbuzz.la
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES) libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
lib_LTLIBRARIES = libharfbuzz.la lib_LTLIBRARIES = libharfbuzz.la
@ -169,36 +168,6 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in EXTRA_DIST += harfbuzz-subset.pc.in
FUZZING_CPPFLAGS = \
-DHB_MAX_NESTING_LEVEL=3 \
-DHB_SANITIZE_MAX_EDITS=3 \
-DHB_SANITIZE_MAX_OPS_FACTOR=3 \
-DHB_SANITIZE_MAX_OPS_MIN=128 \
-DHB_BUFFER_MAX_LEN_FACTOR=3 \
-DHB_BUFFER_MAX_LEN_MIN=8 \
-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
-DHB_BUFFER_MAX_OPS_FACTOR=8 \
-DHB_BUFFER_MAX_OPS_MIN=64 \
-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
$(NULL)
EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS)
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-fuzzing.la
libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS)
libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES)
libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
libharfbuzz_subset_fuzzing_la_LIBADD = libharfbuzz-fuzzing.la
EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-subset-fuzzing.la
if HAVE_ICU if HAVE_ICU
if HAVE_ICU_BUILTIN if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS) HBCFLAGS += $(ICU_CFLAGS)

View File

@ -163,6 +163,7 @@ HB_OT_sources = \
hb-ot-shape-fallback.hh \ hb-ot-shape-fallback.hh \
hb-ot-shape-fallback.cc \ hb-ot-shape-fallback.cc \
hb-ot-shape.hh \ hb-ot-shape.hh \
hb-ot-stat-table.hh \
hb-ot-var.cc \ hb-ot-var.cc \
hb-ot-var-avar-table.hh \ hb-ot-var-avar-table.hh \
hb-ot-var-fvar-table.hh \ hb-ot-var-fvar-table.hh \

View File

@ -200,7 +200,8 @@ def is_HALANT(U, UISC, UGC):
return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC) return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC): def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
# https://github.com/harfbuzz/harfbuzz/issues/1102 # https://github.com/harfbuzz/harfbuzz/issues/1102
return U == 0x11046 # https://github.com/harfbuzz/harfbuzz/issues/1379
return U in [0x11046, 0x1134D]
def is_HALANT_NUM(U, UISC, UGC): def is_HALANT_NUM(U, UISC, UGC):
return UISC == Number_Joiner return UISC == Number_Joiner
def is_ZWNJ(U, UISC, UGC): def is_ZWNJ(U, UISC, UGC):

View File

@ -557,7 +557,9 @@ struct StateTable
/* Negative states. */ /* Negative states. */
if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
return_trace (false); return_trace (false);
if (unlikely (!c->check_array (&states[min_state * num_classes], -min_state, row_stride))) if (unlikely (!c->check_range (&states[min_state * num_classes],
-min_state,
row_stride)))
return_trace (false); return_trace (false);
if ((c->max_ops -= state_neg - min_state) < 0) if ((c->max_ops -= state_neg - min_state) < 0)
return_trace (false); return_trace (false);
@ -574,7 +576,9 @@ struct StateTable
if (state_pos <= max_state) if (state_pos <= max_state)
{ {
/* Positive states. */ /* Positive states. */
if (unlikely (!c->check_array (states, max_state + 1, row_stride))) if (unlikely (!c->check_range (states,
max_state + 1,
row_stride)))
return_trace (false); return_trace (false);
if ((c->max_ops -= max_state - state_pos + 1) < 0) if ((c->max_ops -= max_state - state_pos + 1) < 0)
return_trace (false); return_trace (false);

View File

@ -260,14 +260,14 @@ struct KerxSubTableFormat1
depth = 0; /* Probably not what CoreText does, but better? */ depth = 0; /* Probably not what CoreText does, but better? */
} }
if (Format1EntryT::performAction (entry)) if (Format1EntryT::performAction (entry) && depth)
{ {
unsigned int tuple_count = MAX (1u, table->header.tuple_count ()); unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
const FWORD *actions = &kernAction[kern_idx]; const FWORD *actions = &kernAction[kern_idx];
if (!c->sanitizer.check_array (actions, depth * tuple_count)) if (!c->sanitizer.check_array (actions, depth, tuple_count))
{ {
depth = 0; depth = 0;
return false; return false;
@ -279,9 +279,9 @@ struct KerxSubTableFormat1
* "Each pops one glyph from the kerning stack and applies the kerning value to it. * "Each pops one glyph from the kerning stack and applies the kerning value to it.
* The end of the list is marked by an odd value... */ * The end of the list is marked by an odd value... */
bool last = false; bool last = false;
while (!last && depth--) while (!last && depth)
{ {
unsigned int idx = stack[depth]; unsigned int idx = stack[--depth];
int v = *actions; int v = *actions;
actions += tuple_count; actions += tuple_count;
if (idx >= buffer->len) continue; if (idx >= buffer->len) continue;

View File

@ -49,7 +49,8 @@ struct lcar
unsigned int *caret_count /* IN/OUT */, unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const hb_position_t *caret_array /* OUT */) const
{ {
const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph, font->face->num_glyphs); const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
font->face->get_num_glyphs ());
const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry); const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
if (caret_count && *caret_count) if (caret_count && *caret_count)
{ {

View File

@ -51,9 +51,7 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
} }
void void
hb_aat_map_builder_t::compile (hb_aat_map_t &m, hb_aat_map_builder_t::compile (hb_aat_map_t &m)
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{ {
/* Sort features and merge duplicates */ /* Sort features and merge duplicates */
if (features.len) if (features.len)

View File

@ -60,9 +60,7 @@ struct hb_aat_map_builder_t
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
HB_INTERNAL void compile (hb_aat_map_t &m, HB_INTERNAL void compile (hb_aat_map_t &m);
const int *coords,
unsigned int num_coords);
public: public:
struct feature_info_t struct feature_info_t

View File

@ -100,7 +100,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) #define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) #elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h> #include <windows.h>
@ -257,24 +257,24 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
#endif #endif
#ifndef hb_atomic_int_impl_get #ifndef hb_atomic_int_impl_get
inline int hb_atomic_int_impl_get (int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
#endif #endif
#ifndef hb_atomic_ptr_impl_get #ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; } inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif #endif
#define HB_ATOMIC_INT_INIT(V) {V} #define HB_ATOMIC_INT_INIT(V) {V}
struct hb_atomic_int_t struct hb_atomic_int_t
{ {
inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); } inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); } inline void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); } inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); }
inline int get (void) const { return hb_atomic_int_impl_get (&v); } inline int get (void) const { return hb_atomic_int_impl_get (&v); }
inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); } inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); }
inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); } inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); }
mutable int v; int v;
}; };
@ -285,7 +285,7 @@ struct hb_atomic_ptr_t
typedef typename hb_remove_pointer<P>::value T; typedef typename hb_remove_pointer<P>::value T;
inline void init (T* v_ = nullptr) { set_relaxed (v_); } inline void init (T* v_ = nullptr) { set_relaxed (v_); }
inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); } inline void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
inline T *get_relaxed (void) const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } inline T *get_relaxed (void) const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
@ -293,7 +293,7 @@ struct hb_atomic_ptr_t
inline T * operator -> (void) const { return get (); } inline T * operator -> (void) const { return get (); }
template <typename C> inline operator C * (void) const { return get (); } template <typename C> inline operator C * (void) const { return get (); }
mutable T *v; T *v;
}; };

View File

@ -481,7 +481,7 @@ hb_blob_t::try_make_writable (void)
# include <fcntl.h> # include <fcntl.h>
#endif #endif
#if defined(_WIN32) || defined(__CYGWIN__) #ifdef _WIN32
# include <windows.h> # include <windows.h>
#else #else
# ifndef O_BINARY # ifndef O_BINARY
@ -497,19 +497,19 @@ struct hb_mapped_file_t
{ {
char *contents; char *contents;
unsigned long length; unsigned long length;
#if defined(_WIN32) || defined(__CYGWIN__) #ifdef _WIN32
HANDLE mapping; HANDLE mapping;
#endif #endif
}; };
#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) #if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP)
static void static void
_hb_mapped_file_destroy (void *file_) _hb_mapped_file_destroy (void *file_)
{ {
hb_mapped_file_t *file = (hb_mapped_file_t *) file_; hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
munmap (file->contents, file->length); munmap (file->contents, file->length);
#elif defined(_WIN32) || defined(__CYGWIN__) #elif defined(_WIN32)
UnmapViewOfFile (file->contents); UnmapViewOfFile (file->contents);
CloseHandle (file->mapping); CloseHandle (file->mapping);
#else #else
@ -560,7 +560,7 @@ fail:
fail_without_close: fail_without_close:
free (file); free (file);
#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP) #elif defined(_WIN32) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t)); hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty (); if (unlikely (!file)) return hb_blob_get_empty ();

View File

@ -264,6 +264,17 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */ /* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline int
hb_memcmp (const void *a, const void *b, unsigned int len)
{
/* It's illegal to pass NULL to memcmp(), even if len is zero.
* So, wrap it.
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
if (!len) return 0;
return memcmp (a, b, len);
}
static inline bool static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size) hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
{ {
@ -535,11 +546,7 @@ struct hb_bytes_t
{ {
if (len != a.len) if (len != a.len)
return (int) a.len - (int) len; return (int) a.len - (int) len;
return hb_memcmp (a.arrayZ, arrayZ, len);
if (!len)
return 0; /* glibc's memcmp() declares args non-NULL, and UBSan doesn't like that. :( */
return memcmp (a.arrayZ, arrayZ, len);
} }
static inline int cmp (const void *pa, const void *pb) static inline int cmp (const void *pa, const void *pb)
{ {

View File

@ -87,8 +87,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
nullptr, /* destroy */ nullptr, /* destroy */
0, /* index */ 0, /* index */
1000, /* upem */ HB_ATOMIC_INT_INIT (1000), /* upem */
0, /* num_glyphs */ HB_ATOMIC_INT_INIT (0), /* num_glyphs */
{ {
#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID), #define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
@ -129,7 +129,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
face->user_data = user_data; face->user_data = user_data;
face->destroy = destroy; face->destroy = destroy;
face->num_glyphs = (unsigned int) -1; face->num_glyphs.set_relaxed (-1);
face->table.init0 (face); face->table.init0 (face);
@ -445,7 +445,7 @@ hb_face_set_upem (hb_face_t *face,
if (hb_object_is_immutable (face)) if (hb_object_is_immutable (face))
return; return;
face->upem = upem; face->upem.set_relaxed (upem);
} }
/** /**
@ -480,7 +480,7 @@ hb_face_set_glyph_count (hb_face_t *face,
if (hb_object_is_immutable (face)) if (hb_object_is_immutable (face))
return; return;
face->num_glyphs = glyph_count; face->num_glyphs.set_relaxed (glyph_count);
} }
/** /**

View File

@ -49,8 +49,8 @@ struct hb_face_t
hb_destroy_func_t destroy; hb_destroy_func_t destroy;
unsigned int index; /* Face index in a collection, zero-based. */ unsigned int index; /* Face index in a collection, zero-based. */
mutable unsigned int upem; /* Units-per-EM. */ mutable hb_atomic_int_t upem; /* Units-per-EM. */
mutable unsigned int num_glyphs; /* Number of glyphs. */ mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
struct hb_shaper_data_t shaper_data; /* Various shaper data. */ struct hb_shaper_data_t shaper_data; /* Various shaper data. */
@ -80,21 +80,25 @@ struct hb_face_t
inline HB_PURE_FUNC unsigned int get_upem (void) const inline HB_PURE_FUNC unsigned int get_upem (void) const
{ {
if (unlikely (!upem)) unsigned int ret = upem.get_relaxed ();
load_upem (); if (unlikely (!ret))
return upem; {
return load_upem ();
}
return ret;
} }
inline unsigned int get_num_glyphs (void) const inline unsigned int get_num_glyphs (void) const
{ {
if (unlikely (num_glyphs == (unsigned int) -1)) unsigned int ret = num_glyphs.get_relaxed ();
load_num_glyphs (); if (unlikely (ret == (unsigned int) -1))
return num_glyphs; return load_num_glyphs ();
return ret;
} }
private: private:
HB_INTERNAL void load_upem (void) const; HB_INTERNAL unsigned int load_upem (void) const;
HB_INTERNAL void load_num_glyphs (void) const; HB_INTERNAL unsigned int load_num_glyphs (void) const;
}; };
DECLARE_NULL_INSTANCE (hb_face_t); DECLARE_NULL_INSTANCE (hb_face_t);

View File

@ -298,7 +298,8 @@ struct hb_sanitize_context_t :
this->start = this->end = nullptr; this->start = this->end = nullptr;
} }
inline bool check_range (const void *base, unsigned int len) const inline bool check_range (const void *base,
unsigned int len) const
{ {
const char *p = (const char *) base; const char *p = (const char *) base;
bool ok = this->start <= p && bool ok = this->start <= p &&
@ -316,20 +317,37 @@ struct hb_sanitize_context_t :
} }
template <typename T> template <typename T>
inline bool check_array (const T *base, unsigned int len, unsigned int record_size = T::static_size) const inline bool check_range (const T *base,
unsigned int a,
unsigned int b) const
{ {
const char *p = (const char *) base; return !hb_unsigned_mul_overflows (a, b) &&
bool overflows = hb_unsigned_mul_overflows (len, record_size); this->check_range (base, a * b);
unsigned int array_size = record_size * len; }
bool ok = !overflows && this->check_range (base, array_size);
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, template <typename T>
"check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s", inline bool check_range (const T *base,
p, p + (record_size * len), record_size, len, (unsigned int) array_size, unsigned int a,
this->start, this->end, unsigned int b,
overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE"); unsigned int c) const
{
return !hb_unsigned_mul_overflows (a, b) &&
this->check_range (base, a * b, c);
}
return likely (ok); template <typename T>
inline bool check_array (const T *base,
unsigned int len) const
{
return this->check_range (base, len, T::static_size);
}
template <typename T>
inline bool check_array (const T *base,
unsigned int a,
unsigned int b) const
{
return this->check_range (base, a, b, T::static_size);
} }
template <typename Type> template <typename Type>
@ -734,16 +752,19 @@ struct hb_data_wrapper_t
return *(((Data **) (void *) this) - WheresData); return *(((Data **) (void *) this) - WheresData);
} }
inline bool is_inert (void) const { return !get_data (); }
template <typename Stored, typename Subclass> template <typename Stored, typename Subclass>
inline Stored * call_create (void) const inline Stored * call_create (void) const
{ {
Data *data = this->get_data (); return Subclass::create (this->get_data ());
return likely (data) ? Subclass::create (data) : nullptr;
} }
}; };
template <> template <>
struct hb_data_wrapper_t<void, 0> struct hb_data_wrapper_t<void, 0>
{ {
inline bool is_inert (void) const { return false; }
template <typename Stored, typename Funcs> template <typename Stored, typename Funcs>
inline Stored * call_create (void) const inline Stored * call_create (void) const
{ {
@ -782,7 +803,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
static inline void do_destroy (Stored *p) static inline void do_destroy (Stored *p)
{ {
if (p) if (p && p != const_cast<Stored *> (Funcs::get_null ()))
Funcs::destroy (p); Funcs::destroy (p);
} }
@ -796,9 +817,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
Stored *p = this->instance.get (); Stored *p = this->instance.get ();
if (unlikely (!p)) if (unlikely (!p))
{ {
if (unlikely (this->is_inert ()))
return const_cast<Stored *> (Funcs::get_null ());
p = this->template call_create<Stored, Funcs> (); p = this->template call_create<Stored, Funcs> ();
if (unlikely (!p)) if (unlikely (!p))
return const_cast<Stored *> (Funcs::get_null ()); p = const_cast<Stored *> (Funcs::get_null ());
if (unlikely (!this->instance.cmpexch (nullptr, p))) if (unlikely (!this->instance.cmpexch (nullptr, p)))
{ {

View File

@ -48,7 +48,7 @@
/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) #elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h> #include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t; typedef CRITICAL_SECTION hb_mutex_impl_t;

View File

@ -194,7 +194,7 @@ struct hb_user_data_array_t
struct hb_object_header_t struct hb_object_header_t
{ {
hb_reference_count_t ref_count; hb_reference_count_t ref_count;
hb_atomic_int_t writable; mutable hb_atomic_int_t writable;
hb_atomic_ptr_t<hb_user_data_array_t> user_data; hb_atomic_ptr_t<hb_user_data_array_t> user_data;
}; };
#define HB_OBJECT_HEADER_STATIC \ #define HB_OBJECT_HEADER_STATIC \

View File

@ -887,7 +887,9 @@ struct VarSizedBinSearchArrayOf
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (header.sanitize (c) && return_trace (header.sanitize (c) &&
Type::static_size <= header.unitSize && Type::static_size <= header.unitSize &&
c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize)); c->check_range (bytesZ.arrayZ,
header.nUnits,
header.unitSize));
} }
protected: protected:

View File

@ -91,7 +91,7 @@ struct CFFIndex
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */ return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
(c->check_struct (this) && offSize >= 1 && offSize <= 4 && (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1) && c->check_array (offsets, offSize, count + 1) &&
c->check_array (data_base (), 1, max_offset () - 1)))); c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
} }
inline static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) inline static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)

View File

@ -249,7 +249,7 @@ struct sbix
/* Convert to font units. */ /* Convert to font units. */
if (strike_ppem) if (strike_ppem)
{ {
double scale = font->face->upem / (double) strike_ppem; double scale = font->face->get_upem () / (double) strike_ppem;
extents->x_bearing = round (extents->x_bearing * scale); extents->x_bearing = round (extents->x_bearing * scale);
extents->y_bearing = round (extents->y_bearing * scale); extents->y_bearing = round (extents->y_bearing * scale);
extents->width = round (extents->width * scale); extents->width = round (extents->width * scale);

View File

@ -238,7 +238,7 @@ hb_ot_color_has_svg (hb_face_t *face)
* @face: a font face. * @face: a font face.
* @glyph: a svg glyph index. * @glyph: a svg glyph index.
* *
* Get SVG document for a glyph. * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded.
* *
* Returns: (transfer full): respective svg blob of the glyph, if available. * Returns: (transfer full): respective svg blob of the glyph, if available.
* *

View File

@ -40,6 +40,7 @@
#define HB_OT_TABLES \ #define HB_OT_TABLES \
/* OpenType fundamentals. */ \ /* OpenType fundamentals. */ \
HB_OT_TABLE(OT, head) \
HB_OT_ACCELERATOR(OT, cmap) \ HB_OT_ACCELERATOR(OT, cmap) \
HB_OT_ACCELERATOR(OT, hmtx) \ HB_OT_ACCELERATOR(OT, hmtx) \
HB_OT_ACCELERATOR(OT, vmtx) \ HB_OT_ACCELERATOR(OT, vmtx) \
@ -50,6 +51,8 @@
HB_OT_ACCELERATOR(OT, cff2) \ HB_OT_ACCELERATOR(OT, cff2) \
HB_OT_TABLE(OT, VORG) \ HB_OT_TABLE(OT, VORG) \
HB_OT_ACCELERATOR(OT, name) \ HB_OT_ACCELERATOR(OT, name) \
HB_OT_TABLE(OT, OS2) \
HB_OT_TABLE(OT, STAT) \
/* OpenType shaping. */ \ /* OpenType shaping. */ \
HB_OT_ACCELERATOR(OT, GDEF) \ HB_OT_ACCELERATOR(OT, GDEF) \
HB_OT_ACCELERATOR(OT, GSUB) \ HB_OT_ACCELERATOR(OT, GSUB) \

View File

@ -33,12 +33,14 @@
#include "hb-ot-face.hh" #include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh" #include "hb-ot-cmap-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-glyf-table.hh" #include "hb-ot-glyf-table.hh"
#include "hb-ot-cff1-table.hh" #include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh" #include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-vorg-table.hh" #include "hb-ot-vorg-table.hh"
#include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-sbix-table.hh" #include "hb-ot-color-sbix-table.hh"

View File

@ -235,16 +235,11 @@ struct glyf
{ {
memset (this, 0, sizeof (accelerator_t)); memset (this, 0, sizeof (accelerator_t));
hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (face); const OT::head &head = *face->table.head;
const head *head_table = head_blob->as<head> (); if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0)
if (head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
{
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
hb_blob_destroy (head_blob);
return; return;
} short_offset = 0 == head.indexToLocFormat;
short_offset = 0 == head_table->indexToLocFormat;
hb_blob_destroy (head_blob);
loca_table = hb_sanitize_context_t().reference_table<loca> (face); loca_table = hb_sanitize_context_t().reference_table<loca> (face);
glyf_table = hb_sanitize_context_t().reference_table<glyf> (face); glyf_table = hb_sanitize_context_t().reference_table<glyf> (face);

View File

@ -194,17 +194,14 @@ struct hmtxvmtx
bool got_font_extents = false; bool got_font_extents = false;
if (T::os2Tag) if (T::os2Tag)
{ {
hb_blob_t *os2_blob = hb_sanitize_context_t().reference_table<OS2> (face);
const OS2 *os2_table = os2_blob->as<OS2> ();
#define USE_TYPO_METRICS (1u<<7) #define USE_TYPO_METRICS (1u<<7)
if (0 != (os2_table->fsSelection & USE_TYPO_METRICS)) if (0 != (face->table.OS2->fsSelection & USE_TYPO_METRICS))
{ {
ascender = abs (os2_table->sTypoAscender); ascender = abs (face->table.OS2->sTypoAscender);
descender = -abs (os2_table->sTypoDescender); descender = -abs (face->table.OS2->sTypoDescender);
line_gap = os2_table->sTypoLineGap; line_gap = face->table.OS2->sTypoLineGap;
got_font_extents = (ascender | descender) != 0; got_font_extents = (ascender | descender) != 0;
} }
hb_blob_destroy (os2_blob);
} }
hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face); hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face);
@ -289,9 +286,9 @@ struct hmtxvmtx
public: public:
bool has_font_extents; bool has_font_extents;
unsigned short ascender; int ascender;
unsigned short descender; int descender;
unsigned short line_gap; int line_gap;
protected: protected:
unsigned int num_metrics; unsigned int num_metrics;

View File

@ -1584,8 +1584,9 @@ struct VarData
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
regionIndices.sanitize(c) && regionIndices.sanitize(c) &&
shortCount <= regionIndices.len && shortCount <= regionIndices.len &&
c->check_array (&StructAfter<HBUINT8> (regionIndices), c->check_range (&StructAfter<HBUINT8> (regionIndices),
itemCount, get_row_size ())); itemCount,
get_row_size ()));
} }
protected: protected:

View File

@ -207,7 +207,7 @@ struct ValueFormat : HBUINT16
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
unsigned int len = get_len (); unsigned int len = get_len ();
if (!c->check_array (values, count, get_size ())) return_trace (false); if (!c->check_range (values, count, get_size ())) return_trace (false);
if (!has_device ()) return_trace (true); if (!has_device ()) return_trace (true);
@ -706,7 +706,10 @@ struct PairSet
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (!(c->check_struct (this) if (!(c->check_struct (this)
&& c->check_array (&firstPairValueRecord, len, HBUINT16::static_size * closure->stride))) return_trace (false); && c->check_range (&firstPairValueRecord,
len,
HBUINT16::static_size,
closure->stride))) return_trace (false);
unsigned int count = len; unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord; const PairValueRecord *record = &firstPairValueRecord;
@ -879,7 +882,9 @@ struct PairPosFormat2
unsigned int stride = len1 + len2; unsigned int stride = len1 + len2;
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_array ((const void *) values, count, record_size) && return_trace (c->check_range ((const void *) values,
count,
record_size) &&
valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
} }

View File

@ -27,7 +27,7 @@
*/ */
#include "hb-ot-map.hh" #include "hb-ot-map.hh"
#include "hb-ot-shape.hh"
#include "hb-ot-layout.hh" #include "hb-ot-layout.hh"
@ -144,8 +144,7 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus
void void
hb_ot_map_builder_t::compile (hb_ot_map_t &m, hb_ot_map_builder_t::compile (hb_ot_map_t &m,
const int *coords, const hb_ot_shape_plan_key_t &key)
unsigned int num_coords)
{ {
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), ""); static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1; unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
@ -282,13 +281,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
{ {
/* Collect lookup indices for features */ /* Collect lookup indices for features */
unsigned int variations_index;
hb_ot_layout_table_find_feature_variations (face,
table_tags[table_index],
coords,
num_coords,
&variations_index);
unsigned int stage_index = 0; unsigned int stage_index = 0;
unsigned int last_num_lookups = 0; unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++) for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
@ -297,14 +289,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
required_feature_stage[table_index] == stage) required_feature_stage[table_index] == stage)
add_lookups (m, table_index, add_lookups (m, table_index,
required_feature_index[table_index], required_feature_index[table_index],
variations_index, key.variations_index[table_index],
global_bit_mask); global_bit_mask);
for (unsigned i = 0; i < m.features.len; i++) for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage) if (m.features[i].stage[table_index] == stage)
add_lookups (m, table_index, add_lookups (m, table_index,
m.features[i].index[table_index], m.features[i].index[table_index],
variations_index, key.variations_index[table_index],
m.features[i].mask, m.features[i].mask,
m.features[i].auto_zwnj, m.features[i].auto_zwnj,
m.features[i].auto_zwj, m.features[i].auto_zwj,

View File

@ -188,6 +188,7 @@ struct hb_ot_map_feature_t
hb_ot_map_feature_flags_t flags; hb_ot_map_feature_flags_t flags;
}; };
struct hb_ot_shape_plan_key_t;
struct hb_ot_map_builder_t struct hb_ot_map_builder_t
{ {
@ -219,8 +220,7 @@ struct hb_ot_map_builder_t
{ add_pause (1, pause_func); } { add_pause (1, pause_func); }
HB_INTERNAL void compile (hb_ot_map_t &m, HB_INTERNAL void compile (hb_ot_map_t &m,
const int *coords, const hb_ot_shape_plan_key_t &key);
unsigned int num_coords);
private: private:

View File

@ -202,7 +202,7 @@ struct arabic_fallback_plan_t
OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
}; };
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256) #if defined(_WIN32) && !defined(HB_NO_WIN1256)
#define HB_WITH_WIN1256 #define HB_WITH_WIN1256
#endif #endif

View File

@ -582,7 +582,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst,
/* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, H, O, O, /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, HVM, O, O,
/* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B, /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B,
/* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
/* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O, /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,

View File

@ -53,7 +53,6 @@
static void static void
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
const hb_segment_properties_t *props,
const hb_feature_t *user_features, const hb_feature_t *user_features,
unsigned int num_user_features); unsigned int num_user_features);
@ -68,11 +67,12 @@ _hb_apply_morx (hb_face_t *face)
hb_aat_layout_has_substitution (face); hb_aat_layout_has_substitution (face);
} }
hb_ot_shape_planner_t::hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) : hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face,
face (master_plan->face_unsafe), const hb_segment_properties_t *props) :
props (master_plan->props), face (face),
map (face, &props), props (*props),
aat_map (face, &props), map (face, props),
aat_map (face, props),
apply_morx (_hb_apply_morx (face)), apply_morx (_hb_apply_morx (face)),
shaper (apply_morx ? shaper (apply_morx ?
&_hb_ot_complex_shaper_default : &_hb_ot_complex_shaper_default :
@ -80,14 +80,13 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan
void void
hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
const int *coords, const hb_ot_shape_plan_key_t &key)
unsigned int num_coords)
{ {
plan.props = props; plan.props = props;
plan.shaper = shaper; plan.shaper = shaper;
map.compile (plan.map, coords, num_coords); map.compile (plan.map, key);
if (apply_morx) if (apply_morx)
aat_map.compile (plan.aat_map, coords, num_coords); aat_map.compile (plan.aat_map);
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
@ -139,30 +138,28 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
} }
bool has_kern_mark = plan.apply_kern && hb_ot_layout_has_cross_kerning (face); bool has_kern_mark = plan.apply_kern && hb_ot_layout_has_cross_kerning (face);
plan.zero_marks = !plan.apply_kerx && !has_kern_mark; plan.zero_marks = !plan.apply_morx && !plan.apply_kerx && !has_kern_mark;
plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
plan.fallback_mark_positioning = !plan.apply_gpos && !plan.apply_kerx && !has_kern_mark; plan.fallback_mark_positioning = !plan.apply_gpos && plan.zero_marks;
/* Currently we always apply trak. */ /* Currently we always apply trak. */
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face); plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
} }
bool bool
hb_ot_shape_plan_t::init0 (hb_shape_plan_t *shape_plan, hb_ot_shape_plan_t::init0 (hb_face_t *face,
const hb_feature_t *user_features, const hb_shape_plan_key_t *key)
unsigned int num_user_features,
const int *coords,
unsigned int num_coords)
{ {
map.init (); map.init ();
aat_map.init (); aat_map.init ();
hb_ot_shape_planner_t planner (shape_plan); hb_ot_shape_planner_t planner (face,
&key->props);
hb_ot_shape_collect_features (&planner,
key->user_features,
key->num_user_features);
hb_ot_shape_collect_features (&planner, &shape_plan->props, planner.compile (*this, key->ot);
user_features, num_user_features);
planner.compile (*this, coords, num_coords);
if (shaper->data_create) if (shaper->data_create)
{ {
@ -209,7 +206,6 @@ horizontal_features[] =
static void static void
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
const hb_segment_properties_t *props,
const hb_feature_t *user_features, const hb_feature_t *user_features,
unsigned int num_user_features) unsigned int num_user_features)
{ {
@ -218,7 +214,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG('r','v','r','n')); map->enable_feature (HB_TAG('r','v','r','n'));
map->add_gsub_pause (nullptr); map->add_gsub_pause (nullptr);
switch (props->direction) { switch (planner->props.direction) {
case HB_DIRECTION_LTR: case HB_DIRECTION_LTR:
map->enable_feature (HB_TAG ('l','t','r','a')); map->enable_feature (HB_TAG ('l','t','r','a'));
map->enable_feature (HB_TAG ('l','t','r','m')); map->enable_feature (HB_TAG ('l','t','r','m'));
@ -257,7 +253,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
map->add_feature (common_features[i]); map->add_feature (common_features[i]);
if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) if (HB_DIRECTION_IS_HORIZONTAL (planner->props.direction))
for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
map->add_feature (horizontal_features[i]); map->add_feature (horizontal_features[i]);
else else

View File

@ -33,6 +33,31 @@
#include "hb-aat-map.hh" #include "hb-aat-map.hh"
struct hb_ot_shape_plan_key_t
{
unsigned int variations_index[2];
inline void init (hb_face_t *face,
const int *coords,
unsigned int num_coords)
{
for (unsigned int table_index = 0; table_index < 2; table_index++)
hb_ot_layout_table_find_feature_variations (face,
table_tags[table_index],
coords,
num_coords,
&variations_index[table_index]);
}
inline bool equal (const hb_ot_shape_plan_key_t *other)
{
return 0 == memcmp (this, other, sizeof (*this));
}
};
struct hb_shape_plan_key_t;
struct hb_ot_shape_plan_t struct hb_ot_shape_plan_t
{ {
hb_segment_properties_t props; hb_segment_properties_t props;
@ -73,12 +98,8 @@ struct hb_ot_shape_plan_t
inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); } inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); } inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
HB_INTERNAL bool init0 (hb_shape_plan_t *shape_plan, HB_INTERNAL bool init0 (hb_face_t *face,
const hb_feature_t *user_features, const hb_shape_plan_key_t *key);
unsigned int num_user_features,
const int *coords,
unsigned int num_coords);
HB_INTERNAL void fini (void); HB_INTERNAL void fini (void);
}; };
@ -94,11 +115,11 @@ struct hb_ot_shape_planner_t
bool apply_morx : 1; bool apply_morx : 1;
const struct hb_ot_complex_shaper_t *shaper; const struct hb_ot_complex_shaper_t *shaper;
HB_INTERNAL hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan); HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face,
const hb_segment_properties_t *props);
HB_INTERNAL void compile (hb_ot_shape_plan_t &plan, HB_INTERNAL void compile (hb_ot_shape_plan_t &plan,
const int *coords, const hb_ot_shape_plan_key_t &key);
unsigned int num_coords);
}; };

280
src/hb-ot-stat-table.hh Normal file
View File

@ -0,0 +1,280 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_OT_STAT_TABLE_HH
#define HB_OT_STAT_TABLE_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
/*
* STAT -- Style Attributes
* https://docs.microsoft.com/en-us/typography/opentype/spec/stat
*/
#define HB_OT_TAG_STAT HB_TAG('S','T','A','T')
namespace OT {
enum
{
OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001, /* If set, this axis value table
* provides axis value information
* that is applicable to other fonts
* within the same font family. This
* is used if the other fonts were
* released earlier and did not include
* information about values for some axis.
* If newer versions of the other
* fonts include the information
* themselves and are present,
* then this record is ignored. */
ELIDABLE_AXIS_VALUE_NAME = 0x0002 /* If set, it indicates that the axis
* value represents the normal value
* for the axis and may be omitted when
* composing name strings. */
// Reserved = 0xFFFC /* Reserved for future use — set to zero. */
};
struct StatAxisRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
Tag axisTag; /* A tag identifying the axis of design variation. */
NameID axisNameID; /* The name ID for entries in the 'name' table that
* provide a display string for this axis. */
HBUINT16 axisOrdering; /* A value that applications can use to determine
* primary sorting of face names, or for ordering
* of descriptors when composing family or face names. */
public:
DEFINE_SIZE_STATIC (8);
};
struct AxisValueFormat1
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 format; /* Format identifier — set to 1. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis of design variation
* to which the axis value record applies.
* Must be less than designAxisCount. */
HBUINT16 flags; /* Flags — see below for details. */
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
Fixed value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (12);
};
struct AxisValueFormat2
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 format; /* Format identifier — set to 2. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis of design variation
* to which the axis value record applies.
* Must be less than designAxisCount. */
HBUINT16 flags; /* Flags — see below for details. */
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
Fixed nominalValue; /* A numeric value for this attribute value. */
Fixed rangeMinValue; /* The minimum value for a range associated
* with the specified name ID. */
Fixed rangeMaxValue; /* The maximum value for a range associated
* with the specified name ID. */
public:
DEFINE_SIZE_STATIC (20);
};
struct AxisValueFormat3
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 format; /* Format identifier — set to 3. */
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis of design variation
* to which the axis value record applies.
* Must be less than designAxisCount. */
HBUINT16 flags; /* Flags — see below for details. */
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
Fixed value; /* A numeric value for this attribute value. */
Fixed linkedValue; /* The numeric value for a style-linked mapping
* from this value. */
public:
DEFINE_SIZE_STATIC (16);
};
struct AxisValueRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis to which this value
* applies. Must be less than designAxisCount. */
Fixed value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (6);
};
struct AxisValueFormat4
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT16 format; /* Format identifier — set to 4. */
HBUINT16 axisCount; /* The total number of axes contributing to
* this axis-values combination. */
HBUINT16 flags; /* Flags — see below for details. */
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
UnsizedArrayOf<AxisValueRecord>
axisValues; /* Array of AxisValue records that provide the
* combination of axis values, one for each
* contributing axis. */
public:
DEFINE_SIZE_ARRAY (8, axisValues);
};
struct AxisValue
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (c->check_struct (this)))
return_trace (false);
switch (u.format)
{
case 1: return_trace (likely (u.format1.sanitize (c)));
case 2: return_trace (likely (u.format2.sanitize (c)));
case 3: return_trace (likely (u.format3.sanitize (c)));
case 4: return_trace (likely (u.format4.sanitize (c)));
default: return_trace (true);
}
}
protected:
union
{
HBUINT16 format;
AxisValueFormat1 format1;
AxisValueFormat2 format2;
AxisValueFormat3 format3;
AxisValueFormat4 format4;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct STAT
{
static const hb_tag_t tableTag = HB_OT_TAG_STAT;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
majorVersion == 1 &&
minorVersion > 0 &&
designAxesOffset.sanitize (c, this, designAxisCount) &&
offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
}
protected:
HBUINT16 majorVersion; /* Major version number of the style attributes
* table set to 1. */
HBUINT16 minorVersion; /* Minor version number of the style attributes
* table set to 2. */
HBUINT16 designAxisSize; /* The size in bytes of each axis record. */
HBUINT16 designAxisCount;/* The number of design axis records. In a
* font with an 'fvar' table, this value must be
* greater than or equal to the axisCount value
* in the 'fvar' table. In all fonts, must
* be greater than zero if axisValueCount
* is greater than zero. */
LOffsetTo<UnsizedArrayOf<StatAxisRecord>, false>
designAxesOffset;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design
* axes array. If designAxisCount is zero,
* set to zero; if designAxisCount is greater
* than zero, must be greater than zero. */
HBUINT16 axisValueCount; /* The number of axis value tables. */
LOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue> >, false>
offsetToAxisValueOffsets;
/* Offset in bytes from the beginning of
* the STAT table to the start of the design
* axes value offsets array. If axisValueCount
* is zero, set to zero; if axisValueCount is
* greater than zero, must be greater than zero. */
NameID elidedFallbackNameID;
/* Name ID used as fallback when projection of
* names into a particular font model produces
* a subfamily name containing only elidable
* elements. */
public:
DEFINE_SIZE_STATIC (20);
};
} /* namespace OT */
#endif /* HB_OT_STAT_TABLE_HH */

View File

@ -39,7 +39,9 @@ struct DeltaSetIndexMap
{ {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && return_trace (c->check_struct (this) &&
c->check_array (mapDataZ.arrayZ, mapCount, get_width ())); c->check_range (mapDataZ.arrayZ,
mapCount,
get_width ()));
} }
unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */

View File

@ -68,7 +68,9 @@ struct MVAR
c->check_struct (this) && c->check_struct (this) &&
valueRecordSize >= VariationValueRecord::static_size && valueRecordSize >= VariationValueRecord::static_size &&
varStore.sanitize (c, this) && varStore.sanitize (c, this) &&
c->check_array (valuesZ.arrayZ, valueRecordCount, valueRecordSize)); c->check_range (valuesZ.arrayZ,
valueRecordCount,
valueRecordSize));
} }
inline float get_var (hb_tag_t tag, inline float get_var (hb_tag_t tag,

View File

@ -90,7 +90,7 @@ struct hb_set_t
inline bool is_equal (const page_t *other) const inline bool is_equal (const page_t *other) const
{ {
return 0 == memcmp (&v, &other->v, sizeof (v)); return 0 == hb_memcmp (&v, &other->v, sizeof (v));
} }
inline unsigned int get_population (void) const inline unsigned int get_population (void) const

View File

@ -44,42 +44,59 @@
**/ **/
static void /*
hb_shape_plan_plan (hb_shape_plan_t *shape_plan, * hb_shape_plan_key_t
*/
bool
hb_shape_plan_key_t::init (bool copy,
hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features, const hb_feature_t *user_features,
unsigned int num_user_features, unsigned int num_user_features,
const int *coords, const int *coords,
unsigned int num_coords, unsigned int num_coords,
const char * const *shaper_list) const char * const *shaper_list)
{ {
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, hb_feature_t *features = nullptr;
"num_features=%d num_coords=%d shaper_list=%p", if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
num_user_features, goto bail;
num_coords,
shaper_list);
const hb_shaper_pair_t *shapers = _hb_shapers_get (); this->props = *props;
this->num_user_features = num_user_features;
this->user_features = copy ? features : user_features;
if (copy && num_user_features)
{
memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
/* Make start/end uniform to easier catch bugs. */
for (unsigned int i = 0; i < num_user_features; i++)
{
if (features[0].start != HB_FEATURE_GLOBAL_START)
features[0].start = 1;
if (features[0].end != HB_FEATURE_GLOBAL_END)
features[0].end = 2;
}
}
this->shaper_func = nullptr;
this->shaper_name = nullptr;
this->ot.init (face, coords, num_coords);
/*
* Choose shaper.
*/
#define HB_SHAPER_PLAN(shaper) \ #define HB_SHAPER_PLAN(shaper) \
HB_STMT_START { \ HB_STMT_START { \
if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) \ if (hb_##shaper##_shaper_face_data_ensure (face)) \
{ \ { \
shape_plan->shaper_func = _hb_##shaper##_shape; \ this->shaper_func = _hb_##shaper##_shape; \
shape_plan->shaper_name = #shaper; \ this->shaper_name = #shaper; \
return; \ return true; \
} \ } \
} HB_STMT_END } HB_STMT_END
if (likely (!shaper_list)) { if (unlikely (shaper_list))
for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++) {
if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (shapers[i].func == _hb_##shaper##_shape) \
HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
} else {
for (; *shaper_list; shaper_list++) for (; *shaper_list; shaper_list++)
if (false) if (false)
; ;
@ -89,8 +106,50 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT #undef HB_SHAPER_IMPLEMENT
} }
else
{
const hb_shaper_pair_static_t *shapers = _hb_shapers_get ();
for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (shapers[i].func == _hb_##shaper##_shape) \
HB_SHAPER_PLAN (shaper);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
}
#undef HB_SHAPER_PLAN #undef HB_SHAPER_PLAN
bail:
::free (features);
return false;
}
bool
hb_shape_plan_key_t::user_features_match (const hb_shape_plan_key_t *other)
{
if (this->num_user_features != other->num_user_features)
return false;
for (unsigned int i = 0; i < num_user_features; i++)
{
if (this->user_features[i].tag != other->user_features[i].tag ||
this->user_features[i].value != other->user_features[i].value ||
(this->user_features[i].start == HB_FEATURE_GLOBAL_START &&
this->user_features[i].end == HB_FEATURE_GLOBAL_END) !=
(other->user_features[i].start == HB_FEATURE_GLOBAL_START &&
other->user_features[i].end == HB_FEATURE_GLOBAL_END))
return false;
}
return true;
}
bool
hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other)
{
return hb_segment_properties_equal (&this->props, &other->props) &&
this->user_features_match (other) &&
this->ot.equal (&other->ot) &&
this->shaper_func == other->shaper_func;
} }
@ -131,7 +190,7 @@ hb_shape_plan_create2 (hb_face_t *face,
const hb_segment_properties_t *props, const hb_segment_properties_t *props,
const hb_feature_t *user_features, const hb_feature_t *user_features,
unsigned int num_user_features, unsigned int num_user_features,
const int *orig_coords, const int *coords,
unsigned int num_coords, unsigned int num_coords,
const char * const *shaper_list) const char * const *shaper_list)
{ {
@ -142,54 +201,39 @@ hb_shape_plan_create2 (hb_face_t *face,
num_coords, num_coords,
shaper_list); shaper_list);
assert (props->direction != HB_DIRECTION_INVALID);
hb_shape_plan_t *shape_plan; hb_shape_plan_t *shape_plan;
hb_feature_t *features = nullptr;
int *coords = nullptr;
if (unlikely (!props)) if (unlikely (!props))
goto bail; goto bail;
if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
goto bail;
if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
goto bail;
if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
goto bail; goto bail;
assert (props->direction != HB_DIRECTION_INVALID);
if (unlikely (!face)) if (unlikely (!face))
face = hb_face_get_empty (); face = hb_face_get_empty ();
hb_face_make_immutable (face); hb_face_make_immutable (face);
shape_plan->custom_shaper_list = shaper_list;
shape_plan->face_unsafe = face; shape_plan->face_unsafe = face;
shape_plan->props = *props;
shape_plan->num_user_features = num_user_features;
shape_plan->user_features = features;
if (num_user_features)
memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
shape_plan->num_coords = num_coords;
shape_plan->coords = coords;
if (num_coords)
memcpy (coords, orig_coords, num_coords * sizeof (int));
hb_shape_plan_plan (shape_plan, if (unlikely (!shape_plan->key.init (true,
user_features, num_user_features, face,
coords, num_coords, props,
shaper_list);
if (unlikely (!shape_plan->ot.init0 (shape_plan,
user_features, user_features,
num_user_features, num_user_features,
coords, coords,
num_coords))) num_coords,
goto bail; shaper_list)))
goto bail2;
if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
goto bail3;
return shape_plan; return shape_plan;
bail3:
shape_plan->key.free ();
bail2:
free (shape_plan);
bail: bail:
free (coords);
free (features);
return hb_shape_plan_get_empty (); return hb_shape_plan_get_empty ();
} }
@ -238,10 +282,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
if (!hb_object_destroy (shape_plan)) return; if (!hb_object_destroy (shape_plan)) return;
shape_plan->ot.fini (); shape_plan->ot.fini ();
shape_plan->key.free ();
free (shape_plan->user_features);
free (shape_plan->coords);
free (shape_plan); free (shape_plan);
} }
@ -287,6 +328,22 @@ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
return hb_object_get_user_data (shape_plan, key); return hb_object_get_user_data (shape_plan, key);
} }
/**
* hb_shape_plan_get_shaper:
* @shape_plan: a shape plan.
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.7
**/
const char *
hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
{
return shape_plan->key.shaper_name;
}
/** /**
* hb_shape_plan_execute: * hb_shape_plan_execute:
@ -312,8 +369,8 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
"num_features=%d shaper_func=%p, shaper_name=%s", "num_features=%d shaper_func=%p, shaper_name=%s",
num_features, num_features,
shape_plan->shaper_func, shape_plan->key.shaper_func,
shape_plan->shaper_name); shape_plan->key.shaper_name);
if (unlikely (!buffer->len)) if (unlikely (!buffer->len))
return true; return true;
@ -325,7 +382,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
return false; return false;
assert (shape_plan->face_unsafe == font->face); assert (shape_plan->face_unsafe == font->face);
assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); assert (hb_segment_properties_equal (&shape_plan->key.props, &buffer->props));
#define HB_SHAPER_EXECUTE(shaper) \ #define HB_SHAPER_EXECUTE(shaper) \
HB_STMT_START { \ HB_STMT_START { \
@ -336,7 +393,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
if (false) if (false)
; ;
#define HB_SHAPER_IMPLEMENT(shaper) \ #define HB_SHAPER_IMPLEMENT(shaper) \
else if (shape_plan->shaper_func == _hb_##shaper##_shape) \ else if (shape_plan->key.shaper_func == _hb_##shaper##_shape) \
HB_SHAPER_EXECUTE (shaper); HB_SHAPER_EXECUTE (shaper);
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT #undef HB_SHAPER_IMPLEMENT
@ -348,92 +405,9 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
/* /*
* caching * Caching
*/ */
#if 0
static unsigned int
hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
{
return hb_segment_properties_hash (&shape_plan->props) +
shape_plan->custom_shaper_list ? (intptr_t) shape_plan->shaper_func : 0;
}
#endif
/* User-feature caching is currently somewhat dumb:
* it only finds matches where the feature array is identical,
* not cases where the feature lists would be compatible for plan purposes
* but have different ranges, for example.
*/
struct hb_shape_plan_proposal_t
{
const hb_segment_properties_t props;
const char * const *shaper_list;
const hb_feature_t *user_features;
unsigned int num_user_features;
const int *coords;
unsigned int num_coords;
hb_shape_func_t *shaper_func;
};
static inline hb_bool_t
hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
if (proposal->num_user_features != shape_plan->num_user_features)
return false;
for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
proposal->user_features[i].value != shape_plan->user_features[i].value ||
proposal->user_features[i].start != shape_plan->user_features[i].start ||
proposal->user_features[i].end != shape_plan->user_features[i].end)
return false;
return true;
}
static inline hb_bool_t
hb_shape_plan_coords_match (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
if (proposal->num_coords != shape_plan->num_coords)
return false;
for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
if (proposal->coords[i] != shape_plan->coords[i])
return false;
return true;
}
static hb_bool_t
hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
hb_shape_plan_user_features_match (shape_plan, proposal) &&
hb_shape_plan_coords_match (shape_plan, proposal) &&
((!shape_plan->custom_shaper_list && !proposal->shaper_list) ||
(shape_plan->shaper_func == proposal->shaper_func));
}
static inline hb_bool_t
hb_non_global_user_features_present (const hb_feature_t *user_features,
unsigned int num_user_features)
{
while (num_user_features) {
if (user_features->start != 0 || user_features->end != (unsigned int) -1)
return true;
num_user_features--;
user_features++;
}
return false;
}
static inline hb_bool_t
hb_coords_present (const int *coords HB_UNUSED,
unsigned int num_coords)
{
return num_coords != 0;
}
/** /**
* hb_shape_plan_create_cached: * hb_shape_plan_create_cached:
* @face: * @face:
@ -476,64 +450,38 @@ hb_shape_plan_create_cached2 (hb_face_t *face,
num_user_features, num_user_features,
shaper_list); shaper_list);
hb_shape_plan_proposal_t proposal = { retry:
*props, hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
shaper_list,
bool dont_cache = hb_object_is_inert (face);
if (likely (!dont_cache))
{
hb_shape_plan_key_t key;
if (!key.init (false,
face,
props,
user_features, user_features,
num_user_features, num_user_features,
coords, coords,
num_coords, num_coords,
nullptr shaper_list))
};
if (shaper_list) {
/* Choose shaper. Adapted from hb_shape_plan_plan().
* Must choose shaper exactly the same way as that function. */
for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (0 == strcmp (*shaper_item, #shaper) && \
hb_##shaper##_shaper_face_data_ensure (face)) \
{ \
proposal.shaper_func = _hb_##shaper##_shape; \
break; \
}
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
if (unlikely (!proposal.shaper_func))
return hb_shape_plan_get_empty (); return hb_shape_plan_get_empty ();
}
retry:
hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
/* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
if (!hb_coords_present (coords, num_coords))
for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
if (hb_shape_plan_matches (node->shape_plan, &proposal)) if (node->shape_plan->key.equal (&key))
{ {
DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
return hb_shape_plan_reference (node->shape_plan); return hb_shape_plan_reference (node->shape_plan);
} }
}
/* Not found. */
hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props, hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
user_features, num_user_features, user_features, num_user_features,
coords, num_coords, coords, num_coords,
shaper_list); shaper_list);
/* Don't add to the cache if face is inert. */ if (unlikely (dont_cache))
if (unlikely (hb_object_is_inert (face)))
return shape_plan;
/* Don't add the plan to the cache if there were user features with non-global ranges */
if (hb_non_global_user_features_present (user_features, num_user_features))
return shape_plan;
/* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
if (hb_coords_present (coords, num_coords))
return shape_plan; return shape_plan;
hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t)); hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
@ -553,19 +501,3 @@ retry:
return hb_shape_plan_reference (shape_plan); return hb_shape_plan_reference (shape_plan);
} }
/**
* hb_shape_plan_get_shaper:
* @shape_plan: a shape plan.
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.7
**/
const char *
hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
{
return shape_plan->shaper_name;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2012 Google, Inc. * Copyright © 2012,2018 Google, Inc.
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -32,35 +32,44 @@
#include "hb-ot-shape.hh" #include "hb-ot-shape.hh"
struct hb_shape_plan_t struct hb_shape_plan_key_t
{ {
hb_object_header_t header;
hb_face_t *face_unsafe; /* We don't carry a reference to face. */
bool custom_shaper_list;
hb_segment_properties_t props; hb_segment_properties_t props;
const hb_feature_t *user_features;
unsigned int num_user_features;
hb_ot_shape_plan_key_t ot;
hb_shape_func_t *shaper_func; hb_shape_func_t *shaper_func;
const char *shaper_name; const char *shaper_name;
hb_feature_t *user_features; HB_INTERNAL inline bool init (bool copy,
unsigned int num_user_features; hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features,
const int *coords,
unsigned int num_coords,
const char * const *shaper_list);
int *coords; HB_INTERNAL inline void free (void)
unsigned int num_coords; {
::free ((void *) user_features);
}
HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other);
HB_INTERNAL bool equal (const hb_shape_plan_key_t *other);
};
struct hb_shape_plan_t
{
hb_object_header_t header;
hb_face_t *face_unsafe; /* We don't carry a reference to face. */
hb_shape_plan_key_t key;
hb_ot_shape_plan_t ot; hb_ot_shape_plan_t ot;
}; };
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
, const hb_feature_t *user_features \
, unsigned int num_user_features \
, const int *coords \
, unsigned int num_coords
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_SHAPE_PLAN_HH */ #endif /* HB_SHAPE_PLAN_HH */

View File

@ -63,7 +63,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
if (unlikely (!shaper_list)) if (unlikely (!shaper_list))
return nullptr; return nullptr;
const hb_shaper_pair_t *shapers = _hb_shapers_get (); const hb_shaper_pair_static_t *shapers = _hb_shapers_get ();
unsigned int i; unsigned int i;
for (i = 0; i < HB_SHAPERS_COUNT; i++) for (i = 0; i < HB_SHAPERS_COUNT; i++)
shaper_list[i] = shapers[i].name; shaper_list[i] = shapers[i].name;

View File

@ -29,7 +29,7 @@
#include "hb-machinery.hh" #include "hb-machinery.hh"
static const hb_shaper_pair_t all_shapers[] = { static const hb_shaper_pair_static_t all_shapers[] = {
#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}, #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT #undef HB_SHAPER_IMPLEMENT
@ -39,16 +39,16 @@ static const hb_shaper_pair_t all_shapers[] = {
static void free_static_shapers (void); static void free_static_shapers (void);
#endif #endif
static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t, static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_static_t,
hb_shapers_lazy_loader_t> hb_shapers_lazy_loader_t>
{ {
static inline hb_shaper_pair_t *create (void) static inline hb_shaper_pair_static_t *create (void)
{ {
char *env = getenv ("HB_SHAPER_LIST"); char *env = getenv ("HB_SHAPER_LIST");
if (!env || !*env) if (!env || !*env)
return nullptr; return nullptr;
hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers)); hb_shaper_pair_static_t *shapers = (hb_shaper_pair_static_t *) calloc (1, sizeof (all_shapers));
if (unlikely (!shapers)) if (unlikely (!shapers))
return nullptr; return nullptr;
@ -68,7 +68,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t
0 == strncmp (shapers[j].name, p, end - p)) 0 == strncmp (shapers[j].name, p, end - p))
{ {
/* Reorder this shaper to position i */ /* Reorder this shaper to position i */
struct hb_shaper_pair_t t = shapers[j]; struct hb_shaper_pair_static_t t = shapers[j];
memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i)); memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
shapers[i] = t; shapers[i] = t;
i++; i++;
@ -86,11 +86,11 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t
return shapers; return shapers;
} }
static inline void destroy (const hb_shaper_pair_t *p) static inline void destroy (const hb_shaper_pair_static_t *p)
{ {
free ((void *) p); free ((void *) p);
} }
static inline const hb_shaper_pair_t *get_null (void) static inline const hb_shaper_pair_static_t *get_null (void)
{ {
return all_shapers; return all_shapers;
} }
@ -104,7 +104,7 @@ void free_static_shapers (void)
} }
#endif #endif
const hb_shaper_pair_t * const hb_shaper_pair_static_t *
_hb_shapers_get (void) _hb_shapers_get (void)
{ {
return static_shapers.get_unconst (); return static_shapers.get_unconst ();

View File

@ -40,12 +40,12 @@ typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan,
#include "hb-shaper-list.hh" #include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT #undef HB_SHAPER_IMPLEMENT
struct hb_shaper_pair_t { struct hb_shaper_pair_static_t {
char name[16]; char name[16];
hb_shape_func_t *func; hb_shape_func_t *func;
}; };
HB_INTERNAL const hb_shaper_pair_t * HB_INTERNAL const hb_shaper_pair_static_t *
_hb_shapers_get (void); _hb_shapers_get (void);

View File

@ -46,24 +46,26 @@ DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x0
const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
void unsigned int
hb_face_t::load_num_glyphs (void) const hb_face_t::load_num_glyphs (void) const
{ {
hb_sanitize_context_t c = hb_sanitize_context_t (); hb_sanitize_context_t c = hb_sanitize_context_t ();
c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */ c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this); hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> (); const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
num_glyphs = maxp_table->get_num_glyphs ();
unsigned int ret = maxp_table->get_num_glyphs ();
num_glyphs.set_relaxed (ret);
hb_blob_destroy (maxp_blob); hb_blob_destroy (maxp_blob);
return ret;
} }
void unsigned int
hb_face_t::load_upem (void) const hb_face_t::load_upem (void) const
{ {
hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (this); unsigned int ret = table.head->get_upem ();
const OT::head *head_table = head_blob->as<OT::head> (); upem.set_relaxed (ret);
upem = head_table->get_upem (); return ret;
hb_blob_destroy (head_blob);
} }
#endif #endif

View File

@ -246,7 +246,7 @@ struct _hb_alignof
#endif #endif
#if defined(_WIN32) || defined(__CYGWIN__) #ifdef _WIN32
/* We need Windows Vista for both Uniscribe backend and for /* We need Windows Vista for both Uniscribe backend and for
* MemoryBarrier. We don't support compiling on Windows XP, * MemoryBarrier. We don't support compiling on Windows XP,
* though we run on it fine. */ * though we run on it fine. */

View File

@ -7,13 +7,13 @@ DISTCLEANFILES =
MAINTAINERCLEANFILES = MAINTAINERCLEANFILES =
# Convenience targets: # Convenience targets:
lib-only: lib:
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src fuzzing @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
lib: lib-only libs:
@$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
$(top_builddir)/src/libharfbuzz-fuzzing.la: lib-only $(top_builddir)/src/libharfbuzz.la: lib
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la: lib-only $(top_builddir)/src/libharfbuzz-subset.la: libs
EXTRA_DIST += \ EXTRA_DIST += \
README \ README \
@ -33,24 +33,15 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/ \
-I$(top_builddir)/src/ \ -I$(top_builddir)/src/ \
$(NULL) $(NULL)
LDADD = \
$(top_builddir)/src/libharfbuzz-fuzzing.la \
$(NULL)
hb_shape_fuzzer_SOURCES = \ hb_shape_fuzzer_SOURCES = \
hb-fuzzer.hh \ hb-fuzzer.hh \
hb-shape-fuzzer.cc \ hb-shape-fuzzer.cc \
main.cc \ main.cc \
$(NULL) $(NULL)
hb_shape_fuzzer_LDADD = \ hb_shape_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
$(LDADD) \ hb_shape_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
$(NULL) hb_shape_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
hb_shape_fuzzer_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(NULL)
hb_shape_fuzzer_DEPENDENCIES = \
$(top_builddir)/src/libharfbuzz-fuzzing.la
$(NULL)
hb_subset_fuzzer_SOURCES = \ hb_subset_fuzzer_SOURCES = \
hb-fuzzer.hh \ hb-fuzzer.hh \
@ -58,14 +49,10 @@ hb_subset_fuzzer_SOURCES = \
main.cc \ main.cc \
$(NULL) $(NULL)
hb_subset_fuzzer_LDADD = \ hb_subset_fuzzer_LDADD = \
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la \ $(top_builddir)/src/libharfbuzz.la \
$(NULL) $(top_builddir)/src/libharfbuzz-subset.la
hb_subset_fuzzer_CPPFLAGS = \ hb_subset_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
$(AM_CPPFLAGS) \ hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la
$(NULL)
hb_subset_fuzzer_DEPENDENCIES = \
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la
$(NULL)
check: check:
EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py

View File

@ -8,3 +8,4 @@
../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11134,U+11131:[u11124=0+514|u11134=0+0|u11131=0+0] ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11134,U+11131:[u11124=0+514|u11134=0+0|u11131=0+0]
../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11134:[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0] ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11134:[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0]
../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443:[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0] ../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443:[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0]
../fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf::U+11328,U+1134D,U+1CF4:[gid1=0+793|gid2=0+0|gid3=0+0]