diff --git a/src/Makefile.sources b/src/Makefile.sources index 79a47a396..5c2e02bca 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -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 \ diff --git a/src/hb-array.hh b/src/hb-array.hh index 16f53cc8f..9382db31e 100644 --- a/src/hb-array.hh +++ b/src/hb-array.hh @@ -79,6 +79,7 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> operator hb_array_t () { return hb_array_t (arrayZ, length); } template operator T * () const { return arrayZ; } + bool operator == (const hb_array_t &o) const; uint32_t hash () const; /* @@ -275,19 +276,29 @@ template inline hb_sorted_array_t hb_sorted_array (T (&array_)[length_]) { return hb_sorted_array_t (array_); } +template +bool hb_array_t::operator == (const hb_array_t &o) const +{ + return length == o.length && + + hb_zip (*this, o) + | hb_map ([] (hb_pair_t &&_) -> bool { return _.first == _.second; }) + | hb_all + ; +} template uint32_t hb_array_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 hb_bytes_t; typedef hb_array_t 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::hash () const { return 0; } diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 598930678..23f1c8415 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -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); -} diff --git a/src/hb-iter.hh b/src/hb-iter.hh index 203a3c7ef..f23904c22 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh @@ -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 iter_t& operator >> (T &v) { v = **thiz(); ++*thiz(); return *thiz(); } template + iter_t& operator >> (T &v) const { v = **thiz(); ++*thiz(); return *thiz(); } + template 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 (p, f); } } hb_filter HB_UNUSED; +template +struct hb_reduce_t +{ + hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {} + + template + 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 + hb_reduce_t + operator () (Redu&& r, InitT init_value) const + { return hb_reduce_t (r, init_value); } +} hb_reduce HB_UNUSED; + + /* hb_zip() */ template @@ -585,14 +619,11 @@ hb_fill (C& c, const V &v) *i = v; } -template -inline bool -hb_copy (D id, S is) +template +inline void +hb_copy (S&& is, D&& id) { - for (; id && is; ++id, ++is) - *id = *is; - return !is; + hb_iter (is) | hb_sink (id); } diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 095462eab..5a2087e4a 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -144,94 +144,6 @@ static inline Type& StructAfter(TObject &X) DEFINE_SIZE_ARRAY(size, array) -/* - * Big-endian integers. - */ - -template struct BEInt; - -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v = V; - return *this; - } - operator Type () const { return v; } - private: uint8_t v; -}; -template -struct BEInt -{ - public: - BEInt& 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 -struct BEInt -{ - public: - BEInt& 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 -struct BEInt -{ - public: - BEInt& 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. diff --git a/src/hb-map.hh b/src/hb-map.hh index f5c999170..834a99497 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -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; } diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 26df8e776..761a70f58 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -281,16 +281,24 @@ struct OffsetTo : Offset } template - 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 diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 53b914a17..add5325a4 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -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 bool serialize (hb_serialize_context_t *c, const hb_sorted_vector_t &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::serialize (c, groups); + return_trace (CmapSubtableLongSegmented::serialize (c, groups)); } static size_t get_sub_table_size (const hb_sorted_vector_t &groups) diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 7d0fa2436..03aef0749 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -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++; diff --git a/src/hb-pool.hh b/src/hb-pool.hh new file mode 100644 index 000000000..ff0ee194c --- /dev/null +++ b/src/hb-pool.hh @@ -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 +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 chunks; +}; + + +#endif /* HB_POOL_HH */ diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index ab07080b8..e1c283c1e 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.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 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 (); } 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 + template 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 (); } 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 + 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 *) (parent.head + link.position)); + off = offset; + propagate_error (off == offset); + } + else + { + auto &off = * ((BEInt *) (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_pool; + /* Stack of currently under construction objects. */ - hb_vector_t current; + object_t *current; /* Stack of packed objects. Object 0 is always nil object. */ - hb_vector_t packed; + hb_vector_t packed; /* Map view of packed objects. */ hb_hashmap_t packed_map; diff --git a/src/hb-set.hh b/src/hb-set.hh index 5d48412db..34498d9a8 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -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); diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh index 36d8fc7f6..25c584bc0 100644 --- a/src/hb-shaper-list.hh +++ b/src/hb-shaper-list.hh @@ -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 diff --git a/src/hb-subset.cc b/src/hb-subset.cc index b73638ced..c0bfcbe50 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -83,8 +83,10 @@ _subset2 (hb_subset_plan_t *plan) } retry: hb_serialize_context_t serializer ((void *) buf, buf_size); + serializer.start_serialize (); 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; diff --git a/src/hb-vector.hh b/src/hb-vector.hh index 4621b5134..e0b7fb0cb 100644 --- a/src/hb-vector.hh +++ b/src/hb-vector.hh @@ -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_; } diff --git a/src/hb.hh b/src/hb.hh index 9043de403..896b59025 100644 --- a/src/hb.hh +++ b/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 struct BEInt; + +template +struct BEInt +{ + public: + BEInt& operator = (Type V) + { + v = V; + return *this; + } + operator Type () const { return v; } + private: uint8_t v; +}; +template +struct BEInt +{ + public: + BEInt& 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 +struct BEInt +{ + public: + BEInt& 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 +struct BEInt +{ + public: + BEInt& 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 diff --git a/src/test-iter.cc b/src/test-iter.cc index bc45488eb..675bbe397 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -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 ;