|
|
|
@ -758,43 +758,12 @@ struct graph_t |
|
|
|
|
bool successful; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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. |
|
|
|
|
*/ |
|
|
|
|
inline void |
|
|
|
|
hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed, |
|
|
|
|
hb_serialize_context_t* c) { |
|
|
|
|
// Kahn sort is ~twice as fast as shortest distance sort and works for many fonts
|
|
|
|
|
// so try it first to save time.
|
|
|
|
|
graph_t sorted_graph (packed); |
|
|
|
|
sorted_graph.sort_kahn (); |
|
|
|
|
if (!sorted_graph.will_overflow ()) |
|
|
|
|
{ |
|
|
|
|
sorted_graph.serialize (c); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sorted_graph.sort_shortest_distance (); |
|
|
|
|
|
|
|
|
|
unsigned round = 0; |
|
|
|
|
hb_vector_t<graph_t::overflow_record_t> overflows; |
|
|
|
|
// TODO(garretrieger): select a good limit for max rounds.
|
|
|
|
|
while (!sorted_graph.in_error () |
|
|
|
|
&& sorted_graph.will_overflow (&overflows) |
|
|
|
|
&& round++ < 10) { |
|
|
|
|
DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Over flow resolution round %d ===", round); |
|
|
|
|
sorted_graph.print_overflows (overflows); |
|
|
|
|
|
|
|
|
|
static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows, |
|
|
|
|
hb_set_t& priority_bumped_parents, |
|
|
|
|
graph_t& sorted_graph) |
|
|
|
|
{ |
|
|
|
|
bool resolution_attempted = false; |
|
|
|
|
hb_set_t priority_bumped_parents; |
|
|
|
|
|
|
|
|
|
// Try resolving the furthest overflows first.
|
|
|
|
|
for (int i = overflows.length - 1; i >= 0; i--) |
|
|
|
|
{ |
|
|
|
@ -805,11 +774,7 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac |
|
|
|
|
// The child object is shared, we may be able to eliminate the overflow
|
|
|
|
|
// by duplicating it.
|
|
|
|
|
sorted_graph.duplicate (r.parent, r.child); |
|
|
|
|
resolution_attempted = true; |
|
|
|
|
|
|
|
|
|
// Stop processing overflows for this round so that object order can be
|
|
|
|
|
// updated to account for the newly added object.
|
|
|
|
|
break; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (child.is_leaf () && !priority_bumped_parents.has (r.parent)) |
|
|
|
@ -838,15 +803,51 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac |
|
|
|
|
// - Table splitting.
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (resolution_attempted) |
|
|
|
|
return resolution_attempted; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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. |
|
|
|
|
*/ |
|
|
|
|
inline void |
|
|
|
|
hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed, |
|
|
|
|
hb_serialize_context_t* c) { |
|
|
|
|
// Kahn sort is ~twice as fast as shortest distance sort and works for many fonts
|
|
|
|
|
// so try it first to save time.
|
|
|
|
|
graph_t sorted_graph (packed); |
|
|
|
|
sorted_graph.sort_kahn (); |
|
|
|
|
if (!sorted_graph.will_overflow ()) |
|
|
|
|
{ |
|
|
|
|
sorted_graph.sort_shortest_distance (); |
|
|
|
|
continue; |
|
|
|
|
sorted_graph.serialize (c); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sorted_graph.sort_shortest_distance (); |
|
|
|
|
|
|
|
|
|
unsigned round = 0; |
|
|
|
|
hb_vector_t<graph_t::overflow_record_t> overflows; |
|
|
|
|
// TODO(garretrieger): select a good limit for max rounds.
|
|
|
|
|
while (!sorted_graph.in_error () |
|
|
|
|
&& sorted_graph.will_overflow (&overflows) |
|
|
|
|
&& round++ < 10) { |
|
|
|
|
DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Over flow resolution round %d ===", round); |
|
|
|
|
sorted_graph.print_overflows (overflows); |
|
|
|
|
|
|
|
|
|
hb_set_t priority_bumped_parents; |
|
|
|
|
if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph)) |
|
|
|
|
{ |
|
|
|
|
DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :("); |
|
|
|
|
c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); |
|
|
|
|
return; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sorted_graph.sort_shortest_distance (); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (sorted_graph.in_error ()) |
|
|
|
@ -864,5 +865,4 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac |
|
|
|
|
sorted_graph.serialize (c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* HB_REPACKER_HH */ |
|
|
|
|