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.cc \
hb-ot-vorg-table.hh \
hb-pool.hh \
hb-sanitize.hh \
hb-serialize.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); }
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; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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