summaryrefslogtreecommitdiff
path: root/thirdparty/harfbuzz/src/graph/graph.hh
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/harfbuzz/src/graph/graph.hh')
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh201
1 files changed, 197 insertions, 4 deletions
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index b3aef558a2..64878a84a4 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -49,6 +49,51 @@ struct graph_t
unsigned end = 0;
unsigned priority = 0;
+ void normalize ()
+ {
+ obj.real_links.qsort ();
+ for (auto& l : obj.real_links)
+ {
+ for (unsigned i = 0; i < l.width; i++)
+ {
+ obj.head[l.position + i] = 0;
+ }
+ }
+ }
+
+ bool equals (const vertex_t& other,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ if (!(as_bytes () == other.as_bytes ()))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "vertex [%lu] bytes != [%lu] bytes, depth = %u",
+ table_size (),
+ other.table_size (),
+ depth);
+
+ auto a = as_bytes ();
+ auto b = other.as_bytes ();
+ while (a || b)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b);
+ a++;
+ b++;
+ }
+ return false;
+ }
+
+ return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth);
+ }
+
+ hb_bytes_t as_bytes () const
+ {
+ return hb_bytes_t (obj.head, table_size ());
+ }
+
friend void swap (vertex_t& a, vertex_t& b)
{
hb_swap (a.obj, b.obj);
@@ -60,6 +105,18 @@ struct graph_t
hb_swap (a.priority, b.priority);
}
+ hb_hashmap_t<unsigned, unsigned>
+ position_to_index_map () const
+ {
+ hb_hashmap_t<unsigned, unsigned> result;
+
+ for (const auto& l : obj.real_links) {
+ result.set (l.position, l.objidx);
+ }
+
+ return result;
+ }
+
bool is_shared () const
{
return parents.length > 1;
@@ -84,7 +141,7 @@ struct graph_t
{
for (unsigned i = 0; i < obj.real_links.length; i++)
{
- auto& link = obj.real_links[i];
+ auto& link = obj.real_links.arrayZ[i];
if (link.objidx != child_index)
continue;
@@ -155,6 +212,57 @@ struct graph_t
return -table_size;
}
+
+ private:
+ bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links,
+ const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links,
+ const graph_t& graph,
+ const graph_t& other_graph,
+ unsigned depth) const
+ {
+ auto a = this_links.iter ();
+ auto b = other_links.iter ();
+
+ while (a && b)
+ {
+ const auto& link_a = *a;
+ const auto& link_b = *b;
+
+ if (link_a.width != link_b.width ||
+ link_a.is_signed != link_b.is_signed ||
+ link_a.whence != link_b.whence ||
+ link_a.position != link_b.position ||
+ link_a.bias != link_b.bias)
+ return false;
+
+ if (!graph.vertices_[link_a.objidx].equals (
+ other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
+ return false;
+
+ a++;
+ b++;
+ }
+
+ if (bool (a) != bool (b))
+ return false;
+
+ return true;
+ }
+ };
+
+ template <typename T>
+ struct vertex_and_table_t
+ {
+ vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr)
+ {}
+
+ unsigned index;
+ vertex_t* vertex;
+ T* table;
+
+ operator bool () {
+ return table && vertex;
+ }
};
/*
@@ -169,7 +277,8 @@ struct graph_t
: parents_invalid (true),
distance_invalid (true),
positions_invalid (true),
- successful (true)
+ successful (true),
+ buffers ()
{
num_roots_for_space_.push (1);
bool removed_nil = false;
@@ -201,6 +310,20 @@ struct graph_t
~graph_t ()
{
vertices_.fini ();
+ for (char* b : buffers)
+ hb_free (b);
+ }
+
+ bool operator== (const graph_t& other) const
+ {
+ return root ().equals (other.root (), *this, other, 0);
+ }
+
+ // Sorts links of all objects in a consistent manner and zeroes all offsets.
+ void normalize ()
+ {
+ for (auto& v : vertices_.writer ())
+ v.normalize ();
}
bool in_error () const
@@ -228,6 +351,27 @@ struct graph_t
return vertices_[i].obj;
}
+ void add_buffer (char* buffer)
+ {
+ buffers.push (buffer);
+ }
+
+ /*
+ * Adds a 16 bit link from parent_id to child_id
+ */
+ template<typename T>
+ void add_link (T* offset,
+ unsigned parent_id,
+ unsigned child_id)
+ {
+ auto& v = vertices_[parent_id];
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = child_id;
+ link->position = (char*) offset - (char*) v.obj.head;
+ vertices_[child_id].parents.push (parent_id);
+ }
+
/*
* Generates a new topological sorting of graph ordered by the shortest
* distance to each node if positions are marked as invalid.
@@ -345,13 +489,43 @@ struct graph_t
}
}
- unsigned index_for_offset(unsigned node_idx, const void* offset) const
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds)
+ {
+ return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
+ }
+
+ template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
+ {
+ if (index >= vertices_.length)
+ return vertex_and_table_t<T> ();
+
+ vertex_and_table_t<T> r;
+ r.vertex = &vertices_[index];
+ r.table = (T*) r.vertex->obj.head;
+ r.index = index;
+ if (!r.table)
+ return vertex_and_table_t<T> ();
+
+ if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...))
+ return vertex_and_table_t<T> ();
+
+ return r;
+ }
+
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx].
+ unsigned index_for_offset (unsigned node_idx, const void* offset) const
{
const auto& node = object (node_idx);
if (offset < node.head || offset >= node.tail) return -1;
- for (const auto& link : node.real_links)
+ unsigned length = node.real_links.length;
+ for (unsigned i = 0; i < length; i++)
{
+ // Use direct access for increased performance, this is a hot method.
+ const auto& link = node.real_links.arrayZ[i];
if (offset != node.head + link.position)
continue;
return link.objidx;
@@ -360,6 +534,24 @@ struct graph_t
return -1;
}
+ // Finds the object id of the object pointed to by the offset at 'offset'
+ // within object[node_idx]. Ensures that the returned object is safe to mutate.
+ // That is, if the original child object is shared by parents other than node_idx
+ // it will be duplicated and the duplicate will be returned instead.
+ unsigned mutable_index_for_offset (unsigned node_idx, const void* offset)
+ {
+ unsigned child_idx = index_for_offset (node_idx, offset);
+ auto& child = vertices_[child_idx];
+ for (unsigned p : child.parents)
+ {
+ if (p != node_idx) {
+ return duplicate (node_idx, child_idx);
+ }
+ }
+
+ return child_idx;
+ }
+
/*
* Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
@@ -1039,6 +1231,7 @@ struct graph_t
bool positions_invalid;
bool successful;
hb_vector_t<unsigned> num_roots_for_space_;
+ hb_vector_t<char*> buffers;
};
}