You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-24 15:26:15 +00:00
HarfBuzz: Update to version 3.0.0
This commit is contained in:
146
thirdparty/harfbuzz/src/hb-serialize.hh
vendored
146
thirdparty/harfbuzz/src/hb-serialize.hh
vendored
@@ -41,6 +41,16 @@
|
||||
* Serialize
|
||||
*/
|
||||
|
||||
enum hb_serialize_error_t {
|
||||
HB_SERIALIZE_ERROR_NONE = 0x00000000u,
|
||||
HB_SERIALIZE_ERROR_OTHER = 0x00000001u,
|
||||
HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u,
|
||||
HB_SERIALIZE_ERROR_OUT_OF_ROOM = 0x00000004u,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW = 0x00000008u,
|
||||
HB_SERIALIZE_ERROR_ARRAY_OVERFLOW = 0x00000010u
|
||||
};
|
||||
HB_MARK_AS_FLAG_T (hb_serialize_error_t);
|
||||
|
||||
struct hb_serialize_context_t
|
||||
{
|
||||
typedef unsigned objidx_t;
|
||||
@@ -51,6 +61,8 @@ struct hb_serialize_context_t
|
||||
Absolute /* Absolute: from the start of the serialize buffer. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct object_t
|
||||
{
|
||||
void fini () { links.fini (); }
|
||||
@@ -70,7 +82,7 @@ struct hb_serialize_context_t
|
||||
|
||||
struct link_t
|
||||
{
|
||||
bool is_wide: 1;
|
||||
unsigned width: 3;
|
||||
bool is_signed: 1;
|
||||
unsigned whence: 2;
|
||||
unsigned position: 28;
|
||||
@@ -90,10 +102,11 @@ struct hb_serialize_context_t
|
||||
char *tail;
|
||||
object_t *current; // Just for sanity check
|
||||
unsigned num_links;
|
||||
hb_serialize_error_t errors;
|
||||
};
|
||||
|
||||
snapshot_t snapshot ()
|
||||
{ return snapshot_t { head, tail, current, current->links.length }; }
|
||||
{ return snapshot_t { head, tail, current, current->links.length, errors }; }
|
||||
|
||||
hb_serialize_context_t (void *start_, unsigned int size) :
|
||||
start ((char *) start_),
|
||||
@@ -117,30 +130,60 @@ struct hb_serialize_context_t
|
||||
object_pool.fini ();
|
||||
}
|
||||
|
||||
bool in_error () const { return !this->successful; }
|
||||
bool in_error () const { return bool (errors); }
|
||||
|
||||
bool successful () const { return !bool (errors); }
|
||||
|
||||
HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
|
||||
HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||
HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
|
||||
HB_NODISCARD bool only_overflow () const
|
||||
{
|
||||
return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
|
||||
|| errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
|
||||
|| errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
|
||||
}
|
||||
|
||||
void reset (void *start_, unsigned int size)
|
||||
{
|
||||
start = (char*) start_;
|
||||
end = start + size;
|
||||
reset ();
|
||||
current = nullptr;
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
this->successful = true;
|
||||
this->ran_out_of_room = false;
|
||||
this->errors = HB_SERIALIZE_ERROR_NONE;
|
||||
this->head = this->start;
|
||||
this->tail = this->end;
|
||||
this->debug_depth = 0;
|
||||
|
||||
fini ();
|
||||
this->packed.push (nullptr);
|
||||
this->packed_map.init ();
|
||||
}
|
||||
|
||||
bool check_success (bool success)
|
||||
{ return this->successful && (success || (err_other_error (), false)); }
|
||||
bool check_success (bool success,
|
||||
hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER)
|
||||
{
|
||||
return successful ()
|
||||
&& (success || err (err_type));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
bool check_equal (T1 &&v1, T2 &&v2)
|
||||
{ return check_success ((long long) v1 == (long long) v2); }
|
||||
bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type)
|
||||
{
|
||||
if ((long long) v1 != (long long) v2)
|
||||
{
|
||||
return err (err_type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
bool check_assign (T1 &v1, T2 &&v2)
|
||||
{ return check_equal (v1 = v2, v2); }
|
||||
bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type)
|
||||
{ return check_equal (v1 = v2, v2, err_type); }
|
||||
|
||||
template <typename T> bool propagate_error (T &&obj)
|
||||
{ return check_success (!hb_deref (obj).in_error ()); }
|
||||
@@ -167,12 +210,18 @@ struct hb_serialize_context_t
|
||||
"end [%p..%p] serialized %u bytes; %s",
|
||||
this->start, this->end,
|
||||
(unsigned) (this->head - this->start),
|
||||
this->successful ? "successful" : "UNSUCCESSFUL");
|
||||
successful () ? "successful" : "UNSUCCESSFUL");
|
||||
|
||||
propagate_error (packed, packed_map);
|
||||
|
||||
if (unlikely (!current)) return;
|
||||
if (unlikely (in_error())) return;
|
||||
if (unlikely (in_error()))
|
||||
{
|
||||
// Offset overflows that occur before link resolution cannot be handled
|
||||
// by repacking, so set a more general error.
|
||||
if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER);
|
||||
return;
|
||||
}
|
||||
|
||||
assert (!current->next);
|
||||
|
||||
@@ -212,7 +261,7 @@ struct hb_serialize_context_t
|
||||
current = current->next;
|
||||
revert (obj->head, obj->tail);
|
||||
obj->fini ();
|
||||
object_pool.free (obj);
|
||||
object_pool.release (obj);
|
||||
}
|
||||
|
||||
/* Set share to false when an object is unlikely sharable with others
|
||||
@@ -275,9 +324,11 @@ struct hb_serialize_context_t
|
||||
|
||||
void revert (snapshot_t snap)
|
||||
{
|
||||
if (unlikely (in_error ())) return;
|
||||
// Overflows that happened after the snapshot will be erased by the revert.
|
||||
if (unlikely (in_error () && !only_overflow ())) return;
|
||||
assert (snap.current == current);
|
||||
current->links.shrink (snap.num_links);
|
||||
errors = snap.errors;
|
||||
revert (snap.head, snap.tail);
|
||||
}
|
||||
|
||||
@@ -312,7 +363,6 @@ struct hb_serialize_context_t
|
||||
whence_t whence = Head,
|
||||
unsigned bias = 0)
|
||||
{
|
||||
static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
|
||||
if (unlikely (in_error ())) return;
|
||||
|
||||
if (!objidx)
|
||||
@@ -322,8 +372,10 @@ struct hb_serialize_context_t
|
||||
assert (current->head <= (const char *) &ofs);
|
||||
|
||||
auto& link = *current->links.push ();
|
||||
if (current->links.in_error ())
|
||||
err (HB_SERIALIZE_ERROR_OTHER);
|
||||
|
||||
link.is_wide = sizeof (T) == 4;
|
||||
link.width = sizeof (T);
|
||||
link.is_signed = hb_is_signed (hb_unwrap_type (T));
|
||||
link.whence = (unsigned) whence;
|
||||
link.position = (const char *) &ofs - current->head;
|
||||
@@ -351,7 +403,7 @@ struct hb_serialize_context_t
|
||||
for (const object_t::link_t &link : parent->links)
|
||||
{
|
||||
const object_t* child = packed[link.objidx];
|
||||
if (unlikely (!child)) { err_other_error(); return; }
|
||||
if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
|
||||
unsigned offset = 0;
|
||||
switch ((whence_t) link.whence) {
|
||||
case Head: offset = child->head - parent->head; break;
|
||||
@@ -363,15 +415,19 @@ struct hb_serialize_context_t
|
||||
offset -= link.bias;
|
||||
if (link.is_signed)
|
||||
{
|
||||
if (link.is_wide)
|
||||
assert (link.width == 2 || link.width == 4);
|
||||
if (link.width == 4)
|
||||
assign_offset<int32_t> (parent, link, offset);
|
||||
else
|
||||
assign_offset<int16_t> (parent, link, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.is_wide)
|
||||
assert (link.width == 2 || link.width == 3 || link.width == 4);
|
||||
if (link.width == 4)
|
||||
assign_offset<uint32_t> (parent, link, offset);
|
||||
else if (link.width == 3)
|
||||
assign_offset<uint32_t, 3> (parent, link, offset);
|
||||
else
|
||||
assign_offset<uint16_t> (parent, link, offset);
|
||||
}
|
||||
@@ -398,22 +454,22 @@ struct hb_serialize_context_t
|
||||
Type *start_embed (const Type &obj) const
|
||||
{ return start_embed (hb_addressof (obj)); }
|
||||
|
||||
/* Following two functions exist to allow setting breakpoint on. */
|
||||
void err_ran_out_of_room () { this->ran_out_of_room = true; }
|
||||
void err_other_error () { this->successful = false; }
|
||||
bool err (hb_serialize_error_t err_type)
|
||||
{
|
||||
return !bool ((errors = (errors | err_type)));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *allocate_size (unsigned int size)
|
||||
Type *allocate_size (size_t size)
|
||||
{
|
||||
if (unlikely (!this->successful)) return nullptr;
|
||||
if (unlikely (in_error ())) return nullptr;
|
||||
|
||||
if (this->tail - this->head < ptrdiff_t (size))
|
||||
if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
|
||||
{
|
||||
err_ran_out_of_room ();
|
||||
this->successful = false;
|
||||
err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
hb_memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
@@ -468,18 +524,19 @@ struct hb_serialize_context_t
|
||||
hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
|
||||
|
||||
template <typename Type>
|
||||
Type *extend_size (Type *obj, unsigned int size)
|
||||
Type *extend_size (Type *obj, size_t size)
|
||||
{
|
||||
if (unlikely (in_error ())) return nullptr;
|
||||
|
||||
assert (this->start <= (char *) obj);
|
||||
assert ((char *) obj <= this->head);
|
||||
assert ((char *) obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
|
||||
assert ((size_t) (this->head - (char *) obj) <= size);
|
||||
if (unlikely (((char *) obj + size < (char *) obj) ||
|
||||
!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (obj);
|
||||
}
|
||||
template <typename Type>
|
||||
Type *extend_size (Type &obj, unsigned int size)
|
||||
Type *extend_size (Type &obj, size_t size)
|
||||
{ return extend_size (hb_addressof (obj), size); }
|
||||
|
||||
template <typename Type>
|
||||
@@ -497,12 +554,16 @@ struct hb_serialize_context_t
|
||||
/* Output routines. */
|
||||
hb_bytes_t copy_bytes () const
|
||||
{
|
||||
assert (this->successful);
|
||||
assert (successful ());
|
||||
/* Copy both items from head side and tail side... */
|
||||
unsigned int len = (this->head - this->start)
|
||||
+ (this->end - this->tail);
|
||||
|
||||
char *p = (char *) malloc (len);
|
||||
// If len is zero don't hb_malloc as the memory won't get properly
|
||||
// cleaned up later.
|
||||
if (!len) return hb_bytes_t ();
|
||||
|
||||
char *p = (char *) hb_malloc (len);
|
||||
if (unlikely (!p)) return hb_bytes_t ();
|
||||
|
||||
memcpy (p, this->start, this->head - this->start);
|
||||
@@ -517,23 +578,25 @@ struct hb_serialize_context_t
|
||||
hb_bytes_t b = copy_bytes ();
|
||||
return hb_blob_create (b.arrayZ, b.length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
(char *) b.arrayZ, free);
|
||||
(char *) b.arrayZ, hb_free);
|
||||
}
|
||||
|
||||
const hb_vector_t<object_t *>& object_graph() const
|
||||
{ return packed; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
template <typename T, unsigned Size = sizeof (T)>
|
||||
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
|
||||
{
|
||||
auto &off = * ((BEInt<T> *) (parent->head + link.position));
|
||||
auto &off = * ((BEInt<T, Size> *) (parent->head + link.position));
|
||||
assert (0 == off);
|
||||
check_assign (off, offset);
|
||||
check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
|
||||
}
|
||||
|
||||
public: /* TODO Make private. */
|
||||
char *start, *head, *tail, *end;
|
||||
unsigned int debug_depth;
|
||||
bool successful;
|
||||
bool ran_out_of_room;
|
||||
hb_serialize_error_t errors;
|
||||
|
||||
private:
|
||||
|
||||
@@ -550,5 +613,4 @@ struct hb_serialize_context_t
|
||||
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_SERIALIZE_HH */
|
||||
|
||||
Reference in New Issue
Block a user