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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

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))
#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;
};

View File

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

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. */
#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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,7 +27,7 @@
*/
#include "hb-ot-map.hh"
#include "hb-ot-shape.hh"
#include "hb-ot-layout.hh"
@ -143,9 +143,8 @@ 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)
hb_ot_map_builder_t::compile (hb_ot_map_t &m,
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,

View File

@ -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
{
@ -218,9 +219,8 @@ struct hb_ot_map_builder_t
inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (1, pause_func); }
HB_INTERNAL void compile (hb_ot_map_t &m,
const int *coords,
unsigned int num_coords);
HB_INTERNAL void compile (hb_ot_map_t &m,
const hb_ot_shape_plan_key_t &key);
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];
};
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
#if defined(_WIN32) && !defined(HB_NO_WIN1256)
#define HB_WITH_WIN1256
#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,
/* 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,

View File

@ -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,26 +67,26 @@ _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 :
hb_ot_shape_complex_categorize (this)) {}
void
hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
const int *coords,
unsigned int num_coords)
hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
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

View File

@ -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);
HB_INTERNAL void compile (hb_ot_shape_plan_t &plan,
const hb_ot_shape_plan_key_t &key);
};

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);
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. */

View File

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

View File

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

View File

@ -44,42 +44,59 @@
**/
static void
hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
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_shape_plan_key_t
*/
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
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)
{
hb_feature_t *features = nullptr;
if (copy && num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
goto bail;
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,
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))
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))
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,
shaper_list))
return hb_shape_plan_get_empty ();
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;
}

View File

@ -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_key_t
{
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_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);
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. */
bool custom_shaper_list;
hb_segment_properties_t props;
hb_shape_func_t *shaper_func;
const char *shaper_name;
hb_feature_t *user_features;
unsigned int num_user_features;
int *coords;
unsigned int num_coords;
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 */

View File

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

View File

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

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"
#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);

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

View File

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

View File

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

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+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]