Merge branch 'master' into var-subset
This commit is contained in:
commit
b999ce9bf0
|
@ -132,6 +132,7 @@ HB_BASE_sources = \
|
||||||
hb-ot-var-gvar-table.hh \
|
hb-ot-var-gvar-table.hh \
|
||||||
hb-ot-var.cc \
|
hb-ot-var.cc \
|
||||||
hb-ot-vorg-table.hh \
|
hb-ot-vorg-table.hh \
|
||||||
|
hb-pool.hh \
|
||||||
hb-sanitize.hh \
|
hb-sanitize.hh \
|
||||||
hb-serialize.hh \
|
hb-serialize.hh \
|
||||||
hb-set-digest.hh \
|
hb-set-digest.hh \
|
||||||
|
|
|
@ -79,6 +79,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||||
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
|
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
|
||||||
template <typename T> operator T * () const { return arrayZ; }
|
template <typename T> operator T * () const { return arrayZ; }
|
||||||
|
|
||||||
|
bool operator == (const hb_array_t &o) const;
|
||||||
uint32_t hash () const;
|
uint32_t hash () const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -275,19 +276,29 @@ template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
|
||||||
hb_sorted_array (T (&array_)[length_])
|
hb_sorted_array (T (&array_)[length_])
|
||||||
{ return hb_sorted_array_t<T> (array_); }
|
{ return hb_sorted_array_t<T> (array_); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
|
||||||
|
{
|
||||||
|
return length == o.length &&
|
||||||
|
+ hb_zip (*this, o)
|
||||||
|
| hb_map ([] (hb_pair_t<T&, T&> &&_) -> bool { return _.first == _.second; })
|
||||||
|
| hb_all
|
||||||
|
;
|
||||||
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
uint32_t hb_array_t<T>::hash () const
|
uint32_t hb_array_t<T>::hash () const
|
||||||
{
|
{
|
||||||
uint32_t h = 0;
|
return
|
||||||
for (unsigned i = 0; i < length; i++)
|
+ hb_iter (*this)
|
||||||
h ^= hb_hash (arrayZ[i]);
|
| hb_map (hb_hash)
|
||||||
return h;
|
| hb_reduce ([] (uint32_t a, uint32_t b) -> uint32_t { return a * 31 + b; }, 0)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef hb_array_t<const char> hb_bytes_t;
|
typedef hb_array_t<const char> hb_bytes_t;
|
||||||
typedef hb_array_t<const unsigned char> hb_ubytes_t;
|
typedef hb_array_t<const unsigned char> hb_ubytes_t;
|
||||||
|
|
||||||
/* TODO Specialize hashing for hb_bytes_t and hb_ubytes_t. */
|
/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */
|
||||||
//template <>
|
//template <>
|
||||||
//uint32_t hb_array_t<const char>::hash () const { return 0; }
|
//uint32_t hb_array_t<const char>::hash () const { return 0; }
|
||||||
|
|
||||||
|
|
|
@ -1148,59 +1148,3 @@ fail:
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AAT shaper
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shaper face data
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hb_coretext_aat_face_data_t {};
|
|
||||||
|
|
||||||
hb_coretext_aat_face_data_t *
|
|
||||||
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
|
||||||
{
|
|
||||||
return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ?
|
|
||||||
(hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shaper font data
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hb_coretext_aat_font_data_t {};
|
|
||||||
|
|
||||||
hb_coretext_aat_font_data_t *
|
|
||||||
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
|
|
||||||
{
|
|
||||||
return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shaper
|
|
||||||
*/
|
|
||||||
|
|
||||||
hb_bool_t
|
|
||||||
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
|
|
||||||
hb_font_t *font,
|
|
||||||
hb_buffer_t *buffer,
|
|
||||||
const hb_feature_t *features,
|
|
||||||
unsigned int num_features)
|
|
||||||
{
|
|
||||||
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
|
|
||||||
}
|
|
||||||
|
|
|
@ -77,7 +77,9 @@ struct hb_iter_t
|
||||||
hb_enable_if (hb_is_reference (T))>
|
hb_enable_if (hb_is_reference (T))>
|
||||||
hb_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
|
hb_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
|
||||||
item_t operator * () const { return thiz()->__item__ (); }
|
item_t operator * () const { return thiz()->__item__ (); }
|
||||||
|
item_t operator * () { return thiz()->__item__ (); }
|
||||||
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||||
|
item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
|
||||||
iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
|
iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
|
||||||
iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
|
iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
|
||||||
iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
|
iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
|
||||||
|
@ -90,6 +92,8 @@ struct hb_iter_t
|
||||||
template <typename T>
|
template <typename T>
|
||||||
iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); }
|
iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
iter_t& operator >> (T &v) const { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||||
|
template <typename T>
|
||||||
iter_t& operator << (const T v) { **thiz() = v; ++*thiz(); return *thiz(); }
|
iter_t& operator << (const T v) { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -344,6 +348,36 @@ static const struct
|
||||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||||
} hb_filter HB_UNUSED;
|
} hb_filter HB_UNUSED;
|
||||||
|
|
||||||
|
template <typename Redu, typename InitT>
|
||||||
|
struct hb_reduce_t
|
||||||
|
{
|
||||||
|
hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
|
||||||
|
|
||||||
|
template <typename Iter,
|
||||||
|
hb_enable_if (hb_is_iterator (Iter)),
|
||||||
|
typename AccuT = decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>
|
||||||
|
AccuT
|
||||||
|
operator () (Iter it) const
|
||||||
|
{
|
||||||
|
AccuT value = init_value;
|
||||||
|
for (; it; ++it)
|
||||||
|
value = r (value, *it);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Redu r;
|
||||||
|
InitT init_value;
|
||||||
|
};
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
template <typename Redu, typename InitT>
|
||||||
|
hb_reduce_t<Redu, InitT>
|
||||||
|
operator () (Redu&& r, InitT init_value) const
|
||||||
|
{ return hb_reduce_t<Redu, InitT> (r, init_value); }
|
||||||
|
} hb_reduce HB_UNUSED;
|
||||||
|
|
||||||
|
|
||||||
/* hb_zip() */
|
/* hb_zip() */
|
||||||
|
|
||||||
template <typename A, typename B>
|
template <typename A, typename B>
|
||||||
|
@ -585,14 +619,11 @@ hb_fill (C& c, const V &v)
|
||||||
*i = v;
|
*i = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename D,
|
template <typename S, typename D>
|
||||||
hb_enable_if (hb_is_iterator (S) && hb_is_iterator (D))>
|
inline void
|
||||||
inline bool
|
hb_copy (S&& is, D&& id)
|
||||||
hb_copy (D id, S is)
|
|
||||||
{
|
{
|
||||||
for (; id && is; ++id, ++is)
|
hb_iter (is) | hb_sink (id);
|
||||||
*id = *is;
|
|
||||||
return !is;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -144,94 +144,6 @@ static inline Type& StructAfter(TObject &X)
|
||||||
DEFINE_SIZE_ARRAY(size, array)
|
DEFINE_SIZE_ARRAY(size, array)
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Big-endian integers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename Type, int Bytes> struct BEInt;
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct BEInt<Type, 1>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BEInt<Type, 1>& operator = (Type V)
|
|
||||||
{
|
|
||||||
v = V;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
operator Type () const { return v; }
|
|
||||||
private: uint8_t v;
|
|
||||||
};
|
|
||||||
template <typename Type>
|
|
||||||
struct BEInt<Type, 2>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BEInt<Type, 2>& operator = (Type V)
|
|
||||||
{
|
|
||||||
v[0] = (V >> 8) & 0xFF;
|
|
||||||
v[1] = (V ) & 0xFF;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
operator Type () const
|
|
||||||
{
|
|
||||||
#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
|
|
||||||
defined(__BYTE_ORDER) && \
|
|
||||||
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
|
|
||||||
/* Spoon-feed the compiler a big-endian integer with alignment 1.
|
|
||||||
* https://github.com/harfbuzz/harfbuzz/pull/1398 */
|
|
||||||
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
return __builtin_bswap16 (((packed_uint16_t *) this)->v);
|
|
||||||
#else /* __BYTE_ORDER == __BIG_ENDIAN */
|
|
||||||
return ((packed_uint16_t *) this)->v;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
return (v[0] << 8)
|
|
||||||
+ (v[1] );
|
|
||||||
}
|
|
||||||
private: uint8_t v[2];
|
|
||||||
};
|
|
||||||
template <typename Type>
|
|
||||||
struct BEInt<Type, 3>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BEInt<Type, 3>& operator = (Type V)
|
|
||||||
{
|
|
||||||
v[0] = (V >> 16) & 0xFF;
|
|
||||||
v[1] = (V >> 8) & 0xFF;
|
|
||||||
v[2] = (V ) & 0xFF;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
operator Type () const
|
|
||||||
{
|
|
||||||
return (v[0] << 16)
|
|
||||||
+ (v[1] << 8)
|
|
||||||
+ (v[2] );
|
|
||||||
}
|
|
||||||
private: uint8_t v[3];
|
|
||||||
};
|
|
||||||
template <typename Type>
|
|
||||||
struct BEInt<Type, 4>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BEInt<Type, 4>& operator = (Type V)
|
|
||||||
{
|
|
||||||
v[0] = (V >> 24) & 0xFF;
|
|
||||||
v[1] = (V >> 16) & 0xFF;
|
|
||||||
v[2] = (V >> 8) & 0xFF;
|
|
||||||
v[3] = (V ) & 0xFF;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
operator Type () const
|
|
||||||
{
|
|
||||||
return (v[0] << 24)
|
|
||||||
+ (v[1] << 16)
|
|
||||||
+ (v[2] << 8)
|
|
||||||
+ (v[3] );
|
|
||||||
}
|
|
||||||
private: uint8_t v[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lazy loaders.
|
* Lazy loaders.
|
||||||
|
|
|
@ -57,10 +57,13 @@ struct hb_hashmap_t
|
||||||
K key;
|
K key;
|
||||||
V value;
|
V value;
|
||||||
|
|
||||||
bool operator== (K o) { return hb_deref_pointer (key) == hb_deref_pointer (o); }
|
void clear () { key = kINVALID; value = vINVALID; }
|
||||||
bool operator== (const item_t &o) { return *this == o.key; }
|
|
||||||
|
bool operator == (K o) { return hb_deref_pointer (key) == hb_deref_pointer (o); }
|
||||||
|
bool operator == (const item_t &o) { return *this == o.key; }
|
||||||
bool is_unused () const { return key == kINVALID; }
|
bool is_unused () const { return key == kINVALID; }
|
||||||
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
|
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
|
||||||
|
bool is_real () const { return key != kINVALID && value != vINVALID; }
|
||||||
};
|
};
|
||||||
|
|
||||||
hb_object_header_t header;
|
hb_object_header_t header;
|
||||||
|
@ -98,9 +101,10 @@ struct hb_hashmap_t
|
||||||
|
|
||||||
void reset ()
|
void reset ()
|
||||||
{
|
{
|
||||||
/* TODO Keep array? */
|
if (unlikely (hb_object_is_immutable (this)))
|
||||||
fini_shallow ();
|
return;
|
||||||
init_shallow ();
|
successful = true;
|
||||||
|
clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_error () const { return !successful; }
|
bool in_error () const { return !successful; }
|
||||||
|
@ -117,7 +121,9 @@ struct hb_hashmap_t
|
||||||
successful = false;
|
successful = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
|
+ hb_iter (new_items, new_size)
|
||||||
|
| hb_apply ([] (item_t &_) { _.clear (); }) /* TODO make pointer-to-methods invokable. */
|
||||||
|
;
|
||||||
|
|
||||||
unsigned int old_size = mask + 1;
|
unsigned int old_size = mask + 1;
|
||||||
item_t *old_items = items;
|
item_t *old_items = items;
|
||||||
|
@ -131,7 +137,7 @@ struct hb_hashmap_t
|
||||||
/* Insert back old items. */
|
/* Insert back old items. */
|
||||||
if (old_items)
|
if (old_items)
|
||||||
for (unsigned int i = 0; i < old_size; i++)
|
for (unsigned int i = 0; i < old_size; i++)
|
||||||
if (old_items[i].key != kINVALID && old_items[i].value != vINVALID)
|
if (old_items[i].is_real ())
|
||||||
set (old_items[i].key, old_items[i].value);
|
set (old_items[i].key, old_items[i].value);
|
||||||
|
|
||||||
free (old_items);
|
free (old_items);
|
||||||
|
@ -168,7 +174,7 @@ struct hb_hashmap_t
|
||||||
{
|
{
|
||||||
if (unlikely (!items)) return vINVALID;
|
if (unlikely (!items)) return vINVALID;
|
||||||
unsigned int i = bucket_for (key);
|
unsigned int i = bucket_for (key);
|
||||||
return items[i] == key ? items[i].value : vINVALID;
|
return items[i].is_real () && items[i] == key ? items[i].value : vINVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void del (K key) { set (key, vINVALID); }
|
void del (K key) { set (key, vINVALID); }
|
||||||
|
@ -183,7 +189,13 @@ struct hb_hashmap_t
|
||||||
|
|
||||||
void clear ()
|
void clear ()
|
||||||
{
|
{
|
||||||
if (items) memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
|
if (unlikely (hb_object_is_immutable (this)))
|
||||||
|
return;
|
||||||
|
if (items)
|
||||||
|
+ hb_iter (items, mask + 1)
|
||||||
|
| hb_apply ([] (item_t &_) { _.clear (); }) /* TODO make pointer-to-methods invokable. */
|
||||||
|
;
|
||||||
|
|
||||||
population = occupancy = 0;
|
population = occupancy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -281,16 +281,24 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
|
bool serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
|
||||||
{
|
|
||||||
if (&src == &Null (T))
|
|
||||||
{
|
{
|
||||||
*this = 0;
|
*this = 0;
|
||||||
return;
|
if (has_null && &src == &Null (T))
|
||||||
}
|
return false;
|
||||||
serialize (c->serializer, base);
|
|
||||||
if (!src.subset (c))
|
auto *s = c->serializer;
|
||||||
*this = 0;
|
|
||||||
|
s->push ();
|
||||||
|
|
||||||
|
bool ret = src.subset (c);
|
||||||
|
|
||||||
|
if (ret || !has_null)
|
||||||
|
s->add_link (*this, s->pop_pack (), base);
|
||||||
|
else
|
||||||
|
s->pop_discard ();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
|
bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
|
||||||
|
|
|
@ -495,7 +495,7 @@ struct CmapSubtableLongSegmented
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||||
if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
|
if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
|
||||||
return true;
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -520,13 +520,14 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||||
bool serialize (hb_serialize_context_t *c,
|
bool serialize (hb_serialize_context_t *c,
|
||||||
const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
||||||
{
|
{
|
||||||
if (unlikely (!c->extend_min (*this))) return false;
|
TRACE_SERIALIZE (this);
|
||||||
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||||
|
|
||||||
this->format = 12;
|
this->format = 12;
|
||||||
this->reserved = 0;
|
this->reserved = 0;
|
||||||
this->length = get_sub_table_size (groups);
|
this->length = get_sub_table_size (groups);
|
||||||
|
|
||||||
return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
|
return_trace (CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups));
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
|
||||||
|
|
|
@ -922,12 +922,13 @@ struct CoverageFormat2
|
||||||
{
|
{
|
||||||
if (glyphs[i - 1] + 1 != glyphs[i])
|
if (glyphs[i - 1] + 1 != glyphs[i])
|
||||||
{
|
{
|
||||||
|
rangeRecord[range].end = glyphs[i - 1];
|
||||||
range++;
|
range++;
|
||||||
rangeRecord[range].start = glyphs[i];
|
rangeRecord[range].start = glyphs[i];
|
||||||
rangeRecord[range].value = i;
|
rangeRecord[range].value = i;
|
||||||
}
|
}
|
||||||
rangeRecord[range].end = glyphs[i];
|
|
||||||
}
|
}
|
||||||
|
rangeRecord[range].end = glyphs[count - 1];
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1353,8 +1354,9 @@ struct ClassDefFormat2
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int count = glyphs.len ();
|
||||||
unsigned int num_ranges = 1;
|
unsigned int num_ranges = 1;
|
||||||
for (unsigned int i = 1; i < glyphs.length; i++)
|
for (unsigned int i = 1; i < count; i++)
|
||||||
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
||||||
klasses[i - 1] != klasses[i])
|
klasses[i - 1] != klasses[i])
|
||||||
num_ranges++;
|
num_ranges++;
|
||||||
|
@ -1364,17 +1366,18 @@ struct ClassDefFormat2
|
||||||
unsigned int range = 0;
|
unsigned int range = 0;
|
||||||
rangeRecord[range].start = glyphs[0];
|
rangeRecord[range].start = glyphs[0];
|
||||||
rangeRecord[range].value = klasses[0];
|
rangeRecord[range].value = klasses[0];
|
||||||
for (unsigned int i = 1; i < glyphs.length; i++)
|
for (unsigned int i = 1; i < count; i++)
|
||||||
{
|
{
|
||||||
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
||||||
klasses[i - 1] != klasses[i])
|
klasses[i - 1] != klasses[i])
|
||||||
{
|
{
|
||||||
|
rangeRecord[range].end = glyphs[i - 1];
|
||||||
range++;
|
range++;
|
||||||
rangeRecord[range].start = glyphs[i];
|
rangeRecord[range].start = glyphs[i];
|
||||||
rangeRecord[range].value = klasses[i];
|
rangeRecord[range].value = klasses[i];
|
||||||
}
|
}
|
||||||
rangeRecord[range].end = glyphs[i];
|
|
||||||
}
|
}
|
||||||
|
rangeRecord[range].end = glyphs[count - 1];
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1511,8 +1514,9 @@ struct ClassDef
|
||||||
hb_codepoint_t glyph_min = glyphs[0];
|
hb_codepoint_t glyph_min = glyphs[0];
|
||||||
hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
|
hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
|
||||||
|
|
||||||
|
unsigned int count = glyphs.len ();
|
||||||
unsigned int num_ranges = 1;
|
unsigned int num_ranges = 1;
|
||||||
for (unsigned int i = 1; i < glyphs.length; i++)
|
for (unsigned int i = 1; i < count; i++)
|
||||||
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
if (glyphs[i - 1] + 1 != glyphs[i] ||
|
||||||
klasses[i - 1] != klasses[i])
|
klasses[i - 1] != klasses[i])
|
||||||
num_ranges++;
|
num_ranges++;
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2019 Facebook, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Facebook Author(s): Behdad Esfahbod
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_POOL_HH
|
||||||
|
#define HB_POOL_HH
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
|
||||||
|
/* Memory pool for persistent allocation of small objects. */
|
||||||
|
|
||||||
|
template <typename T, unsigned ChunkLen = 16>
|
||||||
|
struct hb_pool_t
|
||||||
|
{
|
||||||
|
hb_pool_t () : next (nullptr) {}
|
||||||
|
~hb_pool_t () { fini (); }
|
||||||
|
|
||||||
|
void fini ()
|
||||||
|
{
|
||||||
|
next = nullptr;
|
||||||
|
|
||||||
|
+ hb_iter (chunks)
|
||||||
|
| hb_apply ([] (chunk_t *_) { ::free (_); })
|
||||||
|
;
|
||||||
|
|
||||||
|
chunks.fini ();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* alloc ()
|
||||||
|
{
|
||||||
|
if (unlikely (!next))
|
||||||
|
{
|
||||||
|
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
|
||||||
|
chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t));
|
||||||
|
if (unlikely (!chunk)) return nullptr;
|
||||||
|
chunks.push (chunk);
|
||||||
|
next = chunk->thread ();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* obj = next;
|
||||||
|
next = * ((T**) next);
|
||||||
|
|
||||||
|
memset (obj, 0, sizeof (T));
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free (T* obj)
|
||||||
|
{
|
||||||
|
* (T**) obj = next;
|
||||||
|
next = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static_assert (ChunkLen > 1, "");
|
||||||
|
static_assert (sizeof (T) >= sizeof (void *), "");
|
||||||
|
static_assert (alignof (T) % sizeof (void *) == 0, "");
|
||||||
|
|
||||||
|
struct chunk_t
|
||||||
|
{
|
||||||
|
T* thread ()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++)
|
||||||
|
* (T**) &arrayZ[i] = &arrayZ[i + 1];
|
||||||
|
|
||||||
|
* (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr;
|
||||||
|
|
||||||
|
return arrayZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
T arrayZ[ChunkLen];
|
||||||
|
};
|
||||||
|
|
||||||
|
T* next;
|
||||||
|
hb_vector_t<chunk_t *> chunks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_POOL_HH */
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
||||||
* Copyright © 2012,2018 Google, Inc.
|
* Copyright © 2012,2018 Google, Inc.
|
||||||
|
* Copyright © 2019 Facebook, Inc.
|
||||||
*
|
*
|
||||||
* This is part of HarfBuzz, a text shaping library.
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
*
|
*
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
*
|
*
|
||||||
* Red Hat Author(s): Behdad Esfahbod
|
* Red Hat Author(s): Behdad Esfahbod
|
||||||
* Google Author(s): Behdad Esfahbod
|
* Google Author(s): Behdad Esfahbod
|
||||||
|
* Facebook Author(s): Behdad Esfahbod
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HB_SERIALIZE_HH
|
#ifndef HB_SERIALIZE_HH
|
||||||
|
@ -32,6 +34,7 @@
|
||||||
#include "hb.hh"
|
#include "hb.hh"
|
||||||
#include "hb-blob.hh"
|
#include "hb-blob.hh"
|
||||||
#include "hb-map.hh"
|
#include "hb-map.hh"
|
||||||
|
#include "hb-pool.hh"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -54,9 +57,9 @@ struct hb_serialize_context_t
|
||||||
bool operator == (const object_t &o) const
|
bool operator == (const object_t &o) const
|
||||||
{
|
{
|
||||||
return (tail - head == o.tail - o.head)
|
return (tail - head == o.tail - o.head)
|
||||||
&& (links.length != o.links.length)
|
&& (links.length == o.links.length)
|
||||||
&& 0 == memcmp (head, o.head, tail - head)
|
&& 0 == hb_memcmp (head, o.head, tail - head)
|
||||||
&& 0 == memcmp (&links, &o.links, links.get_size ());
|
&& links.as_bytes () == o.links.as_bytes ();
|
||||||
}
|
}
|
||||||
uint32_t hash () const
|
uint32_t hash () const
|
||||||
{
|
{
|
||||||
|
@ -66,28 +69,41 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
struct link_t
|
struct link_t
|
||||||
{
|
{
|
||||||
bool wide: 1;
|
bool is_wide: 1;
|
||||||
unsigned offset : 31;
|
unsigned position : 31;
|
||||||
|
int bias;
|
||||||
objidx_t objidx;
|
objidx_t objidx;
|
||||||
};
|
};
|
||||||
|
|
||||||
hb_vector_t<link_t> links;
|
hb_vector_t<link_t> links;
|
||||||
|
object_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
range_t snapshot () { range_t s = {head, tail} ; return s; }
|
range_t snapshot () { range_t s = {head, tail} ; return s; }
|
||||||
|
|
||||||
|
|
||||||
hb_serialize_context_t (void *start_, unsigned int size)
|
hb_serialize_context_t (void *start_, unsigned int size) :
|
||||||
|
start ((char *) start_),
|
||||||
|
end (start + size),
|
||||||
|
current (nullptr)
|
||||||
|
{ reset (); }
|
||||||
|
~hb_serialize_context_t () { fini (); }
|
||||||
|
|
||||||
|
void fini ()
|
||||||
{
|
{
|
||||||
this->start = (char *) start_;
|
++ hb_iter (packed)
|
||||||
this->end = this->start + size;
|
| hb_apply ([] (object_t *_) { _->fini (); })
|
||||||
reset ();
|
;
|
||||||
|
packed.fini ();
|
||||||
|
this->packed_map.fini ();
|
||||||
|
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
auto *_ = current;
|
||||||
|
current = current->next;
|
||||||
|
_->fini ();
|
||||||
}
|
}
|
||||||
~hb_serialize_context_t ()
|
object_pool.fini ();
|
||||||
{
|
|
||||||
current.fini_deep ();
|
|
||||||
packed.fini_deep ();
|
|
||||||
packed_map.fini ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_error () const { return !this->successful; }
|
bool in_error () const { return !this->successful; }
|
||||||
|
@ -100,10 +116,8 @@ struct hb_serialize_context_t
|
||||||
this->tail = this->end;
|
this->tail = this->end;
|
||||||
this->debug_depth = 0;
|
this->debug_depth = 0;
|
||||||
|
|
||||||
this->current.reset ();
|
fini ();
|
||||||
this->packed.reset ();
|
this->packed.push (nullptr);
|
||||||
this->packed.push ()->head = this->end;
|
|
||||||
this->packed_map.reset ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool propagate_error (bool e)
|
bool propagate_error (bool e)
|
||||||
|
@ -127,7 +141,7 @@ struct hb_serialize_context_t
|
||||||
this->start, this->end,
|
this->start, this->end,
|
||||||
(unsigned long) (this->end - this->start));
|
(unsigned long) (this->end - this->start));
|
||||||
|
|
||||||
assert (!current.length);
|
assert (!current);
|
||||||
return push<Type> ();
|
return push<Type> ();
|
||||||
}
|
}
|
||||||
void end_serialize ()
|
void end_serialize ()
|
||||||
|
@ -138,9 +152,10 @@ struct hb_serialize_context_t
|
||||||
(unsigned) (this->head - this->start),
|
(unsigned) (this->head - this->start),
|
||||||
this->successful ? "successful" : "UNSUCCESSFUL");
|
this->successful ? "successful" : "UNSUCCESSFUL");
|
||||||
|
|
||||||
/* TODO Propagate errors. */
|
propagate_error (packed, packed_map);
|
||||||
|
|
||||||
assert (current.length == 1);
|
if (unlikely (!current)) return;
|
||||||
|
assert (!current->next);
|
||||||
|
|
||||||
/* Only "pack" if there exist other objects... Otherwise, don't bother.
|
/* Only "pack" if there exist other objects... Otherwise, don't bother.
|
||||||
* Saves a move. */
|
* Saves a move. */
|
||||||
|
@ -149,54 +164,69 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
pop_pack ();
|
pop_pack ();
|
||||||
|
|
||||||
link ();
|
resolve_links ();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type = void>
|
||||||
Type *push ()
|
Type *push ()
|
||||||
{
|
{
|
||||||
object_t obj;
|
object_t *obj = object_pool.alloc ();
|
||||||
obj.head = head;
|
if (unlikely (!obj))
|
||||||
obj.tail = tail;
|
propagate_error (false);
|
||||||
current.push (obj);
|
else
|
||||||
|
{
|
||||||
|
obj->head = head;
|
||||||
|
obj->tail = tail;
|
||||||
|
obj->next = current;
|
||||||
|
current = obj;
|
||||||
|
}
|
||||||
return start_embed<Type> ();
|
return start_embed<Type> ();
|
||||||
}
|
}
|
||||||
void pop_discard ()
|
void pop_discard ()
|
||||||
{
|
{
|
||||||
revert (current.pop ());
|
object_t *obj = current;
|
||||||
|
if (unlikely (!obj)) return;
|
||||||
|
current = current->next;
|
||||||
|
revert (*obj);
|
||||||
|
object_pool.free (obj);
|
||||||
}
|
}
|
||||||
objidx_t pop_pack ()
|
objidx_t pop_pack ()
|
||||||
{
|
{
|
||||||
object_t obj = current.pop ();
|
object_t *obj = current;
|
||||||
obj.tail = head;
|
if (unlikely (!obj)) return 0;
|
||||||
unsigned len = obj.tail - obj.head;
|
current = current->next;
|
||||||
|
obj->tail = head;
|
||||||
|
obj->next = nullptr;
|
||||||
|
unsigned len = obj->tail - obj->head;
|
||||||
|
head = obj->head; /* Rewind head. */
|
||||||
|
|
||||||
objidx_t objidx = packed_map.get (&obj);
|
if (!len)
|
||||||
|
{
|
||||||
|
assert (!obj->links.length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
objidx_t objidx = packed_map.get (obj);
|
||||||
if (objidx)
|
if (objidx)
|
||||||
{
|
{
|
||||||
obj.fini ();
|
obj->fini ();
|
||||||
return objidx;
|
return objidx;
|
||||||
}
|
}
|
||||||
|
|
||||||
tail -= len;
|
tail -= len;
|
||||||
memmove (tail, obj.head, len);
|
memmove (tail, obj->head, len);
|
||||||
head = obj.head;
|
|
||||||
|
|
||||||
if (!len)
|
obj->head = tail;
|
||||||
return 0;
|
obj->tail = tail + len;
|
||||||
|
|
||||||
obj.head = tail;
|
packed.push (obj);
|
||||||
obj.tail = tail + len;
|
|
||||||
|
|
||||||
object_t *key = packed.push (hb_move (obj));
|
|
||||||
|
|
||||||
/* TODO Handle error. */
|
|
||||||
if (unlikely (packed.in_error ()))
|
if (unlikely (packed.in_error ()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
objidx = packed.length - 1;
|
objidx = packed.length - 1;
|
||||||
|
|
||||||
packed_map.set (key, objidx);
|
packed_map.set (obj, objidx);
|
||||||
|
|
||||||
return objidx;
|
return objidx;
|
||||||
}
|
}
|
||||||
|
@ -213,17 +243,71 @@ struct hb_serialize_context_t
|
||||||
void discard_stale_objects ()
|
void discard_stale_objects ()
|
||||||
{
|
{
|
||||||
while (packed.length > 1 &&
|
while (packed.length > 1 &&
|
||||||
packed.tail ().head < tail)
|
packed.tail ()->head < tail)
|
||||||
packed.pop ();
|
|
||||||
assert (packed.tail ().head == tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
void link ()
|
|
||||||
{
|
{
|
||||||
// XXX
|
packed_map.del (packed.tail ());
|
||||||
|
assert (!packed.tail ()->next);
|
||||||
|
packed.tail ()->fini ();
|
||||||
|
packed.pop ();
|
||||||
|
}
|
||||||
|
if (packed.length > 1)
|
||||||
|
assert (packed.tail ()->head == tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int length () const { return this->head - current.tail ().head; }
|
template <typename T>
|
||||||
|
void add_link (T &ofs, objidx_t objidx, const void *base = nullptr)
|
||||||
|
{
|
||||||
|
static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
|
||||||
|
|
||||||
|
if (!objidx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert (current);
|
||||||
|
assert (current->head <= (const char *) &ofs);
|
||||||
|
|
||||||
|
if (!base)
|
||||||
|
base = current->head;
|
||||||
|
else
|
||||||
|
assert (current->head <= (const char *) base);
|
||||||
|
|
||||||
|
auto& link = *current->links.push ();
|
||||||
|
link.is_wide = sizeof (T) == 4;
|
||||||
|
link.position = (const char *) &ofs - (const char *) base;
|
||||||
|
link.bias = (const char *) base - current->head;
|
||||||
|
link.objidx = objidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolve_links ()
|
||||||
|
{
|
||||||
|
assert (!current);
|
||||||
|
|
||||||
|
for (auto obj_it = ++hb_iter (packed); obj_it; ++obj_it)
|
||||||
|
{
|
||||||
|
const object_t &parent = **obj_it;
|
||||||
|
|
||||||
|
for (auto link_it = parent.links.iter (); link_it; ++link_it)
|
||||||
|
{
|
||||||
|
const object_t::link_t &link = *link_it;
|
||||||
|
const object_t &child = *packed[link.objidx];
|
||||||
|
unsigned offset = (child.head - parent.head) - link.bias;
|
||||||
|
|
||||||
|
if (link.is_wide)
|
||||||
|
{
|
||||||
|
auto &off = * ((BEInt<uint32_t, 4> *) (parent.head + link.position));
|
||||||
|
off = offset;
|
||||||
|
propagate_error (off == offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto &off = * ((BEInt<uint16_t, 2> *) (parent.head + link.position));
|
||||||
|
off = offset;
|
||||||
|
propagate_error (off == offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int length () const { return this->head - current->head; }
|
||||||
|
|
||||||
void align (unsigned int alignment)
|
void align (unsigned int alignment)
|
||||||
{
|
{
|
||||||
|
@ -326,11 +410,14 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/* Object memory pool. */
|
||||||
|
hb_pool_t<object_t> object_pool;
|
||||||
|
|
||||||
/* Stack of currently under construction objects. */
|
/* Stack of currently under construction objects. */
|
||||||
hb_vector_t<object_t> current;
|
object_t *current;
|
||||||
|
|
||||||
/* Stack of packed objects. Object 0 is always nil object. */
|
/* Stack of packed objects. Object 0 is always nil object. */
|
||||||
hb_vector_t<object_t> packed;
|
hb_vector_t<object_t *> packed;
|
||||||
|
|
||||||
/* Map view of packed objects. */
|
/* Map view of packed objects. */
|
||||||
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
|
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
|
||||||
|
|
|
@ -227,11 +227,18 @@ struct hb_set_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
if (unlikely (hb_object_is_immutable (this)))
|
||||||
|
return;
|
||||||
|
clear ();
|
||||||
|
successful = true;
|
||||||
|
}
|
||||||
|
|
||||||
void clear ()
|
void clear ()
|
||||||
{
|
{
|
||||||
if (unlikely (hb_object_is_immutable (this)))
|
if (unlikely (hb_object_is_immutable (this)))
|
||||||
return;
|
return;
|
||||||
successful = true;
|
|
||||||
population = 0;
|
population = 0;
|
||||||
page_map.resize (0);
|
page_map.resize (0);
|
||||||
pages.resize (0);
|
pages.resize (0);
|
||||||
|
|
|
@ -45,10 +45,6 @@ HB_SHAPER_IMPLEMENT (directwrite)
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_CORETEXT
|
#ifdef HAVE_CORETEXT
|
||||||
HB_SHAPER_IMPLEMENT (coretext)
|
HB_SHAPER_IMPLEMENT (coretext)
|
||||||
|
|
||||||
/* Only picks up fonts that have a "mort" or "morx" table.
|
|
||||||
Probably going to be removed https://github.com/harfbuzz/harfbuzz/issues/1478 */
|
|
||||||
HB_SHAPER_IMPLEMENT (coretext_aat)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FALLBACK
|
#ifdef HAVE_FALLBACK
|
||||||
|
|
|
@ -83,8 +83,10 @@ _subset2 (hb_subset_plan_t *plan)
|
||||||
}
|
}
|
||||||
retry:
|
retry:
|
||||||
hb_serialize_context_t serializer ((void *) buf, buf_size);
|
hb_serialize_context_t serializer ((void *) buf, buf_size);
|
||||||
|
serializer.start_serialize<TableType> ();
|
||||||
hb_subset_context_t c (plan, &serializer);
|
hb_subset_context_t c (plan, &serializer);
|
||||||
result = table->subset (&c);
|
result = table->subset (&c);
|
||||||
|
serializer.end_serialize ();
|
||||||
if (serializer.ran_out_of_room)
|
if (serializer.ran_out_of_room)
|
||||||
{
|
{
|
||||||
buf_size += (buf_size >> 1) + 32;
|
buf_size += (buf_size >> 1) + 32;
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct hb_vector_t
|
||||||
{
|
{
|
||||||
init ();
|
init ();
|
||||||
alloc (o.length);
|
alloc (o.length);
|
||||||
hb_iter (o) | hb_sink (this);
|
hb_copy (o, *this);
|
||||||
}
|
}
|
||||||
hb_vector_t (hb_vector_t &&o)
|
hb_vector_t (hb_vector_t &&o)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ struct hb_vector_t
|
||||||
{
|
{
|
||||||
reset ();
|
reset ();
|
||||||
alloc (o.length);
|
alloc (o.length);
|
||||||
hb_iter (o) | hb_sink (this);
|
hb_copy (o, *this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
hb_vector_t& operator = (hb_vector_t &&o)
|
hb_vector_t& operator = (hb_vector_t &&o)
|
||||||
|
@ -100,10 +100,11 @@ struct hb_vector_t
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_bytes_t as_bytes () const { return hb_bytes_t ((const char *) arrayZ_,
|
hb_bytes_t as_bytes () const
|
||||||
length * item_size); }
|
{ return hb_bytes_t ((const char *) arrayZ(), length * item_size); }
|
||||||
|
|
||||||
uint32_t hash () const { return as_bytes ().hash (); }
|
bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); }
|
||||||
|
uint32_t hash () const { return as_array ().hash (); }
|
||||||
|
|
||||||
const Type * arrayZ () const { return arrayZ_; }
|
const Type * arrayZ () const { return arrayZ_; }
|
||||||
Type * arrayZ () { return arrayZ_; }
|
Type * arrayZ () { return arrayZ_; }
|
||||||
|
|
89
src/hb.hh
89
src/hb.hh
|
@ -553,6 +553,95 @@ _hb_memalign(void **memptr, size_t alignment, size_t size)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Big-endian integers. Here because fundamental.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename Type, int Bytes> struct BEInt;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct BEInt<Type, 1>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BEInt<Type, 1>& operator = (Type V)
|
||||||
|
{
|
||||||
|
v = V;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator Type () const { return v; }
|
||||||
|
private: uint8_t v;
|
||||||
|
};
|
||||||
|
template <typename Type>
|
||||||
|
struct BEInt<Type, 2>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BEInt<Type, 2>& operator = (Type V)
|
||||||
|
{
|
||||||
|
v[0] = (V >> 8) & 0xFF;
|
||||||
|
v[1] = (V ) & 0xFF;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator Type () const
|
||||||
|
{
|
||||||
|
#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
|
||||||
|
defined(__BYTE_ORDER) && \
|
||||||
|
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
|
||||||
|
/* Spoon-feed the compiler a big-endian integer with alignment 1.
|
||||||
|
* https://github.com/harfbuzz/harfbuzz/pull/1398 */
|
||||||
|
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
return __builtin_bswap16 (((packed_uint16_t *) this)->v);
|
||||||
|
#else /* __BYTE_ORDER == __BIG_ENDIAN */
|
||||||
|
return ((packed_uint16_t *) this)->v;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return (v[0] << 8)
|
||||||
|
+ (v[1] );
|
||||||
|
}
|
||||||
|
private: uint8_t v[2];
|
||||||
|
};
|
||||||
|
template <typename Type>
|
||||||
|
struct BEInt<Type, 3>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BEInt<Type, 3>& operator = (Type V)
|
||||||
|
{
|
||||||
|
v[0] = (V >> 16) & 0xFF;
|
||||||
|
v[1] = (V >> 8) & 0xFF;
|
||||||
|
v[2] = (V ) & 0xFF;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator Type () const
|
||||||
|
{
|
||||||
|
return (v[0] << 16)
|
||||||
|
+ (v[1] << 8)
|
||||||
|
+ (v[2] );
|
||||||
|
}
|
||||||
|
private: uint8_t v[3];
|
||||||
|
};
|
||||||
|
template <typename Type>
|
||||||
|
struct BEInt<Type, 4>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BEInt<Type, 4>& operator = (Type V)
|
||||||
|
{
|
||||||
|
v[0] = (V >> 24) & 0xFF;
|
||||||
|
v[1] = (V >> 16) & 0xFF;
|
||||||
|
v[2] = (V >> 8) & 0xFF;
|
||||||
|
v[3] = (V ) & 0xFF;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator Type () const
|
||||||
|
{
|
||||||
|
return (v[0] << 24)
|
||||||
|
+ (v[1] << 16)
|
||||||
|
+ (v[2] << 8)
|
||||||
|
+ (v[3] );
|
||||||
|
}
|
||||||
|
private: uint8_t v[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For lack of a better place, put Zawgyi script hack here.
|
* For lack of a better place, put Zawgyi script hack here.
|
||||||
* https://github.com/harfbuzz/harfbuzz/issues/1162
|
* https://github.com/harfbuzz/harfbuzz/issues/1162
|
||||||
|
|
|
@ -120,8 +120,8 @@ main (int argc, char **argv)
|
||||||
hb_iter (src, 2);
|
hb_iter (src, 2);
|
||||||
|
|
||||||
hb_fill (t, 42);
|
hb_fill (t, 42);
|
||||||
hb_copy (t, s);
|
hb_copy (s, t);
|
||||||
// hb_copy (t, a.iter ());
|
hb_copy (a.iter (), t);
|
||||||
|
|
||||||
test_iterable (v);
|
test_iterable (v);
|
||||||
hb_set_t st;
|
hb_set_t st;
|
||||||
|
@ -154,6 +154,41 @@ main (int argc, char **argv)
|
||||||
| hb_apply (&st)
|
| hb_apply (&st)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
+ hb_iter (src)
|
||||||
|
| hb_map ([&] (int i) -> int { return 1; })
|
||||||
|
| hb_reduce ([&] (int acc, int value) -> int { return acc; }, 2)
|
||||||
|
;
|
||||||
|
|
||||||
|
unsigned int temp1 = 10;
|
||||||
|
unsigned int temp2 = 0;
|
||||||
|
hb_map_t *result =
|
||||||
|
+ hb_iter (src)
|
||||||
|
| hb_map ([&] (int i) -> hb_set_t *
|
||||||
|
{
|
||||||
|
hb_set_t *set = hb_set_create ();
|
||||||
|
for (unsigned int i = 0; i < temp1; ++i)
|
||||||
|
hb_set_add (set, i);
|
||||||
|
temp1++;
|
||||||
|
return set;
|
||||||
|
})
|
||||||
|
| hb_reduce ([&] (hb_map_t *acc, hb_set_t *value) -> hb_map_t *
|
||||||
|
{
|
||||||
|
hb_map_set (acc, temp2++, hb_set_get_population (value));
|
||||||
|
/* This is not a memory managed language, take care! */
|
||||||
|
hb_set_destroy (value);
|
||||||
|
return acc;
|
||||||
|
}, hb_map_create ())
|
||||||
|
;
|
||||||
|
/* The result should be something like 0->10, 1->11, ..., 9->19 */
|
||||||
|
assert (hb_map_get (result, 9) == 19);
|
||||||
|
|
||||||
|
unsigned int temp3 = 0;
|
||||||
|
+ hb_iter(src)
|
||||||
|
| hb_map([&] (int i) -> int { return ++temp3; })
|
||||||
|
| hb_reduce([&] (float acc, int value) -> float { return acc + value; }, 0)
|
||||||
|
;
|
||||||
|
hb_map_destroy (result);
|
||||||
|
|
||||||
+ hb_iter (src)
|
+ hb_iter (src)
|
||||||
| hb_drain
|
| hb_drain
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue