diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 743a736d8..801834e51 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -338,11 +338,15 @@ struct OffsetTo : Offset } /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ + /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 + * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... + */ template bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, const void *src_base, const void *dst_base, + hb_serialize_context_t::whence_t whence, Ts&&... ds) { *this = 0; @@ -353,11 +357,17 @@ struct OffsetTo : Offset bool ret = c->copy (src_base+src, hb_forward (ds)...); - c->add_link (*this, c->pop_pack (), dst_base); + c->add_link (*this, c->pop_pack (), dst_base, whence); return ret; } + bool serialize_copy (hb_serialize_context_t *c, + const OffsetTo& src, + const void *src_base, + const void *dst_base) + { return serialize_copy (c, src, src_base, dst_base, hb_serialize_context_t::Head); } + bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh index 46f87d930..d43b84cb0 100644 --- a/src/hb-ot-name-table.hh +++ b/src/hb-ot-name-table.hh @@ -98,13 +98,12 @@ struct NameRecord } NameRecord* copy (hb_serialize_context_t *c, - const void *src_base, - const void *dst_base) const + const void *src_base) const { TRACE_SERIALIZE (this); auto *out = c->embed (this); if (unlikely (!out)) return_trace (nullptr); - out->offset.serialize_copy (c, offset, src_base, dst_base, length); + out->offset.serialize_copy (c, offset, src_base, nullptr, hb_serialize_context_t::Tail, length); return_trace (out); } @@ -216,13 +215,6 @@ struct name this->format = 0; this->count = it.len (); - auto snap = c->snapshot (); - this->nameRecordZ.serialize (c, this->count); - if (unlikely (!c->check_assign (this->stringOffset, c->length ()))) return_trace (false); - c->revert (snap); - - const void *dst_string_pool = &(this + this->stringOffset); - NameRecord *name_records = (NameRecord *) calloc (it.len (), NameRecord::static_size); hb_array_t records (name_records, it.len ()); @@ -234,12 +226,12 @@ struct name records.qsort (); - c->copy_all (records, src_string_pool, dst_string_pool); + c->copy_all (records, src_string_pool); free (records.arrayZ); if (unlikely (c->ran_out_of_room)) return_trace (false); - assert (this->stringOffset == c->length ()); + this->stringOffset = c->length (); return_trace (true); } diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 454b23786..21e8bcc23 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -50,6 +50,12 @@ struct hb_serialize_context_t char *head, *tail; }; + enum whence_t { + Head, /* Relative to the current object head (default). */ + Tail, /* Relative to the current object tail after packed. */ + Absolute /* Absolute: from the start of the serialize buffer. */ + }; + struct object_t : range_t { void fini () { links.fini (); } @@ -70,7 +76,9 @@ struct hb_serialize_context_t struct link_t { bool is_wide: 1; - unsigned position : 31; + bool is_signed: 1; + unsigned whence: 2; + unsigned position: 28; unsigned bias; objidx_t objidx; }; @@ -269,7 +277,9 @@ struct hb_serialize_context_t } template - void add_link (T &ofs, objidx_t objidx, const void *base = nullptr) + void add_link (T &ofs, objidx_t objidx, + const void *base = nullptr, + whence_t whence = Head) { static_assert (sizeof (T) == 2 || sizeof (T) == 4, ""); @@ -279,15 +289,24 @@ struct hb_serialize_context_t 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.is_signed = hb_is_signed (hb_unwrap_type (T)); + link.whence = (unsigned)whence; link.position = (const char *) &ofs - current->head; - link.bias = (const char *) base - current->head; + if (whence == Head) + { + if (base == nullptr) + link.bias = 0; + else + { + assert (current->head <= (const char *)base); + link.bias = (const char *) base - current->head; + } + } + else + link.bias = 0; link.objidx = objidx; } @@ -302,20 +321,28 @@ struct hb_serialize_context_t for (const object_t::link_t &link : parent->links) { const object_t* child = packed[link.objidx]; - assert (link.bias <= (size_t) (parent->tail - parent->head)); - unsigned offset = (child->head - parent->head) - link.bias; + if (unlikely (!child)) { err_other_error(); return; } + unsigned offset; + switch ((whence_t)link.whence) { + case Head: offset = (child->head - parent->head) - link.bias; break; + case Tail: offset = child->head - parent->tail; break; + case Absolute: offset = (head - start) + (child->head - tail); break; + default: assert (0); + } - if (link.is_wide) + if (link.is_signed) { - auto &off = * ((BEInt *) (parent->head + link.position)); - assert (0 == off); - check_assign (off, offset); + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); } else { - auto &off = * ((BEInt *) (parent->head + link.position)); - assert (0 == off); - check_assign (off, offset); + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); } } } @@ -456,6 +483,15 @@ struct hb_serialize_context_t (char *) b.arrayZ, free); } + private: + template + void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) + { + auto &off = * ((BEInt *) (parent->head + link.position)); + assert (0 == off); + check_assign (off, offset); + } + public: /* TODO Make private. */ char *start, *head, *tail, *end; unsigned int debug_depth;