[repacker] extract graph serialization code into a seperate file.
This commit is contained in:
parent
20b02a672d
commit
7078560e33
|
@ -129,12 +129,6 @@ struct graph_t
|
|||
}
|
||||
};
|
||||
|
||||
struct overflow_record_t
|
||||
{
|
||||
unsigned parent;
|
||||
unsigned child;
|
||||
};
|
||||
|
||||
/*
|
||||
* A topological sorting of an object graph. Ordered
|
||||
* in reverse serialization order (first object in the
|
||||
|
@ -548,36 +542,6 @@ struct graph_t
|
|||
return made_change;
|
||||
}
|
||||
|
||||
/*
|
||||
* Will any offsets overflow on graph when it's serialized?
|
||||
*/
|
||||
bool will_overflow (hb_vector_t<overflow_record_t>* overflows = nullptr)
|
||||
{
|
||||
if (overflows) overflows->resize (0);
|
||||
update_positions ();
|
||||
|
||||
for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
|
||||
{
|
||||
// Don't need to check virtual links for overflow
|
||||
for (const auto& link : vertices_[parent_idx].obj.real_links)
|
||||
{
|
||||
int64_t offset = compute_offset (parent_idx, link);
|
||||
if (is_valid_offset (offset, link))
|
||||
continue;
|
||||
|
||||
if (!overflows) return true;
|
||||
|
||||
overflow_record_t r;
|
||||
r.parent = parent_idx;
|
||||
r.child = link.objidx;
|
||||
overflows->push (r);
|
||||
}
|
||||
}
|
||||
|
||||
if (!overflows) return false;
|
||||
return overflows->length;
|
||||
}
|
||||
|
||||
void print_orphaned_nodes ()
|
||||
{
|
||||
if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
|
||||
|
@ -594,35 +558,6 @@ struct graph_t
|
|||
}
|
||||
}
|
||||
|
||||
void print_overflows (const hb_vector_t<overflow_record_t>& overflows)
|
||||
{
|
||||
if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
|
||||
|
||||
update_parents ();
|
||||
int limit = 10;
|
||||
for (const auto& o : overflows)
|
||||
{
|
||||
if (!limit--) break;
|
||||
const auto& parent = vertices_[o.parent];
|
||||
const auto& child = vertices_[o.child];
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr,
|
||||
" overflow from "
|
||||
"%4d (%4d in, %4d out, space %2d) => "
|
||||
"%4d (%4d in, %4d out, space %2d)",
|
||||
o.parent,
|
||||
parent.incoming_edges (),
|
||||
parent.obj.real_links.length + parent.obj.virtual_links.length,
|
||||
space_for (o.parent),
|
||||
o.child,
|
||||
child.incoming_edges (),
|
||||
child.obj.real_links.length + child.obj.virtual_links.length,
|
||||
space_for (o.child));
|
||||
}
|
||||
if (overflows.length > 10) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned num_roots_for_space (unsigned space) const
|
||||
{
|
||||
return num_roots_for_space_[space];
|
||||
|
@ -710,6 +645,7 @@ struct graph_t
|
|||
bool check_success (bool success)
|
||||
{ return this->successful && (success || ((void) err_other_error (), false)); }
|
||||
|
||||
public:
|
||||
/*
|
||||
* Creates a map from objid to # of incoming edges.
|
||||
*/
|
||||
|
@ -818,52 +754,7 @@ struct graph_t
|
|||
distance_invalid = false;
|
||||
}
|
||||
|
||||
int64_t compute_offset (
|
||||
unsigned parent_idx,
|
||||
const hb_serialize_context_t::object_t::link_t& link) const
|
||||
{
|
||||
const auto& parent = vertices_[parent_idx];
|
||||
const auto& child = vertices_[link.objidx];
|
||||
int64_t offset = 0;
|
||||
switch ((hb_serialize_context_t::whence_t) link.whence) {
|
||||
case hb_serialize_context_t::whence_t::Head:
|
||||
offset = child.start - parent.start; break;
|
||||
case hb_serialize_context_t::whence_t::Tail:
|
||||
offset = child.start - parent.end; break;
|
||||
case hb_serialize_context_t::whence_t::Absolute:
|
||||
offset = child.start; break;
|
||||
}
|
||||
|
||||
assert (offset >= link.bias);
|
||||
offset -= link.bias;
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool is_valid_offset (int64_t offset,
|
||||
const hb_serialize_context_t::object_t::link_t& link) const
|
||||
{
|
||||
if (unlikely (!link.width))
|
||||
// Virtual links can't overflow.
|
||||
return link.is_signed || offset >= 0;
|
||||
|
||||
if (link.is_signed)
|
||||
{
|
||||
if (link.width == 4)
|
||||
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
|
||||
else
|
||||
return offset >= -(1 << 15) && offset < (1 << 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.width == 4)
|
||||
return offset >= 0 && offset < ((int64_t) 1 << 32);
|
||||
else if (link.width == 3)
|
||||
return offset >= 0 && offset < ((int32_t) 1 << 24);
|
||||
else
|
||||
return offset >= 0 && offset < (1 << 16);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* Updates a link in the graph to point to a different object. Corrects the
|
||||
* parents vector on the previous and new child nodes.
|
||||
|
|
|
@ -29,6 +29,125 @@
|
|||
|
||||
namespace graph {
|
||||
|
||||
struct overflow_record_t
|
||||
{
|
||||
unsigned parent;
|
||||
unsigned child;
|
||||
};
|
||||
|
||||
inline
|
||||
int64_t compute_offset (
|
||||
const graph_t& graph,
|
||||
unsigned parent_idx,
|
||||
const hb_serialize_context_t::object_t::link_t& link)
|
||||
{
|
||||
const auto& parent = graph.vertices_[parent_idx];
|
||||
const auto& child = graph.vertices_[link.objidx];
|
||||
int64_t offset = 0;
|
||||
switch ((hb_serialize_context_t::whence_t) link.whence) {
|
||||
case hb_serialize_context_t::whence_t::Head:
|
||||
offset = child.start - parent.start; break;
|
||||
case hb_serialize_context_t::whence_t::Tail:
|
||||
offset = child.start - parent.end; break;
|
||||
case hb_serialize_context_t::whence_t::Absolute:
|
||||
offset = child.start; break;
|
||||
}
|
||||
|
||||
assert (offset >= link.bias);
|
||||
offset -= link.bias;
|
||||
return offset;
|
||||
}
|
||||
|
||||
inline
|
||||
bool is_valid_offset (int64_t offset,
|
||||
const hb_serialize_context_t::object_t::link_t& link)
|
||||
{
|
||||
if (unlikely (!link.width))
|
||||
// Virtual links can't overflow.
|
||||
return link.is_signed || offset >= 0;
|
||||
|
||||
if (link.is_signed)
|
||||
{
|
||||
if (link.width == 4)
|
||||
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
|
||||
else
|
||||
return offset >= -(1 << 15) && offset < (1 << 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.width == 4)
|
||||
return offset >= 0 && offset < ((int64_t) 1 << 32);
|
||||
else if (link.width == 3)
|
||||
return offset >= 0 && offset < ((int32_t) 1 << 24);
|
||||
else
|
||||
return offset >= 0 && offset < (1 << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Will any offsets overflow on graph when it's serialized?
|
||||
*/
|
||||
inline bool
|
||||
will_overflow (graph_t& graph,
|
||||
hb_vector_t<overflow_record_t>* overflows = nullptr)
|
||||
{
|
||||
if (overflows) overflows->resize (0);
|
||||
graph.update_positions ();
|
||||
|
||||
const auto& vertices = graph.vertices_;
|
||||
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
|
||||
{
|
||||
// Don't need to check virtual links for overflow
|
||||
for (const auto& link : vertices[parent_idx].obj.real_links)
|
||||
{
|
||||
int64_t offset = compute_offset (graph, parent_idx, link);
|
||||
if (is_valid_offset (offset, link))
|
||||
continue;
|
||||
|
||||
if (!overflows) return true;
|
||||
|
||||
overflow_record_t r;
|
||||
r.parent = parent_idx;
|
||||
r.child = link.objidx;
|
||||
overflows->push (r);
|
||||
}
|
||||
}
|
||||
|
||||
if (!overflows) return false;
|
||||
return overflows->length;
|
||||
}
|
||||
|
||||
inline
|
||||
void print_overflows (graph_t& graph,
|
||||
const hb_vector_t<overflow_record_t>& overflows)
|
||||
{
|
||||
if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
|
||||
|
||||
graph.update_parents ();
|
||||
int limit = 10;
|
||||
for (const auto& o : overflows)
|
||||
{
|
||||
if (!limit--) break;
|
||||
const auto& parent = graph.vertices_[o.parent];
|
||||
const auto& child = graph.vertices_[o.child];
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr,
|
||||
" overflow from "
|
||||
"%4d (%4d in, %4d out, space %2d) => "
|
||||
"%4d (%4d in, %4d out, space %2d)",
|
||||
o.parent,
|
||||
parent.incoming_edges (),
|
||||
parent.obj.real_links.length + parent.obj.virtual_links.length,
|
||||
graph.space_for (o.parent),
|
||||
o.child,
|
||||
child.incoming_edges (),
|
||||
child.obj.real_links.length + child.obj.virtual_links.length,
|
||||
graph.space_for (o.child));
|
||||
}
|
||||
if (overflows.length > 10) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename O> inline void
|
||||
serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
|
||||
char* head,
|
||||
|
|
|
@ -43,7 +43,7 @@ using graph::graph_t;
|
|||
*/
|
||||
|
||||
static inline
|
||||
bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
|
||||
bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
|
||||
graph_t& sorted_graph)
|
||||
{
|
||||
unsigned space = 0;
|
||||
|
@ -51,7 +51,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov
|
|||
|
||||
for (int i = overflows.length - 1; i >= 0; i--)
|
||||
{
|
||||
const graph_t::overflow_record_t& r = overflows[i];
|
||||
const graph::overflow_record_t& r = overflows[i];
|
||||
|
||||
unsigned root;
|
||||
unsigned overflow_space = sorted_graph.space_for (r.parent, &root);
|
||||
|
@ -93,7 +93,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov
|
|||
}
|
||||
|
||||
static inline
|
||||
bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
|
||||
bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
|
||||
hb_set_t& priority_bumped_parents,
|
||||
graph_t& sorted_graph)
|
||||
{
|
||||
|
@ -102,7 +102,7 @@ bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflow
|
|||
// Try resolving the furthest overflows first.
|
||||
for (int i = overflows.length - 1; i >= 0; i--)
|
||||
{
|
||||
const graph_t::overflow_record_t& r = overflows[i];
|
||||
const graph::overflow_record_t& r = overflows[i];
|
||||
const auto& child = sorted_graph.vertices_[r.child];
|
||||
if (child.is_shared ())
|
||||
{
|
||||
|
@ -161,14 +161,15 @@ hb_resolve_overflows (const T& packed,
|
|||
graph_t sorted_graph (packed);
|
||||
sorted_graph.sort_shortest_distance ();
|
||||
|
||||
if (!sorted_graph.will_overflow ())
|
||||
bool will_overflow = graph::will_overflow (sorted_graph);
|
||||
if (!will_overflow)
|
||||
{
|
||||
return graph::serialize (sorted_graph);
|
||||
}
|
||||
|
||||
if ((table_tag == HB_OT_TAG_GPOS
|
||||
|| table_tag == HB_OT_TAG_GSUB)
|
||||
&& sorted_graph.will_overflow ())
|
||||
&& will_overflow)
|
||||
{
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
|
||||
if (sorted_graph.assign_32bit_spaces ())
|
||||
|
@ -176,13 +177,13 @@ hb_resolve_overflows (const T& packed,
|
|||
}
|
||||
|
||||
unsigned round = 0;
|
||||
hb_vector_t<graph_t::overflow_record_t> overflows;
|
||||
hb_vector_t<graph::overflow_record_t> overflows;
|
||||
// TODO(garretrieger): select a good limit for max rounds.
|
||||
while (!sorted_graph.in_error ()
|
||||
&& sorted_graph.will_overflow (&overflows)
|
||||
&& graph::will_overflow (sorted_graph, &overflows)
|
||||
&& round++ < max_rounds) {
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round);
|
||||
sorted_graph.print_overflows (overflows);
|
||||
print_overflows (sorted_graph, overflows);
|
||||
|
||||
hb_set_t priority_bumped_parents;
|
||||
|
||||
|
@ -204,7 +205,7 @@ hb_resolve_overflows (const T& packed,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (sorted_graph.will_overflow ())
|
||||
if (graph::will_overflow (sorted_graph))
|
||||
{
|
||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
|
||||
return nullptr;
|
||||
|
|
|
@ -949,7 +949,7 @@ static void test_will_overflow_1 ()
|
|||
populate_serializer_complex_2 (&c);
|
||||
graph_t graph (c.object_graph ());
|
||||
|
||||
assert (!graph.will_overflow (nullptr));
|
||||
assert (!graph::will_overflow (graph, nullptr));
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
@ -962,7 +962,7 @@ static void test_will_overflow_2 ()
|
|||
populate_serializer_with_overflow (&c);
|
||||
graph_t graph (c.object_graph ());
|
||||
|
||||
assert (graph.will_overflow (nullptr));
|
||||
assert (graph::will_overflow (graph, nullptr));
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
@ -975,7 +975,7 @@ static void test_will_overflow_3 ()
|
|||
populate_serializer_with_dedup_overflow (&c);
|
||||
graph_t graph (c.object_graph ());
|
||||
|
||||
assert (graph.will_overflow (nullptr));
|
||||
assert (graph::will_overflow (graph, nullptr));
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue