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.cc \
|
||||
hb-ot-vorg-table.hh \
|
||||
hb-pool.hh \
|
||||
hb-sanitize.hh \
|
||||
hb-serialize.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); }
|
||||
template <typename T> operator T * () const { return arrayZ; }
|
||||
|
||||
bool operator == (const hb_array_t &o) 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_])
|
||||
{ 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>
|
||||
uint32_t hb_array_t<T>::hash () const
|
||||
{
|
||||
uint32_t h = 0;
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
h ^= hb_hash (arrayZ[i]);
|
||||
return h;
|
||||
return
|
||||
+ hb_iter (*this)
|
||||
| hb_map (hb_hash)
|
||||
| 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 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 <>
|
||||
//uint32_t hb_array_t<const char>::hash () const { return 0; }
|
||||
|
||||
|
@ -1148,59 +1148,3 @@ fail:
|
||||
|
||||
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_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
|
||||
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) { return thiz()->__item_at__ (i); }
|
||||
iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
|
||||
@ -90,6 +92,8 @@ struct hb_iter_t
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
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(); }
|
||||
|
||||
protected:
|
||||
@ -344,6 +348,36 @@ static const struct
|
||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||
} 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() */
|
||||
|
||||
template <typename A, typename B>
|
||||
@ -585,14 +619,11 @@ hb_fill (C& c, const V &v)
|
||||
*i = v;
|
||||
}
|
||||
|
||||
template <typename S, typename D,
|
||||
hb_enable_if (hb_is_iterator (S) && hb_is_iterator (D))>
|
||||
inline bool
|
||||
hb_copy (D id, S is)
|
||||
template <typename S, typename D>
|
||||
inline void
|
||||
hb_copy (S&& is, D&& id)
|
||||
{
|
||||
for (; id && is; ++id, ++is)
|
||||
*id = *is;
|
||||
return !is;
|
||||
hb_iter (is) | hb_sink (id);
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,94 +144,6 @@ static inline Type& StructAfter(TObject &X)
|
||||
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.
|
||||
|
@ -57,10 +57,13 @@ struct hb_hashmap_t
|
||||
K key;
|
||||
V value;
|
||||
|
||||
bool operator== (K o) { return hb_deref_pointer (key) == hb_deref_pointer (o); }
|
||||
bool operator== (const item_t &o) { return *this == o.key; }
|
||||
void clear () { key = kINVALID; value = vINVALID; }
|
||||
|
||||
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_tombstone () const { return key != kINVALID && value == vINVALID; }
|
||||
bool is_real () const { return key != kINVALID && value != vINVALID; }
|
||||
};
|
||||
|
||||
hb_object_header_t header;
|
||||
@ -98,9 +101,10 @@ struct hb_hashmap_t
|
||||
|
||||
void reset ()
|
||||
{
|
||||
/* TODO Keep array? */
|
||||
fini_shallow ();
|
||||
init_shallow ();
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
successful = true;
|
||||
clear ();
|
||||
}
|
||||
|
||||
bool in_error () const { return !successful; }
|
||||
@ -117,7 +121,9 @@ struct hb_hashmap_t
|
||||
successful = 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;
|
||||
item_t *old_items = items;
|
||||
@ -131,7 +137,7 @@ struct hb_hashmap_t
|
||||
/* Insert back old items. */
|
||||
if (old_items)
|
||||
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);
|
||||
|
||||
free (old_items);
|
||||
@ -168,7 +174,7 @@ struct hb_hashmap_t
|
||||
{
|
||||
if (unlikely (!items)) return vINVALID;
|
||||
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); }
|
||||
@ -183,7 +189,13 @@ struct hb_hashmap_t
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -281,16 +281,24 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
}
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
serialize (c->serializer, base);
|
||||
if (!src.subset (c))
|
||||
*this = 0;
|
||||
*this = 0;
|
||||
if (has_null && &src == &Null (T))
|
||||
return false;
|
||||
|
||||
auto *s = c->serializer;
|
||||
|
||||
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
|
||||
|
@ -495,7 +495,7 @@ struct CmapSubtableLongSegmented
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);
|
||||
return true;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -520,13 +520,14 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
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->reserved = 0;
|
||||
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)
|
||||
|
@ -922,12 +922,13 @@ struct CoverageFormat2
|
||||
{
|
||||
if (glyphs[i - 1] + 1 != glyphs[i])
|
||||
{
|
||||
rangeRecord[range].end = glyphs[i - 1];
|
||||
range++;
|
||||
rangeRecord[range].start = glyphs[i];
|
||||
rangeRecord[range].value = i;
|
||||
}
|
||||
rangeRecord[range].end = glyphs[i];
|
||||
}
|
||||
rangeRecord[range].end = glyphs[count - 1];
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -1353,8 +1354,9 @@ struct ClassDefFormat2
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
unsigned int count = glyphs.len ();
|
||||
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] ||
|
||||
klasses[i - 1] != klasses[i])
|
||||
num_ranges++;
|
||||
@ -1364,17 +1366,18 @@ struct ClassDefFormat2
|
||||
unsigned int range = 0;
|
||||
rangeRecord[range].start = glyphs[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] ||
|
||||
klasses[i - 1] != klasses[i])
|
||||
{
|
||||
rangeRecord[range].end = glyphs[i - 1];
|
||||
range++;
|
||||
rangeRecord[range].start = glyphs[i];
|
||||
rangeRecord[range].value = klasses[i];
|
||||
}
|
||||
rangeRecord[range].end = glyphs[i];
|
||||
}
|
||||
rangeRecord[range].end = glyphs[count - 1];
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -1511,8 +1514,9 @@ struct ClassDef
|
||||
hb_codepoint_t glyph_min = glyphs[0];
|
||||
hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
|
||||
|
||||
unsigned int count = glyphs.len ();
|
||||
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] ||
|
||||
klasses[i - 1] != klasses[i])
|
||||
num_ranges++;
|
||||
|
102
src/hb-pool.hh
Normal file
102
src/hb-pool.hh
Normal file
@ -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 © 2012,2018 Google, Inc.
|
||||
* Copyright © 2019 Facebook, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
@ -24,6 +25,7 @@
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_SERIALIZE_HH
|
||||
@ -32,6 +34,7 @@
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.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
|
||||
{
|
||||
return (tail - head == o.tail - o.head)
|
||||
&& (links.length != o.links.length)
|
||||
&& 0 == memcmp (head, o.head, tail - head)
|
||||
&& 0 == memcmp (&links, &o.links, links.get_size ());
|
||||
&& (links.length == o.links.length)
|
||||
&& 0 == hb_memcmp (head, o.head, tail - head)
|
||||
&& links.as_bytes () == o.links.as_bytes ();
|
||||
}
|
||||
uint32_t hash () const
|
||||
{
|
||||
@ -66,28 +69,41 @@ struct hb_serialize_context_t
|
||||
|
||||
struct link_t
|
||||
{
|
||||
bool wide: 1;
|
||||
unsigned offset : 31;
|
||||
bool is_wide: 1;
|
||||
unsigned position : 31;
|
||||
int bias;
|
||||
objidx_t objidx;
|
||||
};
|
||||
|
||||
hb_vector_t<link_t> links;
|
||||
object_t *next;
|
||||
};
|
||||
|
||||
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_;
|
||||
this->end = this->start + size;
|
||||
reset ();
|
||||
}
|
||||
~hb_serialize_context_t ()
|
||||
{
|
||||
current.fini_deep ();
|
||||
packed.fini_deep ();
|
||||
packed_map.fini ();
|
||||
++ hb_iter (packed)
|
||||
| hb_apply ([] (object_t *_) { _->fini (); })
|
||||
;
|
||||
packed.fini ();
|
||||
this->packed_map.fini ();
|
||||
|
||||
while (current)
|
||||
{
|
||||
auto *_ = current;
|
||||
current = current->next;
|
||||
_->fini ();
|
||||
}
|
||||
object_pool.fini ();
|
||||
}
|
||||
|
||||
bool in_error () const { return !this->successful; }
|
||||
@ -100,10 +116,8 @@ struct hb_serialize_context_t
|
||||
this->tail = this->end;
|
||||
this->debug_depth = 0;
|
||||
|
||||
this->current.reset ();
|
||||
this->packed.reset ();
|
||||
this->packed.push ()->head = this->end;
|
||||
this->packed_map.reset ();
|
||||
fini ();
|
||||
this->packed.push (nullptr);
|
||||
}
|
||||
|
||||
bool propagate_error (bool e)
|
||||
@ -127,7 +141,7 @@ struct hb_serialize_context_t
|
||||
this->start, this->end,
|
||||
(unsigned long) (this->end - this->start));
|
||||
|
||||
assert (!current.length);
|
||||
assert (!current);
|
||||
return push<Type> ();
|
||||
}
|
||||
void end_serialize ()
|
||||
@ -138,9 +152,10 @@ struct hb_serialize_context_t
|
||||
(unsigned) (this->head - this->start),
|
||||
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.
|
||||
* Saves a move. */
|
||||
@ -149,54 +164,69 @@ struct hb_serialize_context_t
|
||||
|
||||
pop_pack ();
|
||||
|
||||
link ();
|
||||
resolve_links ();
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template <typename Type = void>
|
||||
Type *push ()
|
||||
{
|
||||
object_t obj;
|
||||
obj.head = head;
|
||||
obj.tail = tail;
|
||||
current.push (obj);
|
||||
object_t *obj = object_pool.alloc ();
|
||||
if (unlikely (!obj))
|
||||
propagate_error (false);
|
||||
else
|
||||
{
|
||||
obj->head = head;
|
||||
obj->tail = tail;
|
||||
obj->next = current;
|
||||
current = obj;
|
||||
}
|
||||
return start_embed<Type> ();
|
||||
}
|
||||
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 ()
|
||||
{
|
||||
object_t obj = current.pop ();
|
||||
obj.tail = head;
|
||||
unsigned len = obj.tail - obj.head;
|
||||
object_t *obj = current;
|
||||
if (unlikely (!obj)) return 0;
|
||||
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)
|
||||
{
|
||||
obj.fini ();
|
||||
obj->fini ();
|
||||
return objidx;
|
||||
}
|
||||
|
||||
tail -= len;
|
||||
memmove (tail, obj.head, len);
|
||||
head = obj.head;
|
||||
memmove (tail, obj->head, len);
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
obj->head = tail;
|
||||
obj->tail = tail + len;
|
||||
|
||||
obj.head = tail;
|
||||
obj.tail = tail + len;
|
||||
packed.push (obj);
|
||||
|
||||
object_t *key = packed.push (hb_move (obj));
|
||||
|
||||
/* TODO Handle error. */
|
||||
if (unlikely (packed.in_error ()))
|
||||
return 0;
|
||||
|
||||
objidx = packed.length - 1;
|
||||
|
||||
packed_map.set (key, objidx);
|
||||
packed_map.set (obj, objidx);
|
||||
|
||||
return objidx;
|
||||
}
|
||||
@ -213,17 +243,71 @@ struct hb_serialize_context_t
|
||||
void discard_stale_objects ()
|
||||
{
|
||||
while (packed.length > 1 &&
|
||||
packed.tail ().head < tail)
|
||||
packed.tail ()->head < tail)
|
||||
{
|
||||
packed_map.del (packed.tail ());
|
||||
assert (!packed.tail ()->next);
|
||||
packed.tail ()->fini ();
|
||||
packed.pop ();
|
||||
assert (packed.tail ().head == tail);
|
||||
}
|
||||
if (packed.length > 1)
|
||||
assert (packed.tail ()->head == tail);
|
||||
}
|
||||
|
||||
void link ()
|
||||
template <typename T>
|
||||
void add_link (T &ofs, objidx_t objidx, const void *base = nullptr)
|
||||
{
|
||||
// XXX
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int length () const { return this->head - current.tail ().head; }
|
||||
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)
|
||||
{
|
||||
@ -326,11 +410,14 @@ struct hb_serialize_context_t
|
||||
|
||||
private:
|
||||
|
||||
/* Object memory pool. */
|
||||
hb_pool_t<object_t> object_pool;
|
||||
|
||||
/* 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. */
|
||||
hb_vector_t<object_t> packed;
|
||||
hb_vector_t<object_t *> packed;
|
||||
|
||||
/* Map view of packed objects. */
|
||||
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
|
||||
|
@ -227,11 +227,18 @@ struct hb_set_t
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
clear ();
|
||||
successful = true;
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
successful = true;
|
||||
population = 0;
|
||||
page_map.resize (0);
|
||||
pages.resize (0);
|
||||
|
@ -45,10 +45,6 @@ HB_SHAPER_IMPLEMENT (directwrite)
|
||||
#endif
|
||||
#ifdef HAVE_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
|
||||
|
||||
#ifdef HAVE_FALLBACK
|
||||
|
@ -83,8 +83,10 @@ _subset2 (hb_subset_plan_t *plan)
|
||||
}
|
||||
retry:
|
||||
hb_serialize_context_t serializer ((void *) buf, buf_size);
|
||||
serializer.start_serialize<TableType> ();
|
||||
hb_subset_context_t c (plan, &serializer);
|
||||
result = table->subset (&c);
|
||||
serializer.end_serialize ();
|
||||
if (serializer.ran_out_of_room)
|
||||
{
|
||||
buf_size += (buf_size >> 1) + 32;
|
||||
|
@ -43,7 +43,7 @@ struct hb_vector_t
|
||||
{
|
||||
init ();
|
||||
alloc (o.length);
|
||||
hb_iter (o) | hb_sink (this);
|
||||
hb_copy (o, *this);
|
||||
}
|
||||
hb_vector_t (hb_vector_t &&o)
|
||||
{
|
||||
@ -87,7 +87,7 @@ struct hb_vector_t
|
||||
{
|
||||
reset ();
|
||||
alloc (o.length);
|
||||
hb_iter (o) | hb_sink (this);
|
||||
hb_copy (o, *this);
|
||||
return *this;
|
||||
}
|
||||
hb_vector_t& operator = (hb_vector_t &&o)
|
||||
@ -100,10 +100,11 @@ struct hb_vector_t
|
||||
return *this;
|
||||
}
|
||||
|
||||
hb_bytes_t as_bytes () const { return hb_bytes_t ((const char *) arrayZ_,
|
||||
length * item_size); }
|
||||
hb_bytes_t as_bytes () const
|
||||
{ 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_; }
|
||||
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
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1162
|
||||
|
@ -120,8 +120,8 @@ main (int argc, char **argv)
|
||||
hb_iter (src, 2);
|
||||
|
||||
hb_fill (t, 42);
|
||||
hb_copy (t, s);
|
||||
// hb_copy (t, a.iter ());
|
||||
hb_copy (s, t);
|
||||
hb_copy (a.iter (), t);
|
||||
|
||||
test_iterable (v);
|
||||
hb_set_t st;
|
||||
@ -154,6 +154,41 @@ main (int argc, char **argv)
|
||||
| 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_drain
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user