[repacker] Expose on internal method in the repacker that allows the caller to pass in/out a graph.

Will be used in testing so we can compare graphs instead of packed result.
This commit is contained in:
Garret Rieger 2022-08-15 22:49:24 +00:00
parent c414ef292b
commit 5cf2a25a60
4 changed files with 53 additions and 40 deletions

View File

@ -196,7 +196,8 @@ struct graph_t
: parents_invalid (true), : parents_invalid (true),
distance_invalid (true), distance_invalid (true),
positions_invalid (true), positions_invalid (true),
successful (true) successful (true),
buffers ()
{ {
num_roots_for_space_.push (1); num_roots_for_space_.push (1);
bool removed_nil = false; bool removed_nil = false;
@ -228,6 +229,8 @@ struct graph_t
~graph_t () ~graph_t ()
{ {
vertices_.fini (); vertices_.fini ();
for (char* b : buffers)
hb_free (b);
} }
bool in_error () const bool in_error () const
@ -255,6 +258,11 @@ struct graph_t
return vertices_[i].obj; return vertices_[i].obj;
} }
void add_buffer (char* buffer)
{
buffers.push (buffer);
}
/* /*
* Adds a 16 bit link from parent_id to child_id * Adds a 16 bit link from parent_id to child_id
*/ */
@ -1127,6 +1135,7 @@ struct graph_t
bool positions_invalid; bool positions_invalid;
bool successful; bool successful;
hb_vector_t<unsigned> num_roots_for_space_; hb_vector_t<unsigned> num_roots_for_space_;
hb_vector_t<char*> buffers;
}; };
} }

View File

@ -33,8 +33,7 @@ gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
: table_tag (table_tag_), : table_tag (table_tag_),
graph (graph_), graph (graph_),
lookup_list_index (0), lookup_list_index (0),
lookups (), lookups ()
buffers ()
{ {
if (table_tag_ != HB_OT_TAG_GPOS if (table_tag_ != HB_OT_TAG_GPOS
&& table_tag_ != HB_OT_TAG_GSUB) && table_tag_ != HB_OT_TAG_GSUB)
@ -53,7 +52,7 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size)
if (!buffer) if (!buffer)
return -1; return -1;
buffers.push (buffer); add_buffer (buffer);
return graph.new_node (buffer, buffer + size); return graph.new_node (buffer, buffer + size);
} }

View File

@ -40,22 +40,16 @@ struct gsubgpos_graph_context_t
graph_t& graph; graph_t& graph;
unsigned lookup_list_index; unsigned lookup_list_index;
hb_hashmap_t<unsigned, graph::Lookup*> lookups; hb_hashmap_t<unsigned, graph::Lookup*> lookups;
hb_vector_t<char*> buffers;
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
graph_t& graph_); graph_t& graph_);
~gsubgpos_graph_context_t ()
{
for (char* b : buffers)
hb_free (b);
}
HB_INTERNAL unsigned create_node (unsigned size); HB_INTERNAL unsigned create_node (unsigned size);
void add_buffer (char* buffer) void add_buffer (char* buffer)
{ {
buffers.push (buffer); graph.add_buffer (buffer);
} }
private: private:

View File

@ -276,35 +276,20 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
return resolution_attempted; return resolution_attempted;
} }
/* inline bool
* Attempts to modify the topological sorting of the provided object graph to hb_resolve_graph_overflows (hb_tag_t table_tag,
* eliminate offset overflows in the links between objects of the graph. If a unsigned max_rounds ,
* non-overflowing ordering is found the updated graph is serialized it into the bool recalculate_extensions,
* provided serialization context. graph_t& sorted_graph /* IN/OUT */)
* {
* If necessary the structure of the graph may be modified in ways that do not
* affect the functionality of the graph. For example shared objects may be
* duplicated.
*
* For a detailed writeup describing how the algorithm operates see:
* docs/repacker.md
*/
template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
unsigned max_rounds = 20,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
sorted_graph.sort_shortest_distance (); sorted_graph.sort_shortest_distance ();
bool will_overflow = graph::will_overflow (sorted_graph); bool will_overflow = graph::will_overflow (sorted_graph);
if (!will_overflow) if (!will_overflow)
{ return true;
return graph::serialize (sorted_graph);
}
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph); // TODO attach to graph? or just move buffers to the graph?
graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph); // TODO lifetime
if ((table_tag == HB_OT_TAG_GPOS if ((table_tag == HB_OT_TAG_GPOS
|| table_tag == HB_OT_TAG_GSUB) || table_tag == HB_OT_TAG_GSUB)
&& will_overflow) && will_overflow)
@ -314,13 +299,13 @@ hb_resolve_overflows (const T& packed,
DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
if (!_presplit_subtables_if_needed (ext_context)) { if (!_presplit_subtables_if_needed (ext_context)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
return nullptr; return false;
} }
DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
if (!_promote_extensions_if_needed (ext_context)) { if (!_promote_extensions_if_needed (ext_context)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
return nullptr; return false;
} }
} }
@ -360,15 +345,41 @@ hb_resolve_overflows (const T& packed,
if (sorted_graph.in_error ()) if (sorted_graph.in_error ())
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state.");
return nullptr; return false;
} }
if (graph::will_overflow (sorted_graph)) if (graph::will_overflow (sorted_graph))
{ {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed.");
return nullptr; return false;
} }
return true;
}
/*
* Attempts to modify the topological sorting of the provided object graph to
* eliminate offset overflows in the links between objects of the graph. If a
* non-overflowing ordering is found the updated graph is serialized it into the
* provided serialization context.
*
* If necessary the structure of the graph may be modified in ways that do not
* affect the functionality of the graph. For example shared objects may be
* duplicated.
*
* For a detailed writeup describing how the algorithm operates see:
* docs/repacker.md
*/
template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
unsigned max_rounds = 20,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
if (!hb_resolve_graph_overflows (table_tag, max_rounds, recalculate_extensions, sorted_graph))
return nullptr;
return graph::serialize (sorted_graph); return graph::serialize (sorted_graph);
} }