Merge branch 'master' into var-subset

This commit is contained in:
Michiharu Ariza 2019-04-03 10:34:09 -07:00
commit b999ce9bf0
17 changed files with 488 additions and 245 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

102
src/hb-pool.hh Normal file
View 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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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