Merge branch 'master' into cff-subset
This commit is contained in:
commit
892ab37e7c
|
@ -15,7 +15,6 @@ check_PROGRAMS =
|
|||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la
|
||||
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
|
||||
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
|
||||
|
||||
lib_LTLIBRARIES = libharfbuzz.la
|
||||
|
||||
|
@ -169,36 +168,6 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
|
|||
pkgconfig_DATA += harfbuzz-subset.pc
|
||||
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_BUILTIN
|
||||
HBCFLAGS += $(ICU_CFLAGS)
|
||||
|
|
|
@ -163,6 +163,7 @@ HB_OT_sources = \
|
|||
hb-ot-shape-fallback.hh \
|
||||
hb-ot-shape-fallback.cc \
|
||||
hb-ot-shape.hh \
|
||||
hb-ot-stat-table.hh \
|
||||
hb-ot-var.cc \
|
||||
hb-ot-var-avar-table.hh \
|
||||
hb-ot-var-fvar-table.hh \
|
||||
|
|
|
@ -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)
|
||||
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
|
||||
# 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):
|
||||
return UISC == Number_Joiner
|
||||
def is_ZWNJ(U, UISC, UGC):
|
||||
|
|
|
@ -557,7 +557,9 @@ struct StateTable
|
|||
/* Negative states. */
|
||||
if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
|
||||
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);
|
||||
if ((c->max_ops -= state_neg - min_state) < 0)
|
||||
return_trace (false);
|
||||
|
@ -574,7 +576,9 @@ struct StateTable
|
|||
if (state_pos <= max_state)
|
||||
{
|
||||
/* 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);
|
||||
if ((c->max_ops -= max_state - state_pos + 1) < 0)
|
||||
return_trace (false);
|
||||
|
|
|
@ -260,14 +260,14 @@ struct KerxSubTableFormat1
|
|||
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 kern_idx = Format1EntryT::kernActionIndex (entry);
|
||||
kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
|
||||
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;
|
||||
return false;
|
||||
|
@ -279,9 +279,9 @@ struct KerxSubTableFormat1
|
|||
* "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... */
|
||||
bool last = false;
|
||||
while (!last && depth--)
|
||||
while (!last && depth)
|
||||
{
|
||||
unsigned int idx = stack[depth];
|
||||
unsigned int idx = stack[--depth];
|
||||
int v = *actions;
|
||||
actions += tuple_count;
|
||||
if (idx >= buffer->len) continue;
|
||||
|
|
|
@ -49,7 +49,8 @@ struct lcar
|
|||
unsigned int *caret_count /* IN/OUT */,
|
||||
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);
|
||||
if (caret_count && *caret_count)
|
||||
{
|
||||
|
|
|
@ -51,9 +51,7 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
|||
}
|
||||
|
||||
void
|
||||
hb_aat_map_builder_t::compile (hb_aat_map_t &m,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
||||
{
|
||||
/* Sort features and merge duplicates */
|
||||
if (features.len)
|
||||
|
|
|
@ -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 compile (hb_aat_map_t &m,
|
||||
const int *coords,
|
||||
unsigned int num_coords);
|
||||
HB_INTERNAL void compile (hb_aat_map_t &m);
|
||||
|
||||
public:
|
||||
struct feature_info_t
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
#elif !defined(HB_NO_MT) && defined(_WIN32)
|
||||
|
||||
#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; }
|
||||
#endif
|
||||
#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
|
||||
#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
|
||||
|
||||
|
||||
#define HB_ATOMIC_INT_INIT(V) {V}
|
||||
struct hb_atomic_int_t
|
||||
{
|
||||
inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); }
|
||||
inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&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 (void) const { return hb_atomic_int_impl_get (&v); }
|
||||
inline int inc (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;
|
||||
|
||||
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 (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_); }
|
||||
|
@ -293,7 +293,7 @@ struct hb_atomic_ptr_t
|
|||
inline T * operator -> (void) const { return get (); }
|
||||
template <typename C> inline operator C * (void) const { return get (); }
|
||||
|
||||
mutable T *v;
|
||||
T *v;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ hb_blob_t::try_make_writable (void)
|
|||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# ifndef O_BINARY
|
||||
|
@ -497,19 +497,19 @@ struct hb_mapped_file_t
|
|||
{
|
||||
char *contents;
|
||||
unsigned long length;
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef _WIN32
|
||||
HANDLE mapping;
|
||||
#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
|
||||
_hb_mapped_file_destroy (void *file_)
|
||||
{
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
|
||||
#ifdef HAVE_MMAP
|
||||
munmap (file->contents, file->length);
|
||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||
#elif defined(_WIN32)
|
||||
UnmapViewOfFile (file->contents);
|
||||
CloseHandle (file->mapping);
|
||||
#else
|
||||
|
@ -560,7 +560,7 @@ fail:
|
|||
fail_without_close:
|
||||
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));
|
||||
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||
|
||||
|
|
|
@ -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. */
|
||||
#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
|
||||
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
|
||||
{
|
||||
|
@ -535,11 +546,7 @@ struct hb_bytes_t
|
|||
{
|
||||
if (len != a.len)
|
||||
return (int) a.len - (int) len;
|
||||
|
||||
if (!len)
|
||||
return 0; /* glibc's memcmp() declares args non-NULL, and UBSan doesn't like that. :( */
|
||||
|
||||
return memcmp (a.arrayZ, arrayZ, len);
|
||||
return hb_memcmp (a.arrayZ, arrayZ, len);
|
||||
}
|
||||
static inline int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
|
|
|
@ -87,8 +87,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
|
|||
nullptr, /* destroy */
|
||||
|
||||
0, /* index */
|
||||
1000, /* upem */
|
||||
0, /* num_glyphs */
|
||||
HB_ATOMIC_INT_INIT (1000), /* upem */
|
||||
HB_ATOMIC_INT_INIT (0), /* num_glyphs */
|
||||
|
||||
{
|
||||
#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->destroy = destroy;
|
||||
|
||||
face->num_glyphs = (unsigned int) -1;
|
||||
face->num_glyphs.set_relaxed (-1);
|
||||
|
||||
face->table.init0 (face);
|
||||
|
||||
|
@ -445,7 +445,7 @@ hb_face_set_upem (hb_face_t *face,
|
|||
if (hb_object_is_immutable (face))
|
||||
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))
|
||||
return;
|
||||
|
||||
face->num_glyphs = glyph_count;
|
||||
face->num_glyphs.set_relaxed (glyph_count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,8 +49,8 @@ struct hb_face_t
|
|||
hb_destroy_func_t destroy;
|
||||
|
||||
unsigned int index; /* Face index in a collection, zero-based. */
|
||||
mutable unsigned int upem; /* Units-per-EM. */
|
||||
mutable unsigned int num_glyphs; /* Number of glyphs. */
|
||||
mutable hb_atomic_int_t upem; /* Units-per-EM. */
|
||||
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
|
||||
|
||||
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
|
||||
{
|
||||
if (unlikely (!upem))
|
||||
load_upem ();
|
||||
return upem;
|
||||
unsigned int ret = upem.get_relaxed ();
|
||||
if (unlikely (!ret))
|
||||
{
|
||||
return load_upem ();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline unsigned int get_num_glyphs (void) const
|
||||
{
|
||||
if (unlikely (num_glyphs == (unsigned int) -1))
|
||||
load_num_glyphs ();
|
||||
return num_glyphs;
|
||||
unsigned int ret = num_glyphs.get_relaxed ();
|
||||
if (unlikely (ret == (unsigned int) -1))
|
||||
return load_num_glyphs ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
HB_INTERNAL void load_upem (void) const;
|
||||
HB_INTERNAL void load_num_glyphs (void) const;
|
||||
HB_INTERNAL unsigned int load_upem (void) const;
|
||||
HB_INTERNAL unsigned int load_num_glyphs (void) const;
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_face_t);
|
||||
|
||||
|
|
|
@ -298,7 +298,8 @@ struct hb_sanitize_context_t :
|
|||
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;
|
||||
bool ok = this->start <= p &&
|
||||
|
@ -316,20 +317,37 @@ struct hb_sanitize_context_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;
|
||||
bool overflows = hb_unsigned_mul_overflows (len, record_size);
|
||||
unsigned int array_size = record_size * len;
|
||||
bool ok = !overflows && this->check_range (base, array_size);
|
||||
return !hb_unsigned_mul_overflows (a, b) &&
|
||||
this->check_range (base, a * b);
|
||||
}
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
|
||||
p, p + (record_size * len), record_size, len, (unsigned int) array_size,
|
||||
this->start, this->end,
|
||||
overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
|
||||
template <typename T>
|
||||
inline bool check_range (const T *base,
|
||||
unsigned int a,
|
||||
unsigned int b,
|
||||
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>
|
||||
|
@ -734,16 +752,19 @@ struct hb_data_wrapper_t
|
|||
return *(((Data **) (void *) this) - WheresData);
|
||||
}
|
||||
|
||||
inline bool is_inert (void) const { return !get_data (); }
|
||||
|
||||
template <typename Stored, typename Subclass>
|
||||
inline Stored * call_create (void) const
|
||||
{
|
||||
Data *data = this->get_data ();
|
||||
return likely (data) ? Subclass::create (data) : nullptr;
|
||||
return Subclass::create (this->get_data ());
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct hb_data_wrapper_t<void, 0>
|
||||
{
|
||||
inline bool is_inert (void) const { return false; }
|
||||
|
||||
template <typename Stored, typename Funcs>
|
||||
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)
|
||||
{
|
||||
if (p)
|
||||
if (p && p != const_cast<Stored *> (Funcs::get_null ()))
|
||||
Funcs::destroy (p);
|
||||
}
|
||||
|
||||
|
@ -796,9 +817,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
|||
Stored *p = this->instance.get ();
|
||||
if (unlikely (!p))
|
||||
{
|
||||
if (unlikely (this->is_inert ()))
|
||||
return const_cast<Stored *> (Funcs::get_null ());
|
||||
|
||||
p = this->template call_create<Stored, Funcs> ();
|
||||
if (unlikely (!p))
|
||||
return const_cast<Stored *> (Funcs::get_null ());
|
||||
p = const_cast<Stored *> (Funcs::get_null ());
|
||||
|
||||
if (unlikely (!this->instance.cmpexch (nullptr, p)))
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
/* 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>
|
||||
typedef CRITICAL_SECTION hb_mutex_impl_t;
|
||||
|
|
|
@ -194,7 +194,7 @@ struct hb_user_data_array_t
|
|||
struct hb_object_header_t
|
||||
{
|
||||
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;
|
||||
};
|
||||
#define HB_OBJECT_HEADER_STATIC \
|
||||
|
|
|
@ -887,7 +887,9 @@ struct VarSizedBinSearchArrayOf
|
|||
TRACE_SANITIZE (this);
|
||||
return_trace (header.sanitize (c) &&
|
||||
Type::static_size <= header.unitSize &&
|
||||
c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize));
|
||||
c->check_range (bytesZ.arrayZ,
|
||||
header.nUnits,
|
||||
header.unitSize));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -91,7 +91,7 @@ struct CFFIndex
|
|||
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
|
||||
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
|
||||
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)
|
||||
|
|
|
@ -249,7 +249,7 @@ struct sbix
|
|||
/* Convert to font units. */
|
||||
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->y_bearing = round (extents->y_bearing * scale);
|
||||
extents->width = round (extents->width * scale);
|
||||
|
|
|
@ -238,7 +238,7 @@ hb_ot_color_has_svg (hb_face_t *face)
|
|||
* @face: a font face.
|
||||
* @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.
|
||||
*
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#define HB_OT_TABLES \
|
||||
/* OpenType fundamentals. */ \
|
||||
HB_OT_TABLE(OT, head) \
|
||||
HB_OT_ACCELERATOR(OT, cmap) \
|
||||
HB_OT_ACCELERATOR(OT, hmtx) \
|
||||
HB_OT_ACCELERATOR(OT, vmtx) \
|
||||
|
@ -50,6 +51,8 @@
|
|||
HB_OT_ACCELERATOR(OT, cff2) \
|
||||
HB_OT_TABLE(OT, VORG) \
|
||||
HB_OT_ACCELERATOR(OT, name) \
|
||||
HB_OT_TABLE(OT, OS2) \
|
||||
HB_OT_TABLE(OT, STAT) \
|
||||
/* OpenType shaping. */ \
|
||||
HB_OT_ACCELERATOR(OT, GDEF) \
|
||||
HB_OT_ACCELERATOR(OT, GSUB) \
|
||||
|
|
|
@ -33,12 +33,14 @@
|
|||
#include "hb-ot-face.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-cff1-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-color-cbdt-table.hh"
|
||||
#include "hb-ot-color-sbix-table.hh"
|
||||
|
|
|
@ -235,16 +235,11 @@ struct glyf
|
|||
{
|
||||
memset (this, 0, sizeof (accelerator_t));
|
||||
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (face);
|
||||
const head *head_table = head_blob->as<head> ();
|
||||
if (head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
|
||||
{
|
||||
const OT::head &head = *face->table.head;
|
||||
if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0)
|
||||
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
|
||||
hb_blob_destroy (head_blob);
|
||||
return;
|
||||
}
|
||||
short_offset = 0 == head_table->indexToLocFormat;
|
||||
hb_blob_destroy (head_blob);
|
||||
short_offset = 0 == head.indexToLocFormat;
|
||||
|
||||
loca_table = hb_sanitize_context_t().reference_table<loca> (face);
|
||||
glyf_table = hb_sanitize_context_t().reference_table<glyf> (face);
|
||||
|
|
|
@ -194,17 +194,14 @@ struct hmtxvmtx
|
|||
bool got_font_extents = false;
|
||||
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)
|
||||
if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
|
||||
if (0 != (face->table.OS2->fsSelection & USE_TYPO_METRICS))
|
||||
{
|
||||
ascender = abs (os2_table->sTypoAscender);
|
||||
descender = -abs (os2_table->sTypoDescender);
|
||||
line_gap = os2_table->sTypoLineGap;
|
||||
ascender = abs (face->table.OS2->sTypoAscender);
|
||||
descender = -abs (face->table.OS2->sTypoDescender);
|
||||
line_gap = face->table.OS2->sTypoLineGap;
|
||||
got_font_extents = (ascender | descender) != 0;
|
||||
}
|
||||
hb_blob_destroy (os2_blob);
|
||||
}
|
||||
|
||||
hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face);
|
||||
|
@ -289,9 +286,9 @@ struct hmtxvmtx
|
|||
|
||||
public:
|
||||
bool has_font_extents;
|
||||
unsigned short ascender;
|
||||
unsigned short descender;
|
||||
unsigned short line_gap;
|
||||
int ascender;
|
||||
int descender;
|
||||
int line_gap;
|
||||
|
||||
protected:
|
||||
unsigned int num_metrics;
|
||||
|
|
|
@ -1584,8 +1584,9 @@ struct VarData
|
|||
return_trace (c->check_struct (this) &&
|
||||
regionIndices.sanitize(c) &&
|
||||
shortCount <= regionIndices.len &&
|
||||
c->check_array (&StructAfter<HBUINT8> (regionIndices),
|
||||
itemCount, get_row_size ()));
|
||||
c->check_range (&StructAfter<HBUINT8> (regionIndices),
|
||||
itemCount,
|
||||
get_row_size ()));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -207,7 +207,7 @@ struct ValueFormat : HBUINT16
|
|||
TRACE_SANITIZE (this);
|
||||
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);
|
||||
|
||||
|
@ -706,7 +706,10 @@ struct PairSet
|
|||
{
|
||||
TRACE_SANITIZE (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;
|
||||
const PairValueRecord *record = &firstPairValueRecord;
|
||||
|
@ -879,7 +882,9 @@ struct PairPosFormat2
|
|||
unsigned int stride = len1 + len2;
|
||||
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
|
||||
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) &&
|
||||
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
#include "hb-ot-map.hh"
|
||||
|
||||
#include "hb-ot-shape.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
|
||||
hb_ot_map_builder_t::compile (hb_ot_map_t &m,
|
||||
const int *coords,
|
||||
unsigned int num_coords)
|
||||
const hb_ot_shape_plan_key_t &key)
|
||||
{
|
||||
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (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 */
|
||||
|
||||
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 last_num_lookups = 0;
|
||||
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)
|
||||
add_lookups (m, table_index,
|
||||
required_feature_index[table_index],
|
||||
variations_index,
|
||||
key.variations_index[table_index],
|
||||
global_bit_mask);
|
||||
|
||||
for (unsigned i = 0; i < m.features.len; i++)
|
||||
if (m.features[i].stage[table_index] == stage)
|
||||
add_lookups (m, table_index,
|
||||
m.features[i].index[table_index],
|
||||
variations_index,
|
||||
key.variations_index[table_index],
|
||||
m.features[i].mask,
|
||||
m.features[i].auto_zwnj,
|
||||
m.features[i].auto_zwj,
|
||||
|
|
|
@ -188,6 +188,7 @@ struct hb_ot_map_feature_t
|
|||
hb_ot_map_feature_flags_t flags;
|
||||
};
|
||||
|
||||
struct hb_ot_shape_plan_key_t;
|
||||
|
||||
struct hb_ot_map_builder_t
|
||||
{
|
||||
|
@ -219,8 +220,7 @@ struct hb_ot_map_builder_t
|
|||
{ add_pause (1, pause_func); }
|
||||
|
||||
HB_INTERNAL void compile (hb_ot_map_t &m,
|
||||
const int *coords,
|
||||
unsigned int num_coords);
|
||||
const hb_ot_shape_plan_key_t &key);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ struct arabic_fallback_plan_t
|
|||
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
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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,
|
||||
/* 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,
|
||||
/* 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,
|
||||
/* 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,
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
|
||||
static void
|
||||
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
||||
const hb_segment_properties_t *props,
|
||||
const hb_feature_t *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_ot_shape_planner_t::hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
|
||||
face (master_plan->face_unsafe),
|
||||
props (master_plan->props),
|
||||
map (face, &props),
|
||||
aat_map (face, &props),
|
||||
hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face,
|
||||
const hb_segment_properties_t *props) :
|
||||
face (face),
|
||||
props (*props),
|
||||
map (face, props),
|
||||
aat_map (face, props),
|
||||
apply_morx (_hb_apply_morx (face)),
|
||||
shaper (apply_morx ?
|
||||
&_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
|
||||
hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
||||
const int *coords,
|
||||
unsigned int num_coords)
|
||||
const hb_ot_shape_plan_key_t &key)
|
||||
{
|
||||
plan.props = props;
|
||||
plan.shaper = shaper;
|
||||
map.compile (plan.map, coords, num_coords);
|
||||
map.compile (plan.map, key);
|
||||
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.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);
|
||||
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.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. */
|
||||
plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face);
|
||||
}
|
||||
|
||||
bool
|
||||
hb_ot_shape_plan_t::init0 (hb_shape_plan_t *shape_plan,
|
||||
const hb_feature_t *user_features,
|
||||
unsigned int num_user_features,
|
||||
const int *coords,
|
||||
unsigned int num_coords)
|
||||
hb_ot_shape_plan_t::init0 (hb_face_t *face,
|
||||
const hb_shape_plan_key_t *key)
|
||||
{
|
||||
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,
|
||||
user_features, num_user_features);
|
||||
|
||||
planner.compile (*this, coords, num_coords);
|
||||
planner.compile (*this, key->ot);
|
||||
|
||||
if (shaper->data_create)
|
||||
{
|
||||
|
@ -209,7 +206,6 @@ horizontal_features[] =
|
|||
|
||||
static void
|
||||
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
||||
const hb_segment_properties_t *props,
|
||||
const hb_feature_t *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->add_gsub_pause (nullptr);
|
||||
|
||||
switch (props->direction) {
|
||||
switch (planner->props.direction) {
|
||||
case HB_DIRECTION_LTR:
|
||||
map->enable_feature (HB_TAG ('l','t','r','a'));
|
||||
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++)
|
||||
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++)
|
||||
map->add_feature (horizontal_features[i]);
|
||||
else
|
||||
|
|
|
@ -33,6 +33,31 @@
|
|||
#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
|
||||
{
|
||||
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 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,
|
||||
const hb_feature_t *user_features,
|
||||
unsigned int num_user_features,
|
||||
const int *coords,
|
||||
unsigned int num_coords);
|
||||
|
||||
HB_INTERNAL bool init0 (hb_face_t *face,
|
||||
const hb_shape_plan_key_t *key);
|
||||
HB_INTERNAL void fini (void);
|
||||
};
|
||||
|
||||
|
@ -94,11 +115,11 @@ struct hb_ot_shape_planner_t
|
|||
bool apply_morx : 1;
|
||||
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,
|
||||
const int *coords,
|
||||
unsigned int num_coords);
|
||||
const hb_ot_shape_plan_key_t &key);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -39,7 +39,9 @@ struct DeltaSetIndexMap
|
|||
{
|
||||
TRACE_SANITIZE (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. */
|
||||
|
|
|
@ -68,7 +68,9 @@ struct MVAR
|
|||
c->check_struct (this) &&
|
||||
valueRecordSize >= VariationValueRecord::static_size &&
|
||||
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,
|
||||
|
|
|
@ -90,7 +90,7 @@ struct hb_set_t
|
|||
|
||||
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
|
||||
|
|
|
@ -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,
|
||||
unsigned int num_user_features,
|
||||
const int *coords,
|
||||
unsigned int num_coords,
|
||||
const char * const *shaper_list)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
|
||||
"num_features=%d num_coords=%d shaper_list=%p",
|
||||
num_user_features,
|
||||
num_coords,
|
||||
shaper_list);
|
||||
hb_feature_t *features = nullptr;
|
||||
if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
|
||||
goto bail;
|
||||
|
||||
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) \
|
||||
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; \
|
||||
shape_plan->shaper_name = #shaper; \
|
||||
return; \
|
||||
this->shaper_func = _hb_##shaper##_shape; \
|
||||
this->shaper_name = #shaper; \
|
||||
return true; \
|
||||
} \
|
||||
} HB_STMT_END
|
||||
|
||||
if (likely (!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 {
|
||||
if (unlikely (shaper_list))
|
||||
{
|
||||
for (; *shaper_list; shaper_list++)
|
||||
if (false)
|
||||
;
|
||||
|
@ -89,8 +106,50 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
|
|||
#include "hb-shaper-list.hh"
|
||||
#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
|
||||
|
||||
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_feature_t *user_features,
|
||||
unsigned int num_user_features,
|
||||
const int *orig_coords,
|
||||
const int *coords,
|
||||
unsigned int num_coords,
|
||||
const char * const *shaper_list)
|
||||
{
|
||||
|
@ -142,54 +201,39 @@ hb_shape_plan_create2 (hb_face_t *face,
|
|||
num_coords,
|
||||
shaper_list);
|
||||
|
||||
assert (props->direction != HB_DIRECTION_INVALID);
|
||||
|
||||
hb_shape_plan_t *shape_plan;
|
||||
hb_feature_t *features = nullptr;
|
||||
int *coords = nullptr;
|
||||
|
||||
if (unlikely (!props))
|
||||
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> ()))
|
||||
goto bail;
|
||||
|
||||
assert (props->direction != HB_DIRECTION_INVALID);
|
||||
|
||||
if (unlikely (!face))
|
||||
face = hb_face_get_empty ();
|
||||
hb_face_make_immutable (face);
|
||||
|
||||
shape_plan->custom_shaper_list = shaper_list;
|
||||
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,
|
||||
user_features, num_user_features,
|
||||
coords, num_coords,
|
||||
shaper_list);
|
||||
|
||||
if (unlikely (!shape_plan->ot.init0 (shape_plan,
|
||||
if (unlikely (!shape_plan->key.init (true,
|
||||
face,
|
||||
props,
|
||||
user_features,
|
||||
num_user_features,
|
||||
coords,
|
||||
num_coords)))
|
||||
goto bail;
|
||||
num_coords,
|
||||
shaper_list)))
|
||||
goto bail2;
|
||||
if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key)))
|
||||
goto bail3;
|
||||
|
||||
return shape_plan;
|
||||
|
||||
bail3:
|
||||
shape_plan->key.free ();
|
||||
bail2:
|
||||
free (shape_plan);
|
||||
bail:
|
||||
free (coords);
|
||||
free (features);
|
||||
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;
|
||||
|
||||
shape_plan->ot.fini ();
|
||||
|
||||
free (shape_plan->user_features);
|
||||
free (shape_plan->coords);
|
||||
|
||||
shape_plan->key.free ();
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
|
@ -312,8 +369,8 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
|
|||
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
|
||||
"num_features=%d shaper_func=%p, shaper_name=%s",
|
||||
num_features,
|
||||
shape_plan->shaper_func,
|
||||
shape_plan->shaper_name);
|
||||
shape_plan->key.shaper_func,
|
||||
shape_plan->key.shaper_name);
|
||||
|
||||
if (unlikely (!buffer->len))
|
||||
return true;
|
||||
|
@ -325,7 +382,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
|
|||
return false;
|
||||
|
||||
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) \
|
||||
HB_STMT_START { \
|
||||
|
@ -336,7 +393,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
|
|||
if (false)
|
||||
;
|
||||
#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);
|
||||
#include "hb-shaper-list.hh"
|
||||
#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:
|
||||
* @face:
|
||||
|
@ -476,64 +450,38 @@ hb_shape_plan_create_cached2 (hb_face_t *face,
|
|||
num_user_features,
|
||||
shaper_list);
|
||||
|
||||
hb_shape_plan_proposal_t proposal = {
|
||||
*props,
|
||||
shaper_list,
|
||||
retry:
|
||||
hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans;
|
||||
|
||||
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,
|
||||
num_user_features,
|
||||
coords,
|
||||
num_coords,
|
||||
nullptr
|
||||
};
|
||||
|
||||
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))
|
||||
shaper_list))
|
||||
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)
|
||||
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");
|
||||
return hb_shape_plan_reference (node->shape_plan);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found. */
|
||||
hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
|
||||
user_features, num_user_features,
|
||||
coords, num_coords,
|
||||
shaper_list);
|
||||
|
||||
/* Don't add to the cache if face is inert. */
|
||||
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))
|
||||
if (unlikely (dont_cache))
|
||||
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));
|
||||
|
@ -553,19 +501,3 @@ retry:
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012 Google, Inc.
|
||||
* Copyright © 2012,2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
|
@ -32,35 +32,44 @@
|
|||
#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;
|
||||
|
||||
const hb_feature_t *user_features;
|
||||
unsigned int num_user_features;
|
||||
|
||||
hb_ot_shape_plan_key_t ot;
|
||||
|
||||
hb_shape_func_t *shaper_func;
|
||||
const char *shaper_name;
|
||||
|
||||
hb_feature_t *user_features;
|
||||
unsigned int num_user_features;
|
||||
HB_INTERNAL inline bool init (bool copy,
|
||||
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;
|
||||
unsigned int num_coords;
|
||||
HB_INTERNAL inline void free (void)
|
||||
{
|
||||
::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;
|
||||
};
|
||||
|
||||
#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 */
|
||||
|
|
|
@ -63,7 +63,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
|
|||
if (unlikely (!shaper_list))
|
||||
return nullptr;
|
||||
|
||||
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
|
||||
const hb_shaper_pair_static_t *shapers = _hb_shapers_get ();
|
||||
unsigned int i;
|
||||
for (i = 0; i < HB_SHAPERS_COUNT; i++)
|
||||
shaper_list[i] = shapers[i].name;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#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},
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
|
@ -39,16 +39,16 @@ static const hb_shaper_pair_t all_shapers[] = {
|
|||
static void free_static_shapers (void);
|
||||
#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>
|
||||
{
|
||||
static inline hb_shaper_pair_t *create (void)
|
||||
static inline hb_shaper_pair_static_t *create (void)
|
||||
{
|
||||
char *env = getenv ("HB_SHAPER_LIST");
|
||||
if (!env || !*env)
|
||||
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))
|
||||
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))
|
||||
{
|
||||
/* 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));
|
||||
shapers[i] = t;
|
||||
i++;
|
||||
|
@ -86,11 +86,11 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t
|
|||
|
||||
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);
|
||||
}
|
||||
static inline const hb_shaper_pair_t *get_null (void)
|
||||
static inline const hb_shaper_pair_static_t *get_null (void)
|
||||
{
|
||||
return all_shapers;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ void free_static_shapers (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
const hb_shaper_pair_t *
|
||||
const hb_shaper_pair_static_t *
|
||||
_hb_shapers_get (void)
|
||||
{
|
||||
return static_shapers.get_unconst ();
|
||||
|
|
|
@ -40,12 +40,12 @@ typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan,
|
|||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
|
||||
struct hb_shaper_pair_t {
|
||||
struct hb_shaper_pair_static_t {
|
||||
char name[16];
|
||||
hb_shape_func_t *func;
|
||||
};
|
||||
|
||||
HB_INTERNAL const hb_shaper_pair_t *
|
||||
HB_INTERNAL const hb_shaper_pair_static_t *
|
||||
_hb_shapers_get (void);
|
||||
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
||||
void
|
||||
unsigned int
|
||||
hb_face_t::load_num_glyphs (void) const
|
||||
{
|
||||
hb_sanitize_context_t c = hb_sanitize_context_t ();
|
||||
c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
|
||||
hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
unsigned int
|
||||
hb_face_t::load_upem (void) const
|
||||
{
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (this);
|
||||
const OT::head *head_table = head_blob->as<OT::head> ();
|
||||
upem = head_table->get_upem ();
|
||||
hb_blob_destroy (head_blob);
|
||||
unsigned int ret = table.head->get_upem ();
|
||||
upem.set_relaxed (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -246,7 +246,7 @@ struct _hb_alignof
|
|||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#ifdef _WIN32
|
||||
/* We need Windows Vista for both Uniscribe backend and for
|
||||
* MemoryBarrier. We don't support compiling on Windows XP,
|
||||
* though we run on it fine. */
|
||||
|
|
|
@ -7,13 +7,13 @@ DISTCLEANFILES =
|
|||
MAINTAINERCLEANFILES =
|
||||
|
||||
# Convenience targets:
|
||||
lib-only:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src fuzzing
|
||||
lib: lib-only
|
||||
@$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
|
||||
lib:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
|
||||
libs:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
|
||||
|
||||
$(top_builddir)/src/libharfbuzz-fuzzing.la: lib-only
|
||||
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la: lib-only
|
||||
$(top_builddir)/src/libharfbuzz.la: lib
|
||||
$(top_builddir)/src/libharfbuzz-subset.la: libs
|
||||
|
||||
EXTRA_DIST += \
|
||||
README \
|
||||
|
@ -33,24 +33,15 @@ AM_CPPFLAGS = \
|
|||
-I$(top_srcdir)/src/ \
|
||||
-I$(top_builddir)/src/ \
|
||||
$(NULL)
|
||||
LDADD = \
|
||||
$(top_builddir)/src/libharfbuzz-fuzzing.la \
|
||||
$(NULL)
|
||||
|
||||
hb_shape_fuzzer_SOURCES = \
|
||||
hb-fuzzer.hh \
|
||||
hb-shape-fuzzer.cc \
|
||||
main.cc \
|
||||
$(NULL)
|
||||
hb_shape_fuzzer_LDADD = \
|
||||
$(LDADD) \
|
||||
$(NULL)
|
||||
hb_shape_fuzzer_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(NULL)
|
||||
hb_shape_fuzzer_DEPENDENCIES = \
|
||||
$(top_builddir)/src/libharfbuzz-fuzzing.la
|
||||
$(NULL)
|
||||
hb_shape_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la
|
||||
hb_shape_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
hb_shape_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la
|
||||
|
||||
hb_subset_fuzzer_SOURCES = \
|
||||
hb-fuzzer.hh \
|
||||
|
@ -58,14 +49,10 @@ hb_subset_fuzzer_SOURCES = \
|
|||
main.cc \
|
||||
$(NULL)
|
||||
hb_subset_fuzzer_LDADD = \
|
||||
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la \
|
||||
$(NULL)
|
||||
hb_subset_fuzzer_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(NULL)
|
||||
hb_subset_fuzzer_DEPENDENCIES = \
|
||||
$(top_builddir)/src/libharfbuzz-subset-fuzzing.la
|
||||
$(NULL)
|
||||
$(top_builddir)/src/libharfbuzz.la \
|
||||
$(top_builddir)/src/libharfbuzz-subset.la
|
||||
hb_subset_fuzzer_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la
|
||||
|
||||
check:
|
||||
EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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+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/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf::U+11328,U+1134D,U+1CF4:[gid1=0+793|gid2=0+0|gid3=0+0]
|
||||
|
|
Loading…
Reference in New Issue