xref: /aosp_15_r20/external/harfbuzz_ng/src/graph/graph.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2022  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Garret Rieger
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #include "../hb-set.hh"
28*2d1272b8SAndroid Build Coastguard Worker #include "../hb-priority-queue.hh"
29*2d1272b8SAndroid Build Coastguard Worker #include "../hb-serialize.hh"
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #ifndef GRAPH_GRAPH_HH
32*2d1272b8SAndroid Build Coastguard Worker #define GRAPH_GRAPH_HH
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker namespace graph {
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker /**
37*2d1272b8SAndroid Build Coastguard Worker  * Represents a serialized table in the form of a graph.
38*2d1272b8SAndroid Build Coastguard Worker  * Provides methods for modifying and reordering the graph.
39*2d1272b8SAndroid Build Coastguard Worker  */
40*2d1272b8SAndroid Build Coastguard Worker struct graph_t
41*2d1272b8SAndroid Build Coastguard Worker {
42*2d1272b8SAndroid Build Coastguard Worker   struct vertex_t
43*2d1272b8SAndroid Build Coastguard Worker   {
44*2d1272b8SAndroid Build Coastguard Worker     hb_serialize_context_t::object_t obj;
45*2d1272b8SAndroid Build Coastguard Worker     int64_t distance = 0 ;
46*2d1272b8SAndroid Build Coastguard Worker     unsigned space = 0 ;
47*2d1272b8SAndroid Build Coastguard Worker     unsigned start = 0;
48*2d1272b8SAndroid Build Coastguard Worker     unsigned end = 0;
49*2d1272b8SAndroid Build Coastguard Worker     unsigned priority = 0;
50*2d1272b8SAndroid Build Coastguard Worker     private:
51*2d1272b8SAndroid Build Coastguard Worker     unsigned incoming_edges_ = 0;
52*2d1272b8SAndroid Build Coastguard Worker     unsigned single_parent = (unsigned) -1;
53*2d1272b8SAndroid Build Coastguard Worker     hb_hashmap_t<unsigned, unsigned> parents;
54*2d1272b8SAndroid Build Coastguard Worker     public:
55*2d1272b8SAndroid Build Coastguard Worker 
parents_itergraph::graph_t::vertex_t56*2d1272b8SAndroid Build Coastguard Worker     auto parents_iter () const HB_AUTO_RETURN
57*2d1272b8SAndroid Build Coastguard Worker     (
58*2d1272b8SAndroid Build Coastguard Worker       hb_concat (
59*2d1272b8SAndroid Build Coastguard Worker 	hb_iter (&single_parent, single_parent != (unsigned) -1),
60*2d1272b8SAndroid Build Coastguard Worker 	parents.keys_ref ()
61*2d1272b8SAndroid Build Coastguard Worker       )
62*2d1272b8SAndroid Build Coastguard Worker     )
63*2d1272b8SAndroid Build Coastguard Worker 
64*2d1272b8SAndroid Build Coastguard Worker     bool in_error () const
65*2d1272b8SAndroid Build Coastguard Worker     {
66*2d1272b8SAndroid Build Coastguard Worker       return parents.in_error ();
67*2d1272b8SAndroid Build Coastguard Worker     }
68*2d1272b8SAndroid Build Coastguard Worker 
link_positions_validgraph::graph_t::vertex_t69*2d1272b8SAndroid Build Coastguard Worker     bool link_positions_valid (unsigned num_objects, bool removed_nil)
70*2d1272b8SAndroid Build Coastguard Worker     {
71*2d1272b8SAndroid Build Coastguard Worker       hb_set_t assigned_bytes;
72*2d1272b8SAndroid Build Coastguard Worker       for (const auto& l : obj.real_links)
73*2d1272b8SAndroid Build Coastguard Worker       {
74*2d1272b8SAndroid Build Coastguard Worker         if (l.objidx >= num_objects
75*2d1272b8SAndroid Build Coastguard Worker             || (removed_nil && !l.objidx))
76*2d1272b8SAndroid Build Coastguard Worker         {
77*2d1272b8SAndroid Build Coastguard Worker           DEBUG_MSG (SUBSET_REPACK, nullptr,
78*2d1272b8SAndroid Build Coastguard Worker                      "Invalid graph. Invalid object index.");
79*2d1272b8SAndroid Build Coastguard Worker           return false;
80*2d1272b8SAndroid Build Coastguard Worker         }
81*2d1272b8SAndroid Build Coastguard Worker 
82*2d1272b8SAndroid Build Coastguard Worker         unsigned start = l.position;
83*2d1272b8SAndroid Build Coastguard Worker         unsigned end = start + l.width - 1;
84*2d1272b8SAndroid Build Coastguard Worker 
85*2d1272b8SAndroid Build Coastguard Worker         if (unlikely (l.width < 2 || l.width > 4))
86*2d1272b8SAndroid Build Coastguard Worker         {
87*2d1272b8SAndroid Build Coastguard Worker           DEBUG_MSG (SUBSET_REPACK, nullptr,
88*2d1272b8SAndroid Build Coastguard Worker                      "Invalid graph. Invalid link width.");
89*2d1272b8SAndroid Build Coastguard Worker           return false;
90*2d1272b8SAndroid Build Coastguard Worker         }
91*2d1272b8SAndroid Build Coastguard Worker 
92*2d1272b8SAndroid Build Coastguard Worker         if (unlikely (end >= table_size ()))
93*2d1272b8SAndroid Build Coastguard Worker         {
94*2d1272b8SAndroid Build Coastguard Worker           DEBUG_MSG (SUBSET_REPACK, nullptr,
95*2d1272b8SAndroid Build Coastguard Worker                      "Invalid graph. Link position is out of bounds.");
96*2d1272b8SAndroid Build Coastguard Worker           return false;
97*2d1272b8SAndroid Build Coastguard Worker         }
98*2d1272b8SAndroid Build Coastguard Worker 
99*2d1272b8SAndroid Build Coastguard Worker         if (unlikely (assigned_bytes.intersects (start, end)))
100*2d1272b8SAndroid Build Coastguard Worker         {
101*2d1272b8SAndroid Build Coastguard Worker           DEBUG_MSG (SUBSET_REPACK, nullptr,
102*2d1272b8SAndroid Build Coastguard Worker                      "Invalid graph. Found offsets whose positions overlap.");
103*2d1272b8SAndroid Build Coastguard Worker           return false;
104*2d1272b8SAndroid Build Coastguard Worker         }
105*2d1272b8SAndroid Build Coastguard Worker 
106*2d1272b8SAndroid Build Coastguard Worker         assigned_bytes.add_range (start, end);
107*2d1272b8SAndroid Build Coastguard Worker       }
108*2d1272b8SAndroid Build Coastguard Worker 
109*2d1272b8SAndroid Build Coastguard Worker       return !assigned_bytes.in_error ();
110*2d1272b8SAndroid Build Coastguard Worker     }
111*2d1272b8SAndroid Build Coastguard Worker 
normalizegraph::graph_t::vertex_t112*2d1272b8SAndroid Build Coastguard Worker     void normalize ()
113*2d1272b8SAndroid Build Coastguard Worker     {
114*2d1272b8SAndroid Build Coastguard Worker       obj.real_links.qsort ();
115*2d1272b8SAndroid Build Coastguard Worker       for (auto& l : obj.real_links)
116*2d1272b8SAndroid Build Coastguard Worker       {
117*2d1272b8SAndroid Build Coastguard Worker         for (unsigned i = 0; i < l.width; i++)
118*2d1272b8SAndroid Build Coastguard Worker         {
119*2d1272b8SAndroid Build Coastguard Worker           obj.head[l.position + i] = 0;
120*2d1272b8SAndroid Build Coastguard Worker         }
121*2d1272b8SAndroid Build Coastguard Worker       }
122*2d1272b8SAndroid Build Coastguard Worker     }
123*2d1272b8SAndroid Build Coastguard Worker 
equalsgraph::graph_t::vertex_t124*2d1272b8SAndroid Build Coastguard Worker     bool equals (const vertex_t& other,
125*2d1272b8SAndroid Build Coastguard Worker                  const graph_t& graph,
126*2d1272b8SAndroid Build Coastguard Worker                  const graph_t& other_graph,
127*2d1272b8SAndroid Build Coastguard Worker                  unsigned depth) const
128*2d1272b8SAndroid Build Coastguard Worker     {
129*2d1272b8SAndroid Build Coastguard Worker       if (!(as_bytes () == other.as_bytes ()))
130*2d1272b8SAndroid Build Coastguard Worker       {
131*2d1272b8SAndroid Build Coastguard Worker         DEBUG_MSG (SUBSET_REPACK, nullptr,
132*2d1272b8SAndroid Build Coastguard Worker                    "vertex [%lu] bytes != [%lu] bytes, depth = %u",
133*2d1272b8SAndroid Build Coastguard Worker                    (unsigned long) table_size (),
134*2d1272b8SAndroid Build Coastguard Worker                    (unsigned long) other.table_size (),
135*2d1272b8SAndroid Build Coastguard Worker                    depth);
136*2d1272b8SAndroid Build Coastguard Worker 
137*2d1272b8SAndroid Build Coastguard Worker         auto a = as_bytes ();
138*2d1272b8SAndroid Build Coastguard Worker         auto b = other.as_bytes ();
139*2d1272b8SAndroid Build Coastguard Worker         while (a || b)
140*2d1272b8SAndroid Build Coastguard Worker         {
141*2d1272b8SAndroid Build Coastguard Worker           DEBUG_MSG (SUBSET_REPACK, nullptr,
142*2d1272b8SAndroid Build Coastguard Worker                      "  0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b);
143*2d1272b8SAndroid Build Coastguard Worker           a++;
144*2d1272b8SAndroid Build Coastguard Worker           b++;
145*2d1272b8SAndroid Build Coastguard Worker         }
146*2d1272b8SAndroid Build Coastguard Worker         return false;
147*2d1272b8SAndroid Build Coastguard Worker       }
148*2d1272b8SAndroid Build Coastguard Worker 
149*2d1272b8SAndroid Build Coastguard Worker       return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth);
150*2d1272b8SAndroid Build Coastguard Worker     }
151*2d1272b8SAndroid Build Coastguard Worker 
as_bytesgraph::graph_t::vertex_t152*2d1272b8SAndroid Build Coastguard Worker     hb_bytes_t as_bytes () const
153*2d1272b8SAndroid Build Coastguard Worker     {
154*2d1272b8SAndroid Build Coastguard Worker       return hb_bytes_t (obj.head, table_size ());
155*2d1272b8SAndroid Build Coastguard Worker     }
156*2d1272b8SAndroid Build Coastguard Worker 
swapgraph::graph_t157*2d1272b8SAndroid Build Coastguard Worker     friend void swap (vertex_t& a, vertex_t& b)
158*2d1272b8SAndroid Build Coastguard Worker     {
159*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.obj, b.obj);
160*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.distance, b.distance);
161*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.space, b.space);
162*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.single_parent, b.single_parent);
163*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.parents, b.parents);
164*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.incoming_edges_, b.incoming_edges_);
165*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.start, b.start);
166*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.end, b.end);
167*2d1272b8SAndroid Build Coastguard Worker       hb_swap (a.priority, b.priority);
168*2d1272b8SAndroid Build Coastguard Worker     }
169*2d1272b8SAndroid Build Coastguard Worker 
170*2d1272b8SAndroid Build Coastguard Worker     hb_hashmap_t<unsigned, unsigned>
position_to_index_mapgraph::graph_t::vertex_t171*2d1272b8SAndroid Build Coastguard Worker     position_to_index_map () const
172*2d1272b8SAndroid Build Coastguard Worker     {
173*2d1272b8SAndroid Build Coastguard Worker       hb_hashmap_t<unsigned, unsigned> result;
174*2d1272b8SAndroid Build Coastguard Worker 
175*2d1272b8SAndroid Build Coastguard Worker       result.alloc (obj.real_links.length);
176*2d1272b8SAndroid Build Coastguard Worker       for (const auto& l : obj.real_links) {
177*2d1272b8SAndroid Build Coastguard Worker         result.set (l.position, l.objidx);
178*2d1272b8SAndroid Build Coastguard Worker       }
179*2d1272b8SAndroid Build Coastguard Worker 
180*2d1272b8SAndroid Build Coastguard Worker       return result;
181*2d1272b8SAndroid Build Coastguard Worker     }
182*2d1272b8SAndroid Build Coastguard Worker 
is_sharedgraph::graph_t::vertex_t183*2d1272b8SAndroid Build Coastguard Worker     bool is_shared () const
184*2d1272b8SAndroid Build Coastguard Worker     {
185*2d1272b8SAndroid Build Coastguard Worker       return parents.get_population () > 1;
186*2d1272b8SAndroid Build Coastguard Worker     }
187*2d1272b8SAndroid Build Coastguard Worker 
incoming_edgesgraph::graph_t::vertex_t188*2d1272b8SAndroid Build Coastguard Worker     unsigned incoming_edges () const
189*2d1272b8SAndroid Build Coastguard Worker     {
190*2d1272b8SAndroid Build Coastguard Worker       if (HB_DEBUG_SUBSET_REPACK)
191*2d1272b8SAndroid Build Coastguard Worker        {
192*2d1272b8SAndroid Build Coastguard Worker 	assert (incoming_edges_ == (single_parent != (unsigned) -1) +
193*2d1272b8SAndroid Build Coastguard Worker 		(parents.values_ref () | hb_reduce (hb_add, 0)));
194*2d1272b8SAndroid Build Coastguard Worker        }
195*2d1272b8SAndroid Build Coastguard Worker       return incoming_edges_;
196*2d1272b8SAndroid Build Coastguard Worker     }
197*2d1272b8SAndroid Build Coastguard Worker 
incoming_edges_from_parentgraph::graph_t::vertex_t198*2d1272b8SAndroid Build Coastguard Worker     unsigned incoming_edges_from_parent (unsigned parent_index) const {
199*2d1272b8SAndroid Build Coastguard Worker       if (single_parent != (unsigned) -1) {
200*2d1272b8SAndroid Build Coastguard Worker         return single_parent == parent_index ? 1 : 0;
201*2d1272b8SAndroid Build Coastguard Worker       }
202*2d1272b8SAndroid Build Coastguard Worker 
203*2d1272b8SAndroid Build Coastguard Worker       unsigned* count;
204*2d1272b8SAndroid Build Coastguard Worker       return  parents.has(parent_index, &count) ? *count : 0;
205*2d1272b8SAndroid Build Coastguard Worker     }
206*2d1272b8SAndroid Build Coastguard Worker 
reset_parentsgraph::graph_t::vertex_t207*2d1272b8SAndroid Build Coastguard Worker     void reset_parents ()
208*2d1272b8SAndroid Build Coastguard Worker     {
209*2d1272b8SAndroid Build Coastguard Worker       incoming_edges_ = 0;
210*2d1272b8SAndroid Build Coastguard Worker       single_parent = (unsigned) -1;
211*2d1272b8SAndroid Build Coastguard Worker       parents.reset ();
212*2d1272b8SAndroid Build Coastguard Worker     }
213*2d1272b8SAndroid Build Coastguard Worker 
add_parentgraph::graph_t::vertex_t214*2d1272b8SAndroid Build Coastguard Worker     void add_parent (unsigned parent_index)
215*2d1272b8SAndroid Build Coastguard Worker     {
216*2d1272b8SAndroid Build Coastguard Worker       assert (parent_index != (unsigned) -1);
217*2d1272b8SAndroid Build Coastguard Worker       if (incoming_edges_ == 0)
218*2d1272b8SAndroid Build Coastguard Worker       {
219*2d1272b8SAndroid Build Coastguard Worker 	single_parent = parent_index;
220*2d1272b8SAndroid Build Coastguard Worker 	incoming_edges_ = 1;
221*2d1272b8SAndroid Build Coastguard Worker 	return;
222*2d1272b8SAndroid Build Coastguard Worker       }
223*2d1272b8SAndroid Build Coastguard Worker       else if (single_parent != (unsigned) -1)
224*2d1272b8SAndroid Build Coastguard Worker       {
225*2d1272b8SAndroid Build Coastguard Worker         assert (incoming_edges_ == 1);
226*2d1272b8SAndroid Build Coastguard Worker 	if (!parents.set (single_parent, 1))
227*2d1272b8SAndroid Build Coastguard Worker 	  return;
228*2d1272b8SAndroid Build Coastguard Worker 	single_parent = (unsigned) -1;
229*2d1272b8SAndroid Build Coastguard Worker       }
230*2d1272b8SAndroid Build Coastguard Worker 
231*2d1272b8SAndroid Build Coastguard Worker       unsigned *v;
232*2d1272b8SAndroid Build Coastguard Worker       if (parents.has (parent_index, &v))
233*2d1272b8SAndroid Build Coastguard Worker       {
234*2d1272b8SAndroid Build Coastguard Worker         (*v)++;
235*2d1272b8SAndroid Build Coastguard Worker 	incoming_edges_++;
236*2d1272b8SAndroid Build Coastguard Worker       }
237*2d1272b8SAndroid Build Coastguard Worker       else if (parents.set (parent_index, 1))
238*2d1272b8SAndroid Build Coastguard Worker 	incoming_edges_++;
239*2d1272b8SAndroid Build Coastguard Worker     }
240*2d1272b8SAndroid Build Coastguard Worker 
remove_parentgraph::graph_t::vertex_t241*2d1272b8SAndroid Build Coastguard Worker     void remove_parent (unsigned parent_index)
242*2d1272b8SAndroid Build Coastguard Worker     {
243*2d1272b8SAndroid Build Coastguard Worker       if (parent_index == single_parent)
244*2d1272b8SAndroid Build Coastguard Worker       {
245*2d1272b8SAndroid Build Coastguard Worker 	single_parent = (unsigned) -1;
246*2d1272b8SAndroid Build Coastguard Worker 	incoming_edges_--;
247*2d1272b8SAndroid Build Coastguard Worker 	return;
248*2d1272b8SAndroid Build Coastguard Worker       }
249*2d1272b8SAndroid Build Coastguard Worker 
250*2d1272b8SAndroid Build Coastguard Worker       unsigned *v;
251*2d1272b8SAndroid Build Coastguard Worker       if (parents.has (parent_index, &v))
252*2d1272b8SAndroid Build Coastguard Worker       {
253*2d1272b8SAndroid Build Coastguard Worker 	incoming_edges_--;
254*2d1272b8SAndroid Build Coastguard Worker 	if (*v > 1)
255*2d1272b8SAndroid Build Coastguard Worker 	  (*v)--;
256*2d1272b8SAndroid Build Coastguard Worker 	else
257*2d1272b8SAndroid Build Coastguard Worker 	  parents.del (parent_index);
258*2d1272b8SAndroid Build Coastguard Worker 
259*2d1272b8SAndroid Build Coastguard Worker 	if (incoming_edges_ == 1)
260*2d1272b8SAndroid Build Coastguard Worker 	{
261*2d1272b8SAndroid Build Coastguard Worker 	  single_parent = *parents.keys ();
262*2d1272b8SAndroid Build Coastguard Worker 	  parents.reset ();
263*2d1272b8SAndroid Build Coastguard Worker 	}
264*2d1272b8SAndroid Build Coastguard Worker       }
265*2d1272b8SAndroid Build Coastguard Worker     }
266*2d1272b8SAndroid Build Coastguard Worker 
remove_real_linkgraph::graph_t::vertex_t267*2d1272b8SAndroid Build Coastguard Worker     void remove_real_link (unsigned child_index, const void* offset)
268*2d1272b8SAndroid Build Coastguard Worker     {
269*2d1272b8SAndroid Build Coastguard Worker       unsigned count = obj.real_links.length;
270*2d1272b8SAndroid Build Coastguard Worker       for (unsigned i = 0; i < count; i++)
271*2d1272b8SAndroid Build Coastguard Worker       {
272*2d1272b8SAndroid Build Coastguard Worker         auto& link = obj.real_links.arrayZ[i];
273*2d1272b8SAndroid Build Coastguard Worker         if (link.objidx != child_index)
274*2d1272b8SAndroid Build Coastguard Worker           continue;
275*2d1272b8SAndroid Build Coastguard Worker 
276*2d1272b8SAndroid Build Coastguard Worker         if ((obj.head + link.position) != offset)
277*2d1272b8SAndroid Build Coastguard Worker           continue;
278*2d1272b8SAndroid Build Coastguard Worker 
279*2d1272b8SAndroid Build Coastguard Worker         obj.real_links.remove_unordered (i);
280*2d1272b8SAndroid Build Coastguard Worker         return;
281*2d1272b8SAndroid Build Coastguard Worker       }
282*2d1272b8SAndroid Build Coastguard Worker     }
283*2d1272b8SAndroid Build Coastguard Worker 
remap_parentsgraph::graph_t::vertex_t284*2d1272b8SAndroid Build Coastguard Worker     bool remap_parents (const hb_vector_t<unsigned>& id_map)
285*2d1272b8SAndroid Build Coastguard Worker     {
286*2d1272b8SAndroid Build Coastguard Worker       if (single_parent != (unsigned) -1)
287*2d1272b8SAndroid Build Coastguard Worker       {
288*2d1272b8SAndroid Build Coastguard Worker         assert (single_parent < id_map.length);
289*2d1272b8SAndroid Build Coastguard Worker 	single_parent = id_map[single_parent];
290*2d1272b8SAndroid Build Coastguard Worker 	return true;
291*2d1272b8SAndroid Build Coastguard Worker       }
292*2d1272b8SAndroid Build Coastguard Worker 
293*2d1272b8SAndroid Build Coastguard Worker       hb_hashmap_t<unsigned, unsigned> new_parents;
294*2d1272b8SAndroid Build Coastguard Worker       new_parents.alloc (parents.get_population ());
295*2d1272b8SAndroid Build Coastguard Worker       for (auto _ : parents)
296*2d1272b8SAndroid Build Coastguard Worker       {
297*2d1272b8SAndroid Build Coastguard Worker 	assert (_.first < id_map.length);
298*2d1272b8SAndroid Build Coastguard Worker 	assert (!new_parents.has (id_map[_.first]));
299*2d1272b8SAndroid Build Coastguard Worker 	new_parents.set (id_map[_.first], _.second);
300*2d1272b8SAndroid Build Coastguard Worker       }
301*2d1272b8SAndroid Build Coastguard Worker 
302*2d1272b8SAndroid Build Coastguard Worker       if (parents.in_error() || new_parents.in_error ())
303*2d1272b8SAndroid Build Coastguard Worker         return false;
304*2d1272b8SAndroid Build Coastguard Worker 
305*2d1272b8SAndroid Build Coastguard Worker       parents = std::move (new_parents);
306*2d1272b8SAndroid Build Coastguard Worker       return true;
307*2d1272b8SAndroid Build Coastguard Worker     }
308*2d1272b8SAndroid Build Coastguard Worker 
remap_parentgraph::graph_t::vertex_t309*2d1272b8SAndroid Build Coastguard Worker     void remap_parent (unsigned old_index, unsigned new_index)
310*2d1272b8SAndroid Build Coastguard Worker     {
311*2d1272b8SAndroid Build Coastguard Worker       if (single_parent != (unsigned) -1)
312*2d1272b8SAndroid Build Coastguard Worker       {
313*2d1272b8SAndroid Build Coastguard Worker         if (single_parent == old_index)
314*2d1272b8SAndroid Build Coastguard Worker 	  single_parent = new_index;
315*2d1272b8SAndroid Build Coastguard Worker         return;
316*2d1272b8SAndroid Build Coastguard Worker       }
317*2d1272b8SAndroid Build Coastguard Worker 
318*2d1272b8SAndroid Build Coastguard Worker       const unsigned *pv;
319*2d1272b8SAndroid Build Coastguard Worker       if (parents.has (old_index, &pv))
320*2d1272b8SAndroid Build Coastguard Worker       {
321*2d1272b8SAndroid Build Coastguard Worker         unsigned v = *pv;
322*2d1272b8SAndroid Build Coastguard Worker 	if (!parents.set (new_index, v))
323*2d1272b8SAndroid Build Coastguard Worker           incoming_edges_ -= v;
324*2d1272b8SAndroid Build Coastguard Worker 	parents.del (old_index);
325*2d1272b8SAndroid Build Coastguard Worker 
326*2d1272b8SAndroid Build Coastguard Worker         if (incoming_edges_ == 1)
327*2d1272b8SAndroid Build Coastguard Worker 	{
328*2d1272b8SAndroid Build Coastguard Worker 	  single_parent = *parents.keys ();
329*2d1272b8SAndroid Build Coastguard Worker 	  parents.reset ();
330*2d1272b8SAndroid Build Coastguard Worker 	}
331*2d1272b8SAndroid Build Coastguard Worker       }
332*2d1272b8SAndroid Build Coastguard Worker     }
333*2d1272b8SAndroid Build Coastguard Worker 
is_leafgraph::graph_t::vertex_t334*2d1272b8SAndroid Build Coastguard Worker     bool is_leaf () const
335*2d1272b8SAndroid Build Coastguard Worker     {
336*2d1272b8SAndroid Build Coastguard Worker       return !obj.real_links.length && !obj.virtual_links.length;
337*2d1272b8SAndroid Build Coastguard Worker     }
338*2d1272b8SAndroid Build Coastguard Worker 
raise_prioritygraph::graph_t::vertex_t339*2d1272b8SAndroid Build Coastguard Worker     bool raise_priority ()
340*2d1272b8SAndroid Build Coastguard Worker     {
341*2d1272b8SAndroid Build Coastguard Worker       if (has_max_priority ()) return false;
342*2d1272b8SAndroid Build Coastguard Worker       priority++;
343*2d1272b8SAndroid Build Coastguard Worker       return true;
344*2d1272b8SAndroid Build Coastguard Worker     }
345*2d1272b8SAndroid Build Coastguard Worker 
give_max_prioritygraph::graph_t::vertex_t346*2d1272b8SAndroid Build Coastguard Worker     bool give_max_priority ()
347*2d1272b8SAndroid Build Coastguard Worker     {
348*2d1272b8SAndroid Build Coastguard Worker       bool result = false;
349*2d1272b8SAndroid Build Coastguard Worker       while (!has_max_priority()) {
350*2d1272b8SAndroid Build Coastguard Worker         result = true;
351*2d1272b8SAndroid Build Coastguard Worker         priority++;
352*2d1272b8SAndroid Build Coastguard Worker       }
353*2d1272b8SAndroid Build Coastguard Worker       return result;
354*2d1272b8SAndroid Build Coastguard Worker     }
355*2d1272b8SAndroid Build Coastguard Worker 
has_max_prioritygraph::graph_t::vertex_t356*2d1272b8SAndroid Build Coastguard Worker     bool has_max_priority () const {
357*2d1272b8SAndroid Build Coastguard Worker       return priority >= 3;
358*2d1272b8SAndroid Build Coastguard Worker     }
359*2d1272b8SAndroid Build Coastguard Worker 
table_sizegraph::graph_t::vertex_t360*2d1272b8SAndroid Build Coastguard Worker     size_t table_size () const {
361*2d1272b8SAndroid Build Coastguard Worker       return obj.tail - obj.head;
362*2d1272b8SAndroid Build Coastguard Worker     }
363*2d1272b8SAndroid Build Coastguard Worker 
modified_distancegraph::graph_t::vertex_t364*2d1272b8SAndroid Build Coastguard Worker     int64_t modified_distance (unsigned order) const
365*2d1272b8SAndroid Build Coastguard Worker     {
366*2d1272b8SAndroid Build Coastguard Worker       // TODO(garretrieger): once priority is high enough, should try
367*2d1272b8SAndroid Build Coastguard Worker       // setting distance = 0 which will force to sort immediately after
368*2d1272b8SAndroid Build Coastguard Worker       // it's parent where possible.
369*2d1272b8SAndroid Build Coastguard Worker 
370*2d1272b8SAndroid Build Coastguard Worker       int64_t modified_distance =
371*2d1272b8SAndroid Build Coastguard Worker           hb_clamp (distance + distance_modifier (), (int64_t) 0, 0x7FFFFFFFFFF);
372*2d1272b8SAndroid Build Coastguard Worker       if (has_max_priority ()) {
373*2d1272b8SAndroid Build Coastguard Worker         modified_distance = 0;
374*2d1272b8SAndroid Build Coastguard Worker       }
375*2d1272b8SAndroid Build Coastguard Worker       return (modified_distance << 18) | (0x003FFFF & order);
376*2d1272b8SAndroid Build Coastguard Worker     }
377*2d1272b8SAndroid Build Coastguard Worker 
distance_modifiergraph::graph_t::vertex_t378*2d1272b8SAndroid Build Coastguard Worker     int64_t distance_modifier () const
379*2d1272b8SAndroid Build Coastguard Worker     {
380*2d1272b8SAndroid Build Coastguard Worker       if (!priority) return 0;
381*2d1272b8SAndroid Build Coastguard Worker       int64_t table_size = obj.tail - obj.head;
382*2d1272b8SAndroid Build Coastguard Worker 
383*2d1272b8SAndroid Build Coastguard Worker       if (priority == 1)
384*2d1272b8SAndroid Build Coastguard Worker         return -table_size / 2;
385*2d1272b8SAndroid Build Coastguard Worker 
386*2d1272b8SAndroid Build Coastguard Worker       return -table_size;
387*2d1272b8SAndroid Build Coastguard Worker     }
388*2d1272b8SAndroid Build Coastguard Worker 
389*2d1272b8SAndroid Build Coastguard Worker    private:
links_equalgraph::graph_t::vertex_t390*2d1272b8SAndroid Build Coastguard Worker     bool links_equal (const hb_vector_t<hb_serialize_context_t::object_t::link_t>& this_links,
391*2d1272b8SAndroid Build Coastguard Worker                       const hb_vector_t<hb_serialize_context_t::object_t::link_t>& other_links,
392*2d1272b8SAndroid Build Coastguard Worker                       const graph_t& graph,
393*2d1272b8SAndroid Build Coastguard Worker                       const graph_t& other_graph,
394*2d1272b8SAndroid Build Coastguard Worker                       unsigned depth) const
395*2d1272b8SAndroid Build Coastguard Worker     {
396*2d1272b8SAndroid Build Coastguard Worker       auto a = this_links.iter ();
397*2d1272b8SAndroid Build Coastguard Worker       auto b = other_links.iter ();
398*2d1272b8SAndroid Build Coastguard Worker 
399*2d1272b8SAndroid Build Coastguard Worker       while (a && b)
400*2d1272b8SAndroid Build Coastguard Worker       {
401*2d1272b8SAndroid Build Coastguard Worker         const auto& link_a = *a;
402*2d1272b8SAndroid Build Coastguard Worker         const auto& link_b = *b;
403*2d1272b8SAndroid Build Coastguard Worker 
404*2d1272b8SAndroid Build Coastguard Worker         if (link_a.width != link_b.width ||
405*2d1272b8SAndroid Build Coastguard Worker             link_a.is_signed != link_b.is_signed ||
406*2d1272b8SAndroid Build Coastguard Worker             link_a.whence != link_b.whence ||
407*2d1272b8SAndroid Build Coastguard Worker             link_a.position != link_b.position ||
408*2d1272b8SAndroid Build Coastguard Worker             link_a.bias != link_b.bias)
409*2d1272b8SAndroid Build Coastguard Worker           return false;
410*2d1272b8SAndroid Build Coastguard Worker 
411*2d1272b8SAndroid Build Coastguard Worker         if (!graph.vertices_[link_a.objidx].equals (
412*2d1272b8SAndroid Build Coastguard Worker                 other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1))
413*2d1272b8SAndroid Build Coastguard Worker           return false;
414*2d1272b8SAndroid Build Coastguard Worker 
415*2d1272b8SAndroid Build Coastguard Worker         a++;
416*2d1272b8SAndroid Build Coastguard Worker         b++;
417*2d1272b8SAndroid Build Coastguard Worker       }
418*2d1272b8SAndroid Build Coastguard Worker 
419*2d1272b8SAndroid Build Coastguard Worker       if (bool (a) != bool (b))
420*2d1272b8SAndroid Build Coastguard Worker         return false;
421*2d1272b8SAndroid Build Coastguard Worker 
422*2d1272b8SAndroid Build Coastguard Worker       return true;
423*2d1272b8SAndroid Build Coastguard Worker     }
424*2d1272b8SAndroid Build Coastguard Worker   };
425*2d1272b8SAndroid Build Coastguard Worker 
426*2d1272b8SAndroid Build Coastguard Worker   template <typename T>
427*2d1272b8SAndroid Build Coastguard Worker   struct vertex_and_table_t
428*2d1272b8SAndroid Build Coastguard Worker   {
vertex_and_table_tgraph::graph_t::vertex_and_table_t429*2d1272b8SAndroid Build Coastguard Worker     vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr)
430*2d1272b8SAndroid Build Coastguard Worker     {}
431*2d1272b8SAndroid Build Coastguard Worker 
432*2d1272b8SAndroid Build Coastguard Worker     unsigned index;
433*2d1272b8SAndroid Build Coastguard Worker     vertex_t* vertex;
434*2d1272b8SAndroid Build Coastguard Worker     T* table;
435*2d1272b8SAndroid Build Coastguard Worker 
operator boolgraph::graph_t::vertex_and_table_t436*2d1272b8SAndroid Build Coastguard Worker     operator bool () {
437*2d1272b8SAndroid Build Coastguard Worker        return table && vertex;
438*2d1272b8SAndroid Build Coastguard Worker     }
439*2d1272b8SAndroid Build Coastguard Worker   };
440*2d1272b8SAndroid Build Coastguard Worker 
441*2d1272b8SAndroid Build Coastguard Worker   /*
442*2d1272b8SAndroid Build Coastguard Worker    * A topological sorting of an object graph. Ordered
443*2d1272b8SAndroid Build Coastguard Worker    * in reverse serialization order (first object in the
444*2d1272b8SAndroid Build Coastguard Worker    * serialization is at the end of the list). This matches
445*2d1272b8SAndroid Build Coastguard Worker    * the 'packed' object stack used internally in the
446*2d1272b8SAndroid Build Coastguard Worker    * serializer
447*2d1272b8SAndroid Build Coastguard Worker    */
448*2d1272b8SAndroid Build Coastguard Worker   template<typename T>
graph_tgraph::graph_t449*2d1272b8SAndroid Build Coastguard Worker   graph_t (const T& objects)
450*2d1272b8SAndroid Build Coastguard Worker       : parents_invalid (true),
451*2d1272b8SAndroid Build Coastguard Worker         distance_invalid (true),
452*2d1272b8SAndroid Build Coastguard Worker         positions_invalid (true),
453*2d1272b8SAndroid Build Coastguard Worker         successful (true),
454*2d1272b8SAndroid Build Coastguard Worker         buffers ()
455*2d1272b8SAndroid Build Coastguard Worker   {
456*2d1272b8SAndroid Build Coastguard Worker     num_roots_for_space_.push (1);
457*2d1272b8SAndroid Build Coastguard Worker     bool removed_nil = false;
458*2d1272b8SAndroid Build Coastguard Worker     vertices_.alloc (objects.length);
459*2d1272b8SAndroid Build Coastguard Worker     vertices_scratch_.alloc (objects.length);
460*2d1272b8SAndroid Build Coastguard Worker     unsigned count = objects.length;
461*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
462*2d1272b8SAndroid Build Coastguard Worker     {
463*2d1272b8SAndroid Build Coastguard Worker       // If this graph came from a serialization buffer object 0 is the
464*2d1272b8SAndroid Build Coastguard Worker       // nil object. We don't need it for our purposes here so drop it.
465*2d1272b8SAndroid Build Coastguard Worker       if (i == 0 && !objects.arrayZ[i])
466*2d1272b8SAndroid Build Coastguard Worker       {
467*2d1272b8SAndroid Build Coastguard Worker         removed_nil = true;
468*2d1272b8SAndroid Build Coastguard Worker         continue;
469*2d1272b8SAndroid Build Coastguard Worker       }
470*2d1272b8SAndroid Build Coastguard Worker 
471*2d1272b8SAndroid Build Coastguard Worker       vertex_t* v = vertices_.push ();
472*2d1272b8SAndroid Build Coastguard Worker       if (check_success (!vertices_.in_error ()))
473*2d1272b8SAndroid Build Coastguard Worker         v->obj = *objects.arrayZ[i];
474*2d1272b8SAndroid Build Coastguard Worker 
475*2d1272b8SAndroid Build Coastguard Worker       check_success (v->link_positions_valid (count, removed_nil));
476*2d1272b8SAndroid Build Coastguard Worker 
477*2d1272b8SAndroid Build Coastguard Worker       if (!removed_nil) continue;
478*2d1272b8SAndroid Build Coastguard Worker       // Fix indices to account for removed nil object.
479*2d1272b8SAndroid Build Coastguard Worker       for (auto& l : v->obj.all_links_writer ()) {
480*2d1272b8SAndroid Build Coastguard Worker         l.objidx--;
481*2d1272b8SAndroid Build Coastguard Worker       }
482*2d1272b8SAndroid Build Coastguard Worker     }
483*2d1272b8SAndroid Build Coastguard Worker   }
484*2d1272b8SAndroid Build Coastguard Worker 
~graph_tgraph::graph_t485*2d1272b8SAndroid Build Coastguard Worker   ~graph_t ()
486*2d1272b8SAndroid Build Coastguard Worker   {
487*2d1272b8SAndroid Build Coastguard Worker     for (char* b : buffers)
488*2d1272b8SAndroid Build Coastguard Worker       hb_free (b);
489*2d1272b8SAndroid Build Coastguard Worker   }
490*2d1272b8SAndroid Build Coastguard Worker 
operator ==graph::graph_t491*2d1272b8SAndroid Build Coastguard Worker   bool operator== (const graph_t& other) const
492*2d1272b8SAndroid Build Coastguard Worker   {
493*2d1272b8SAndroid Build Coastguard Worker     return root ().equals (other.root (), *this, other, 0);
494*2d1272b8SAndroid Build Coastguard Worker   }
495*2d1272b8SAndroid Build Coastguard Worker 
printgraph::graph_t496*2d1272b8SAndroid Build Coastguard Worker   void print () const {
497*2d1272b8SAndroid Build Coastguard Worker     for (int i = vertices_.length - 1; i >= 0; i--)
498*2d1272b8SAndroid Build Coastguard Worker     {
499*2d1272b8SAndroid Build Coastguard Worker       const auto& v = vertices_[i];
500*2d1272b8SAndroid Build Coastguard Worker       printf("%d: %u [", i, (unsigned int)v.table_size());
501*2d1272b8SAndroid Build Coastguard Worker       for (const auto &l : v.obj.real_links) {
502*2d1272b8SAndroid Build Coastguard Worker         printf("%u, ", l.objidx);
503*2d1272b8SAndroid Build Coastguard Worker       }
504*2d1272b8SAndroid Build Coastguard Worker       printf("]\n");
505*2d1272b8SAndroid Build Coastguard Worker     }
506*2d1272b8SAndroid Build Coastguard Worker   }
507*2d1272b8SAndroid Build Coastguard Worker 
508*2d1272b8SAndroid Build Coastguard Worker   // Sorts links of all objects in a consistent manner and zeroes all offsets.
normalizegraph::graph_t509*2d1272b8SAndroid Build Coastguard Worker   void normalize ()
510*2d1272b8SAndroid Build Coastguard Worker   {
511*2d1272b8SAndroid Build Coastguard Worker     for (auto& v : vertices_.writer ())
512*2d1272b8SAndroid Build Coastguard Worker       v.normalize ();
513*2d1272b8SAndroid Build Coastguard Worker   }
514*2d1272b8SAndroid Build Coastguard Worker 
in_errorgraph::graph_t515*2d1272b8SAndroid Build Coastguard Worker   bool in_error () const
516*2d1272b8SAndroid Build Coastguard Worker   {
517*2d1272b8SAndroid Build Coastguard Worker     return !successful ||
518*2d1272b8SAndroid Build Coastguard Worker         vertices_.in_error () ||
519*2d1272b8SAndroid Build Coastguard Worker         num_roots_for_space_.in_error ();
520*2d1272b8SAndroid Build Coastguard Worker   }
521*2d1272b8SAndroid Build Coastguard Worker 
rootgraph::graph_t522*2d1272b8SAndroid Build Coastguard Worker   const vertex_t& root () const
523*2d1272b8SAndroid Build Coastguard Worker   {
524*2d1272b8SAndroid Build Coastguard Worker     return vertices_[root_idx ()];
525*2d1272b8SAndroid Build Coastguard Worker   }
526*2d1272b8SAndroid Build Coastguard Worker 
root_idxgraph::graph_t527*2d1272b8SAndroid Build Coastguard Worker   unsigned root_idx () const
528*2d1272b8SAndroid Build Coastguard Worker   {
529*2d1272b8SAndroid Build Coastguard Worker     // Object graphs are in reverse order, the first object is at the end
530*2d1272b8SAndroid Build Coastguard Worker     // of the vector. Since the graph is topologically sorted it's safe to
531*2d1272b8SAndroid Build Coastguard Worker     // assume the first object has no incoming edges.
532*2d1272b8SAndroid Build Coastguard Worker     return vertices_.length - 1;
533*2d1272b8SAndroid Build Coastguard Worker   }
534*2d1272b8SAndroid Build Coastguard Worker 
objectgraph::graph_t535*2d1272b8SAndroid Build Coastguard Worker   const hb_serialize_context_t::object_t& object (unsigned i) const
536*2d1272b8SAndroid Build Coastguard Worker   {
537*2d1272b8SAndroid Build Coastguard Worker     return vertices_[i].obj;
538*2d1272b8SAndroid Build Coastguard Worker   }
539*2d1272b8SAndroid Build Coastguard Worker 
add_buffergraph::graph_t540*2d1272b8SAndroid Build Coastguard Worker   bool add_buffer (char* buffer)
541*2d1272b8SAndroid Build Coastguard Worker   {
542*2d1272b8SAndroid Build Coastguard Worker     buffers.push (buffer);
543*2d1272b8SAndroid Build Coastguard Worker     return !buffers.in_error ();
544*2d1272b8SAndroid Build Coastguard Worker   }
545*2d1272b8SAndroid Build Coastguard Worker 
546*2d1272b8SAndroid Build Coastguard Worker   /*
547*2d1272b8SAndroid Build Coastguard Worker    * Adds a 16 bit link from parent_id to child_id
548*2d1272b8SAndroid Build Coastguard Worker    */
549*2d1272b8SAndroid Build Coastguard Worker   template<typename T>
add_linkgraph::graph_t550*2d1272b8SAndroid Build Coastguard Worker   void add_link (T* offset,
551*2d1272b8SAndroid Build Coastguard Worker                  unsigned parent_id,
552*2d1272b8SAndroid Build Coastguard Worker                  unsigned child_id)
553*2d1272b8SAndroid Build Coastguard Worker   {
554*2d1272b8SAndroid Build Coastguard Worker     auto& v = vertices_[parent_id];
555*2d1272b8SAndroid Build Coastguard Worker     auto* link = v.obj.real_links.push ();
556*2d1272b8SAndroid Build Coastguard Worker     link->width = 2;
557*2d1272b8SAndroid Build Coastguard Worker     link->objidx = child_id;
558*2d1272b8SAndroid Build Coastguard Worker     link->position = (char*) offset - (char*) v.obj.head;
559*2d1272b8SAndroid Build Coastguard Worker     vertices_[child_id].add_parent (parent_id);
560*2d1272b8SAndroid Build Coastguard Worker   }
561*2d1272b8SAndroid Build Coastguard Worker 
562*2d1272b8SAndroid Build Coastguard Worker   /*
563*2d1272b8SAndroid Build Coastguard Worker    * Generates a new topological sorting of graph ordered by the shortest
564*2d1272b8SAndroid Build Coastguard Worker    * distance to each node if positions are marked as invalid.
565*2d1272b8SAndroid Build Coastguard Worker    */
sort_shortest_distance_if_neededgraph::graph_t566*2d1272b8SAndroid Build Coastguard Worker   void sort_shortest_distance_if_needed ()
567*2d1272b8SAndroid Build Coastguard Worker   {
568*2d1272b8SAndroid Build Coastguard Worker     if (!positions_invalid) return;
569*2d1272b8SAndroid Build Coastguard Worker     sort_shortest_distance ();
570*2d1272b8SAndroid Build Coastguard Worker   }
571*2d1272b8SAndroid Build Coastguard Worker 
572*2d1272b8SAndroid Build Coastguard Worker 
573*2d1272b8SAndroid Build Coastguard Worker   /*
574*2d1272b8SAndroid Build Coastguard Worker    * Generates a new topological sorting of graph ordered by the shortest
575*2d1272b8SAndroid Build Coastguard Worker    * distance to each node.
576*2d1272b8SAndroid Build Coastguard Worker    */
sort_shortest_distancegraph::graph_t577*2d1272b8SAndroid Build Coastguard Worker   void sort_shortest_distance ()
578*2d1272b8SAndroid Build Coastguard Worker   {
579*2d1272b8SAndroid Build Coastguard Worker     positions_invalid = true;
580*2d1272b8SAndroid Build Coastguard Worker 
581*2d1272b8SAndroid Build Coastguard Worker     if (vertices_.length <= 1) {
582*2d1272b8SAndroid Build Coastguard Worker       // Graph of 1 or less doesn't need sorting.
583*2d1272b8SAndroid Build Coastguard Worker       return;
584*2d1272b8SAndroid Build Coastguard Worker     }
585*2d1272b8SAndroid Build Coastguard Worker 
586*2d1272b8SAndroid Build Coastguard Worker     update_distances ();
587*2d1272b8SAndroid Build Coastguard Worker 
588*2d1272b8SAndroid Build Coastguard Worker     hb_priority_queue_t<int64_t> queue;
589*2d1272b8SAndroid Build Coastguard Worker     queue.alloc (vertices_.length);
590*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
591*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
592*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<unsigned> id_map;
593*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
594*2d1272b8SAndroid Build Coastguard Worker 
595*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<unsigned> removed_edges;
596*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
597*2d1272b8SAndroid Build Coastguard Worker     update_parents ();
598*2d1272b8SAndroid Build Coastguard Worker 
599*2d1272b8SAndroid Build Coastguard Worker     queue.insert (root ().modified_distance (0), root_idx ());
600*2d1272b8SAndroid Build Coastguard Worker     int new_id = root_idx ();
601*2d1272b8SAndroid Build Coastguard Worker     unsigned order = 1;
602*2d1272b8SAndroid Build Coastguard Worker     while (!queue.in_error () && !queue.is_empty ())
603*2d1272b8SAndroid Build Coastguard Worker     {
604*2d1272b8SAndroid Build Coastguard Worker       unsigned next_id = queue.pop_minimum().second;
605*2d1272b8SAndroid Build Coastguard Worker 
606*2d1272b8SAndroid Build Coastguard Worker       sorted_graph[new_id] = std::move (vertices_[next_id]);
607*2d1272b8SAndroid Build Coastguard Worker       const vertex_t& next = sorted_graph[new_id];
608*2d1272b8SAndroid Build Coastguard Worker 
609*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!check_success(new_id >= 0))) {
610*2d1272b8SAndroid Build Coastguard Worker         // We are out of ids. Which means we've visited a node more than once.
611*2d1272b8SAndroid Build Coastguard Worker         // This graph contains a cycle which is not allowed.
612*2d1272b8SAndroid Build Coastguard Worker         DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
613*2d1272b8SAndroid Build Coastguard Worker         return;
614*2d1272b8SAndroid Build Coastguard Worker       }
615*2d1272b8SAndroid Build Coastguard Worker 
616*2d1272b8SAndroid Build Coastguard Worker       id_map[next_id] = new_id--;
617*2d1272b8SAndroid Build Coastguard Worker 
618*2d1272b8SAndroid Build Coastguard Worker       for (const auto& link : next.obj.all_links ()) {
619*2d1272b8SAndroid Build Coastguard Worker         removed_edges[link.objidx]++;
620*2d1272b8SAndroid Build Coastguard Worker         if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
621*2d1272b8SAndroid Build Coastguard Worker           // Add the order that the links were encountered to the priority.
622*2d1272b8SAndroid Build Coastguard Worker           // This ensures that ties between priorities objects are broken in a consistent
623*2d1272b8SAndroid Build Coastguard Worker           // way. More specifically this is set up so that if a set of objects have the same
624*2d1272b8SAndroid Build Coastguard Worker           // distance they'll be added to the topological order in the order that they are
625*2d1272b8SAndroid Build Coastguard Worker           // referenced from the parent object.
626*2d1272b8SAndroid Build Coastguard Worker           queue.insert (vertices_[link.objidx].modified_distance (order++),
627*2d1272b8SAndroid Build Coastguard Worker                         link.objidx);
628*2d1272b8SAndroid Build Coastguard Worker       }
629*2d1272b8SAndroid Build Coastguard Worker     }
630*2d1272b8SAndroid Build Coastguard Worker 
631*2d1272b8SAndroid Build Coastguard Worker     check_success (!queue.in_error ());
632*2d1272b8SAndroid Build Coastguard Worker     check_success (!sorted_graph.in_error ());
633*2d1272b8SAndroid Build Coastguard Worker 
634*2d1272b8SAndroid Build Coastguard Worker     check_success (remap_all_obj_indices (id_map, &sorted_graph));
635*2d1272b8SAndroid Build Coastguard Worker     vertices_ = std::move (sorted_graph);
636*2d1272b8SAndroid Build Coastguard Worker 
637*2d1272b8SAndroid Build Coastguard Worker     if (!check_success (new_id == -1))
638*2d1272b8SAndroid Build Coastguard Worker       print_orphaned_nodes ();
639*2d1272b8SAndroid Build Coastguard Worker   }
640*2d1272b8SAndroid Build Coastguard Worker 
641*2d1272b8SAndroid Build Coastguard Worker   /*
642*2d1272b8SAndroid Build Coastguard Worker    * Finds the set of nodes (placed into roots) that should be assigned unique spaces.
643*2d1272b8SAndroid Build Coastguard Worker    * More specifically this looks for the top most 24 bit or 32 bit links in the graph.
644*2d1272b8SAndroid Build Coastguard Worker    * Some special casing is done that is specific to the layout of GSUB/GPOS tables.
645*2d1272b8SAndroid Build Coastguard Worker    */
find_space_rootsgraph::graph_t646*2d1272b8SAndroid Build Coastguard Worker   void find_space_roots (hb_set_t& visited, hb_set_t& roots)
647*2d1272b8SAndroid Build Coastguard Worker   {
648*2d1272b8SAndroid Build Coastguard Worker     int root_index = (int) root_idx ();
649*2d1272b8SAndroid Build Coastguard Worker     for (int i = root_index; i >= 0; i--)
650*2d1272b8SAndroid Build Coastguard Worker     {
651*2d1272b8SAndroid Build Coastguard Worker       if (visited.has (i)) continue;
652*2d1272b8SAndroid Build Coastguard Worker 
653*2d1272b8SAndroid Build Coastguard Worker       // Only real links can form 32 bit spaces
654*2d1272b8SAndroid Build Coastguard Worker       for (auto& l : vertices_[i].obj.real_links)
655*2d1272b8SAndroid Build Coastguard Worker       {
656*2d1272b8SAndroid Build Coastguard Worker         if (l.is_signed || l.width < 3)
657*2d1272b8SAndroid Build Coastguard Worker           continue;
658*2d1272b8SAndroid Build Coastguard Worker 
659*2d1272b8SAndroid Build Coastguard Worker         if (i == root_index && l.width == 3)
660*2d1272b8SAndroid Build Coastguard Worker           // Ignore 24bit links from the root node, this skips past the single 24bit
661*2d1272b8SAndroid Build Coastguard Worker           // pointer to the lookup list.
662*2d1272b8SAndroid Build Coastguard Worker           continue;
663*2d1272b8SAndroid Build Coastguard Worker 
664*2d1272b8SAndroid Build Coastguard Worker         if (l.width == 3)
665*2d1272b8SAndroid Build Coastguard Worker         {
666*2d1272b8SAndroid Build Coastguard Worker           // A 24bit offset forms a root, unless there is 32bit offsets somewhere
667*2d1272b8SAndroid Build Coastguard Worker           // in it's subgraph, then those become the roots instead. This is to make sure
668*2d1272b8SAndroid Build Coastguard Worker           // that extension subtables beneath a 24bit lookup become the spaces instead
669*2d1272b8SAndroid Build Coastguard Worker           // of the offset to the lookup.
670*2d1272b8SAndroid Build Coastguard Worker           hb_set_t sub_roots;
671*2d1272b8SAndroid Build Coastguard Worker           find_32bit_roots (l.objidx, sub_roots);
672*2d1272b8SAndroid Build Coastguard Worker           if (sub_roots) {
673*2d1272b8SAndroid Build Coastguard Worker             for (unsigned sub_root_idx : sub_roots) {
674*2d1272b8SAndroid Build Coastguard Worker               roots.add (sub_root_idx);
675*2d1272b8SAndroid Build Coastguard Worker               find_subgraph (sub_root_idx, visited);
676*2d1272b8SAndroid Build Coastguard Worker             }
677*2d1272b8SAndroid Build Coastguard Worker             continue;
678*2d1272b8SAndroid Build Coastguard Worker           }
679*2d1272b8SAndroid Build Coastguard Worker         }
680*2d1272b8SAndroid Build Coastguard Worker 
681*2d1272b8SAndroid Build Coastguard Worker         roots.add (l.objidx);
682*2d1272b8SAndroid Build Coastguard Worker         find_subgraph (l.objidx, visited);
683*2d1272b8SAndroid Build Coastguard Worker       }
684*2d1272b8SAndroid Build Coastguard Worker     }
685*2d1272b8SAndroid Build Coastguard Worker   }
686*2d1272b8SAndroid Build Coastguard Worker 
687*2d1272b8SAndroid Build Coastguard Worker   template <typename T, typename ...Ts>
as_tablegraph::graph_t688*2d1272b8SAndroid Build Coastguard Worker   vertex_and_table_t<T> as_table (unsigned parent, const void* offset, Ts... ds)
689*2d1272b8SAndroid Build Coastguard Worker   {
690*2d1272b8SAndroid Build Coastguard Worker     return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
691*2d1272b8SAndroid Build Coastguard Worker   }
692*2d1272b8SAndroid Build Coastguard Worker 
693*2d1272b8SAndroid Build Coastguard Worker   template <typename T, typename ...Ts>
as_mutable_tablegraph::graph_t694*2d1272b8SAndroid Build Coastguard Worker   vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
695*2d1272b8SAndroid Build Coastguard Worker   {
696*2d1272b8SAndroid Build Coastguard Worker     return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
697*2d1272b8SAndroid Build Coastguard Worker   }
698*2d1272b8SAndroid Build Coastguard Worker 
699*2d1272b8SAndroid Build Coastguard Worker   template <typename T, typename ...Ts>
as_table_from_indexgraph::graph_t700*2d1272b8SAndroid Build Coastguard Worker   vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
701*2d1272b8SAndroid Build Coastguard Worker   {
702*2d1272b8SAndroid Build Coastguard Worker     if (index >= vertices_.length)
703*2d1272b8SAndroid Build Coastguard Worker       return vertex_and_table_t<T> ();
704*2d1272b8SAndroid Build Coastguard Worker 
705*2d1272b8SAndroid Build Coastguard Worker     vertex_and_table_t<T> r;
706*2d1272b8SAndroid Build Coastguard Worker     r.vertex = &vertices_[index];
707*2d1272b8SAndroid Build Coastguard Worker     r.table = (T*) r.vertex->obj.head;
708*2d1272b8SAndroid Build Coastguard Worker     r.index = index;
709*2d1272b8SAndroid Build Coastguard Worker     if (!r.table)
710*2d1272b8SAndroid Build Coastguard Worker       return vertex_and_table_t<T> ();
711*2d1272b8SAndroid Build Coastguard Worker 
712*2d1272b8SAndroid Build Coastguard Worker     if (!r.table->sanitize (*(r.vertex), std::forward<Ts>(ds)...))
713*2d1272b8SAndroid Build Coastguard Worker       return vertex_and_table_t<T> ();
714*2d1272b8SAndroid Build Coastguard Worker 
715*2d1272b8SAndroid Build Coastguard Worker     return r;
716*2d1272b8SAndroid Build Coastguard Worker   }
717*2d1272b8SAndroid Build Coastguard Worker 
718*2d1272b8SAndroid Build Coastguard Worker   // Finds the object id of the object pointed to by the offset at 'offset'
719*2d1272b8SAndroid Build Coastguard Worker   // within object[node_idx].
index_for_offsetgraph::graph_t720*2d1272b8SAndroid Build Coastguard Worker   unsigned index_for_offset (unsigned node_idx, const void* offset) const
721*2d1272b8SAndroid Build Coastguard Worker   {
722*2d1272b8SAndroid Build Coastguard Worker     const auto& node = object (node_idx);
723*2d1272b8SAndroid Build Coastguard Worker     if (offset < node.head || offset >= node.tail) return -1;
724*2d1272b8SAndroid Build Coastguard Worker 
725*2d1272b8SAndroid Build Coastguard Worker     unsigned count = node.real_links.length;
726*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
727*2d1272b8SAndroid Build Coastguard Worker     {
728*2d1272b8SAndroid Build Coastguard Worker       // Use direct access for increased performance, this is a hot method.
729*2d1272b8SAndroid Build Coastguard Worker       const auto& link = node.real_links.arrayZ[i];
730*2d1272b8SAndroid Build Coastguard Worker       if (offset != node.head + link.position)
731*2d1272b8SAndroid Build Coastguard Worker         continue;
732*2d1272b8SAndroid Build Coastguard Worker       return link.objidx;
733*2d1272b8SAndroid Build Coastguard Worker     }
734*2d1272b8SAndroid Build Coastguard Worker 
735*2d1272b8SAndroid Build Coastguard Worker     return -1;
736*2d1272b8SAndroid Build Coastguard Worker   }
737*2d1272b8SAndroid Build Coastguard Worker 
738*2d1272b8SAndroid Build Coastguard Worker   // Finds the object id of the object pointed to by the offset at 'offset'
739*2d1272b8SAndroid Build Coastguard Worker   // within object[node_idx]. Ensures that the returned object is safe to mutate.
740*2d1272b8SAndroid Build Coastguard Worker   // That is, if the original child object is shared by parents other than node_idx
741*2d1272b8SAndroid Build Coastguard Worker   // it will be duplicated and the duplicate will be returned instead.
mutable_index_for_offsetgraph::graph_t742*2d1272b8SAndroid Build Coastguard Worker   unsigned mutable_index_for_offset (unsigned node_idx, const void* offset)
743*2d1272b8SAndroid Build Coastguard Worker   {
744*2d1272b8SAndroid Build Coastguard Worker     unsigned child_idx = index_for_offset (node_idx, offset);
745*2d1272b8SAndroid Build Coastguard Worker     auto& child = vertices_[child_idx];
746*2d1272b8SAndroid Build Coastguard Worker     for (unsigned p : child.parents_iter ())
747*2d1272b8SAndroid Build Coastguard Worker     {
748*2d1272b8SAndroid Build Coastguard Worker       if (p != node_idx) {
749*2d1272b8SAndroid Build Coastguard Worker         return duplicate (node_idx, child_idx);
750*2d1272b8SAndroid Build Coastguard Worker       }
751*2d1272b8SAndroid Build Coastguard Worker     }
752*2d1272b8SAndroid Build Coastguard Worker 
753*2d1272b8SAndroid Build Coastguard Worker     return child_idx;
754*2d1272b8SAndroid Build Coastguard Worker   }
755*2d1272b8SAndroid Build Coastguard Worker 
756*2d1272b8SAndroid Build Coastguard Worker 
757*2d1272b8SAndroid Build Coastguard Worker   /*
758*2d1272b8SAndroid Build Coastguard Worker    * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
759*2d1272b8SAndroid Build Coastguard Worker    * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
760*2d1272b8SAndroid Build Coastguard Worker    * (including with 24bit offsets) table.
761*2d1272b8SAndroid Build Coastguard Worker    */
assign_spacesgraph::graph_t762*2d1272b8SAndroid Build Coastguard Worker   bool assign_spaces ()
763*2d1272b8SAndroid Build Coastguard Worker   {
764*2d1272b8SAndroid Build Coastguard Worker     update_parents ();
765*2d1272b8SAndroid Build Coastguard Worker 
766*2d1272b8SAndroid Build Coastguard Worker     hb_set_t visited;
767*2d1272b8SAndroid Build Coastguard Worker     hb_set_t roots;
768*2d1272b8SAndroid Build Coastguard Worker     find_space_roots (visited, roots);
769*2d1272b8SAndroid Build Coastguard Worker 
770*2d1272b8SAndroid Build Coastguard Worker     // Mark everything not in the subgraphs of the roots as visited. This prevents
771*2d1272b8SAndroid Build Coastguard Worker     // subgraphs from being connected via nodes not in those subgraphs.
772*2d1272b8SAndroid Build Coastguard Worker     visited.invert ();
773*2d1272b8SAndroid Build Coastguard Worker 
774*2d1272b8SAndroid Build Coastguard Worker     if (!roots) return false;
775*2d1272b8SAndroid Build Coastguard Worker 
776*2d1272b8SAndroid Build Coastguard Worker     while (roots)
777*2d1272b8SAndroid Build Coastguard Worker     {
778*2d1272b8SAndroid Build Coastguard Worker       uint32_t next = HB_SET_VALUE_INVALID;
779*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!check_success (!roots.in_error ()))) break;
780*2d1272b8SAndroid Build Coastguard Worker       if (!roots.next (&next)) break;
781*2d1272b8SAndroid Build Coastguard Worker 
782*2d1272b8SAndroid Build Coastguard Worker       hb_set_t connected_roots;
783*2d1272b8SAndroid Build Coastguard Worker       find_connected_nodes (next, roots, visited, connected_roots);
784*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!check_success (!connected_roots.in_error ()))) break;
785*2d1272b8SAndroid Build Coastguard Worker 
786*2d1272b8SAndroid Build Coastguard Worker       isolate_subgraph (connected_roots);
787*2d1272b8SAndroid Build Coastguard Worker       if (unlikely (!check_success (!connected_roots.in_error ()))) break;
788*2d1272b8SAndroid Build Coastguard Worker 
789*2d1272b8SAndroid Build Coastguard Worker       unsigned next_space = this->next_space ();
790*2d1272b8SAndroid Build Coastguard Worker       num_roots_for_space_.push (0);
791*2d1272b8SAndroid Build Coastguard Worker       for (unsigned root : connected_roots)
792*2d1272b8SAndroid Build Coastguard Worker       {
793*2d1272b8SAndroid Build Coastguard Worker         DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
794*2d1272b8SAndroid Build Coastguard Worker         vertices_[root].space = next_space;
795*2d1272b8SAndroid Build Coastguard Worker         num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1;
796*2d1272b8SAndroid Build Coastguard Worker         distance_invalid = true;
797*2d1272b8SAndroid Build Coastguard Worker         positions_invalid = true;
798*2d1272b8SAndroid Build Coastguard Worker       }
799*2d1272b8SAndroid Build Coastguard Worker 
800*2d1272b8SAndroid Build Coastguard Worker       // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space
801*2d1272b8SAndroid Build Coastguard Worker       //                into the 32 bit space as needed, instead of using isolation.
802*2d1272b8SAndroid Build Coastguard Worker     }
803*2d1272b8SAndroid Build Coastguard Worker 
804*2d1272b8SAndroid Build Coastguard Worker 
805*2d1272b8SAndroid Build Coastguard Worker 
806*2d1272b8SAndroid Build Coastguard Worker     return true;
807*2d1272b8SAndroid Build Coastguard Worker   }
808*2d1272b8SAndroid Build Coastguard Worker 
809*2d1272b8SAndroid Build Coastguard Worker   /*
810*2d1272b8SAndroid Build Coastguard Worker    * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph
811*2d1272b8SAndroid Build Coastguard Worker    * that originate from outside of the subgraph will be removed by duplicating the linked to
812*2d1272b8SAndroid Build Coastguard Worker    * object.
813*2d1272b8SAndroid Build Coastguard Worker    *
814*2d1272b8SAndroid Build Coastguard Worker    * Indices stored in roots will be updated if any of the roots are duplicated to new indices.
815*2d1272b8SAndroid Build Coastguard Worker    */
isolate_subgraphgraph::graph_t816*2d1272b8SAndroid Build Coastguard Worker   bool isolate_subgraph (hb_set_t& roots)
817*2d1272b8SAndroid Build Coastguard Worker   {
818*2d1272b8SAndroid Build Coastguard Worker     update_parents ();
819*2d1272b8SAndroid Build Coastguard Worker     hb_map_t subgraph;
820*2d1272b8SAndroid Build Coastguard Worker 
821*2d1272b8SAndroid Build Coastguard Worker     // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
822*2d1272b8SAndroid Build Coastguard Worker     // set the subgraph incoming edge count to match all of root_idx's incoming edges
823*2d1272b8SAndroid Build Coastguard Worker     hb_set_t parents;
824*2d1272b8SAndroid Build Coastguard Worker     for (unsigned root_idx : roots)
825*2d1272b8SAndroid Build Coastguard Worker     {
826*2d1272b8SAndroid Build Coastguard Worker       subgraph.set (root_idx, wide_parents (root_idx, parents));
827*2d1272b8SAndroid Build Coastguard Worker       find_subgraph (root_idx, subgraph);
828*2d1272b8SAndroid Build Coastguard Worker     }
829*2d1272b8SAndroid Build Coastguard Worker     if (subgraph.in_error ())
830*2d1272b8SAndroid Build Coastguard Worker       return false;
831*2d1272b8SAndroid Build Coastguard Worker 
832*2d1272b8SAndroid Build Coastguard Worker     unsigned original_root_idx = root_idx ();
833*2d1272b8SAndroid Build Coastguard Worker     hb_map_t index_map;
834*2d1272b8SAndroid Build Coastguard Worker     bool made_changes = false;
835*2d1272b8SAndroid Build Coastguard Worker     for (auto entry : subgraph.iter ())
836*2d1272b8SAndroid Build Coastguard Worker     {
837*2d1272b8SAndroid Build Coastguard Worker       assert (entry.first < vertices_.length);
838*2d1272b8SAndroid Build Coastguard Worker       const auto& node = vertices_[entry.first];
839*2d1272b8SAndroid Build Coastguard Worker       unsigned subgraph_incoming_edges = entry.second;
840*2d1272b8SAndroid Build Coastguard Worker 
841*2d1272b8SAndroid Build Coastguard Worker       if (subgraph_incoming_edges < node.incoming_edges ())
842*2d1272b8SAndroid Build Coastguard Worker       {
843*2d1272b8SAndroid Build Coastguard Worker         // Only  de-dup objects with incoming links from outside the subgraph.
844*2d1272b8SAndroid Build Coastguard Worker         made_changes = true;
845*2d1272b8SAndroid Build Coastguard Worker         duplicate_subgraph (entry.first, index_map);
846*2d1272b8SAndroid Build Coastguard Worker       }
847*2d1272b8SAndroid Build Coastguard Worker     }
848*2d1272b8SAndroid Build Coastguard Worker 
849*2d1272b8SAndroid Build Coastguard Worker     if (in_error ())
850*2d1272b8SAndroid Build Coastguard Worker       return false;
851*2d1272b8SAndroid Build Coastguard Worker 
852*2d1272b8SAndroid Build Coastguard Worker     if (!made_changes)
853*2d1272b8SAndroid Build Coastguard Worker       return false;
854*2d1272b8SAndroid Build Coastguard Worker 
855*2d1272b8SAndroid Build Coastguard Worker     if (original_root_idx != root_idx ()
856*2d1272b8SAndroid Build Coastguard Worker         && parents.has (original_root_idx))
857*2d1272b8SAndroid Build Coastguard Worker     {
858*2d1272b8SAndroid Build Coastguard Worker       // If the root idx has changed since parents was determined, update root idx in parents
859*2d1272b8SAndroid Build Coastguard Worker       parents.add (root_idx ());
860*2d1272b8SAndroid Build Coastguard Worker       parents.del (original_root_idx);
861*2d1272b8SAndroid Build Coastguard Worker     }
862*2d1272b8SAndroid Build Coastguard Worker 
863*2d1272b8SAndroid Build Coastguard Worker     auto new_subgraph =
864*2d1272b8SAndroid Build Coastguard Worker         + subgraph.keys ()
865*2d1272b8SAndroid Build Coastguard Worker         | hb_map([&] (uint32_t node_idx) {
866*2d1272b8SAndroid Build Coastguard Worker           const uint32_t *v;
867*2d1272b8SAndroid Build Coastguard Worker           if (index_map.has (node_idx, &v)) return *v;
868*2d1272b8SAndroid Build Coastguard Worker           return node_idx;
869*2d1272b8SAndroid Build Coastguard Worker         })
870*2d1272b8SAndroid Build Coastguard Worker         ;
871*2d1272b8SAndroid Build Coastguard Worker 
872*2d1272b8SAndroid Build Coastguard Worker     remap_obj_indices (index_map, new_subgraph);
873*2d1272b8SAndroid Build Coastguard Worker     remap_obj_indices (index_map, parents.iter (), true);
874*2d1272b8SAndroid Build Coastguard Worker 
875*2d1272b8SAndroid Build Coastguard Worker     // Update roots set with new indices as needed.
876*2d1272b8SAndroid Build Coastguard Worker     for (auto next : roots)
877*2d1272b8SAndroid Build Coastguard Worker     {
878*2d1272b8SAndroid Build Coastguard Worker       const uint32_t *v;
879*2d1272b8SAndroid Build Coastguard Worker       if (index_map.has (next, &v))
880*2d1272b8SAndroid Build Coastguard Worker       {
881*2d1272b8SAndroid Build Coastguard Worker         roots.del (next);
882*2d1272b8SAndroid Build Coastguard Worker         roots.add (*v);
883*2d1272b8SAndroid Build Coastguard Worker       }
884*2d1272b8SAndroid Build Coastguard Worker     }
885*2d1272b8SAndroid Build Coastguard Worker 
886*2d1272b8SAndroid Build Coastguard Worker     return true;
887*2d1272b8SAndroid Build Coastguard Worker   }
888*2d1272b8SAndroid Build Coastguard Worker 
find_subgraphgraph::graph_t889*2d1272b8SAndroid Build Coastguard Worker   void find_subgraph (unsigned node_idx, hb_map_t& subgraph)
890*2d1272b8SAndroid Build Coastguard Worker   {
891*2d1272b8SAndroid Build Coastguard Worker     for (const auto& link : vertices_[node_idx].obj.all_links ())
892*2d1272b8SAndroid Build Coastguard Worker     {
893*2d1272b8SAndroid Build Coastguard Worker       hb_codepoint_t *v;
894*2d1272b8SAndroid Build Coastguard Worker       if (subgraph.has (link.objidx, &v))
895*2d1272b8SAndroid Build Coastguard Worker       {
896*2d1272b8SAndroid Build Coastguard Worker         (*v)++;
897*2d1272b8SAndroid Build Coastguard Worker         continue;
898*2d1272b8SAndroid Build Coastguard Worker       }
899*2d1272b8SAndroid Build Coastguard Worker       subgraph.set (link.objidx, 1);
900*2d1272b8SAndroid Build Coastguard Worker       find_subgraph (link.objidx, subgraph);
901*2d1272b8SAndroid Build Coastguard Worker     }
902*2d1272b8SAndroid Build Coastguard Worker   }
903*2d1272b8SAndroid Build Coastguard Worker 
find_subgraphgraph::graph_t904*2d1272b8SAndroid Build Coastguard Worker   void find_subgraph (unsigned node_idx, hb_set_t& subgraph)
905*2d1272b8SAndroid Build Coastguard Worker   {
906*2d1272b8SAndroid Build Coastguard Worker     if (subgraph.has (node_idx)) return;
907*2d1272b8SAndroid Build Coastguard Worker     subgraph.add (node_idx);
908*2d1272b8SAndroid Build Coastguard Worker     for (const auto& link : vertices_[node_idx].obj.all_links ())
909*2d1272b8SAndroid Build Coastguard Worker       find_subgraph (link.objidx, subgraph);
910*2d1272b8SAndroid Build Coastguard Worker   }
911*2d1272b8SAndroid Build Coastguard Worker 
find_subgraph_sizegraph::graph_t912*2d1272b8SAndroid Build Coastguard Worker   size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
913*2d1272b8SAndroid Build Coastguard Worker   {
914*2d1272b8SAndroid Build Coastguard Worker     if (subgraph.has (node_idx)) return 0;
915*2d1272b8SAndroid Build Coastguard Worker     subgraph.add (node_idx);
916*2d1272b8SAndroid Build Coastguard Worker 
917*2d1272b8SAndroid Build Coastguard Worker     const auto& o = vertices_[node_idx].obj;
918*2d1272b8SAndroid Build Coastguard Worker     size_t size = o.tail - o.head;
919*2d1272b8SAndroid Build Coastguard Worker     if (max_depth == 0)
920*2d1272b8SAndroid Build Coastguard Worker       return size;
921*2d1272b8SAndroid Build Coastguard Worker 
922*2d1272b8SAndroid Build Coastguard Worker     for (const auto& link : o.all_links ())
923*2d1272b8SAndroid Build Coastguard Worker       size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
924*2d1272b8SAndroid Build Coastguard Worker     return size;
925*2d1272b8SAndroid Build Coastguard Worker   }
926*2d1272b8SAndroid Build Coastguard Worker 
927*2d1272b8SAndroid Build Coastguard Worker   /*
928*2d1272b8SAndroid Build Coastguard Worker    * Finds the topmost children of 32bit offsets in the subgraph starting
929*2d1272b8SAndroid Build Coastguard Worker    * at node_idx. Found indices are placed into 'found'.
930*2d1272b8SAndroid Build Coastguard Worker    */
find_32bit_rootsgraph::graph_t931*2d1272b8SAndroid Build Coastguard Worker   void find_32bit_roots (unsigned node_idx, hb_set_t& found)
932*2d1272b8SAndroid Build Coastguard Worker   {
933*2d1272b8SAndroid Build Coastguard Worker     for (const auto& link : vertices_[node_idx].obj.all_links ())
934*2d1272b8SAndroid Build Coastguard Worker     {
935*2d1272b8SAndroid Build Coastguard Worker       if (!link.is_signed && link.width == 4) {
936*2d1272b8SAndroid Build Coastguard Worker         found.add (link.objidx);
937*2d1272b8SAndroid Build Coastguard Worker         continue;
938*2d1272b8SAndroid Build Coastguard Worker       }
939*2d1272b8SAndroid Build Coastguard Worker       find_32bit_roots (link.objidx, found);
940*2d1272b8SAndroid Build Coastguard Worker     }
941*2d1272b8SAndroid Build Coastguard Worker   }
942*2d1272b8SAndroid Build Coastguard Worker 
943*2d1272b8SAndroid Build Coastguard Worker   /*
944*2d1272b8SAndroid Build Coastguard Worker    * Moves the child of old_parent_idx pointed to by old_offset to a new
945*2d1272b8SAndroid Build Coastguard Worker    * vertex at the new_offset.
946*2d1272b8SAndroid Build Coastguard Worker    */
947*2d1272b8SAndroid Build Coastguard Worker   template<typename O>
move_childgraph::graph_t948*2d1272b8SAndroid Build Coastguard Worker   void move_child (unsigned old_parent_idx,
949*2d1272b8SAndroid Build Coastguard Worker                    const O* old_offset,
950*2d1272b8SAndroid Build Coastguard Worker                    unsigned new_parent_idx,
951*2d1272b8SAndroid Build Coastguard Worker                    const O* new_offset)
952*2d1272b8SAndroid Build Coastguard Worker   {
953*2d1272b8SAndroid Build Coastguard Worker     distance_invalid = true;
954*2d1272b8SAndroid Build Coastguard Worker     positions_invalid = true;
955*2d1272b8SAndroid Build Coastguard Worker 
956*2d1272b8SAndroid Build Coastguard Worker     auto& old_v = vertices_[old_parent_idx];
957*2d1272b8SAndroid Build Coastguard Worker     auto& new_v = vertices_[new_parent_idx];
958*2d1272b8SAndroid Build Coastguard Worker 
959*2d1272b8SAndroid Build Coastguard Worker     unsigned child_id = index_for_offset (old_parent_idx,
960*2d1272b8SAndroid Build Coastguard Worker                                           old_offset);
961*2d1272b8SAndroid Build Coastguard Worker 
962*2d1272b8SAndroid Build Coastguard Worker     auto* new_link = new_v.obj.real_links.push ();
963*2d1272b8SAndroid Build Coastguard Worker     new_link->width = O::static_size;
964*2d1272b8SAndroid Build Coastguard Worker     new_link->objidx = child_id;
965*2d1272b8SAndroid Build Coastguard Worker     new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
966*2d1272b8SAndroid Build Coastguard Worker 
967*2d1272b8SAndroid Build Coastguard Worker     auto& child = vertices_[child_id];
968*2d1272b8SAndroid Build Coastguard Worker     child.add_parent (new_parent_idx);
969*2d1272b8SAndroid Build Coastguard Worker 
970*2d1272b8SAndroid Build Coastguard Worker     old_v.remove_real_link (child_id, old_offset);
971*2d1272b8SAndroid Build Coastguard Worker     child.remove_parent (old_parent_idx);
972*2d1272b8SAndroid Build Coastguard Worker   }
973*2d1272b8SAndroid Build Coastguard Worker 
974*2d1272b8SAndroid Build Coastguard Worker   /*
975*2d1272b8SAndroid Build Coastguard Worker    * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
976*2d1272b8SAndroid Build Coastguard Worker    * links. index_map is updated with mappings from old id to new id. If a duplication has already
977*2d1272b8SAndroid Build Coastguard Worker    * been performed for a given index, then it will be skipped.
978*2d1272b8SAndroid Build Coastguard Worker    */
duplicate_subgraphgraph::graph_t979*2d1272b8SAndroid Build Coastguard Worker   void duplicate_subgraph (unsigned node_idx, hb_map_t& index_map)
980*2d1272b8SAndroid Build Coastguard Worker   {
981*2d1272b8SAndroid Build Coastguard Worker     if (index_map.has (node_idx))
982*2d1272b8SAndroid Build Coastguard Worker       return;
983*2d1272b8SAndroid Build Coastguard Worker 
984*2d1272b8SAndroid Build Coastguard Worker     unsigned clone_idx = duplicate (node_idx);
985*2d1272b8SAndroid Build Coastguard Worker     if (!check_success (clone_idx != (unsigned) -1))
986*2d1272b8SAndroid Build Coastguard Worker       return;
987*2d1272b8SAndroid Build Coastguard Worker 
988*2d1272b8SAndroid Build Coastguard Worker     index_map.set (node_idx, clone_idx);
989*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : object (node_idx).all_links ()) {
990*2d1272b8SAndroid Build Coastguard Worker       duplicate_subgraph (l.objidx, index_map);
991*2d1272b8SAndroid Build Coastguard Worker     }
992*2d1272b8SAndroid Build Coastguard Worker   }
993*2d1272b8SAndroid Build Coastguard Worker 
994*2d1272b8SAndroid Build Coastguard Worker   /*
995*2d1272b8SAndroid Build Coastguard Worker    * Creates a copy of node_idx and returns it's new index.
996*2d1272b8SAndroid Build Coastguard Worker    */
duplicategraph::graph_t997*2d1272b8SAndroid Build Coastguard Worker   unsigned duplicate (unsigned node_idx)
998*2d1272b8SAndroid Build Coastguard Worker   {
999*2d1272b8SAndroid Build Coastguard Worker     positions_invalid = true;
1000*2d1272b8SAndroid Build Coastguard Worker     distance_invalid = true;
1001*2d1272b8SAndroid Build Coastguard Worker 
1002*2d1272b8SAndroid Build Coastguard Worker     auto* clone = vertices_.push ();
1003*2d1272b8SAndroid Build Coastguard Worker     auto& child = vertices_[node_idx];
1004*2d1272b8SAndroid Build Coastguard Worker     if (vertices_.in_error ()) {
1005*2d1272b8SAndroid Build Coastguard Worker       return -1;
1006*2d1272b8SAndroid Build Coastguard Worker     }
1007*2d1272b8SAndroid Build Coastguard Worker 
1008*2d1272b8SAndroid Build Coastguard Worker     clone->obj.head = child.obj.head;
1009*2d1272b8SAndroid Build Coastguard Worker     clone->obj.tail = child.obj.tail;
1010*2d1272b8SAndroid Build Coastguard Worker     clone->distance = child.distance;
1011*2d1272b8SAndroid Build Coastguard Worker     clone->space = child.space;
1012*2d1272b8SAndroid Build Coastguard Worker     clone->reset_parents ();
1013*2d1272b8SAndroid Build Coastguard Worker 
1014*2d1272b8SAndroid Build Coastguard Worker     unsigned clone_idx = vertices_.length - 2;
1015*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : child.obj.real_links)
1016*2d1272b8SAndroid Build Coastguard Worker     {
1017*2d1272b8SAndroid Build Coastguard Worker       clone->obj.real_links.push (l);
1018*2d1272b8SAndroid Build Coastguard Worker       vertices_[l.objidx].add_parent (clone_idx);
1019*2d1272b8SAndroid Build Coastguard Worker     }
1020*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : child.obj.virtual_links)
1021*2d1272b8SAndroid Build Coastguard Worker     {
1022*2d1272b8SAndroid Build Coastguard Worker       clone->obj.virtual_links.push (l);
1023*2d1272b8SAndroid Build Coastguard Worker       vertices_[l.objidx].add_parent (clone_idx);
1024*2d1272b8SAndroid Build Coastguard Worker     }
1025*2d1272b8SAndroid Build Coastguard Worker 
1026*2d1272b8SAndroid Build Coastguard Worker     check_success (!clone->obj.real_links.in_error ());
1027*2d1272b8SAndroid Build Coastguard Worker     check_success (!clone->obj.virtual_links.in_error ());
1028*2d1272b8SAndroid Build Coastguard Worker 
1029*2d1272b8SAndroid Build Coastguard Worker     // The last object is the root of the graph, so swap back the root to the end.
1030*2d1272b8SAndroid Build Coastguard Worker     // The root's obj idx does change, however since it's root nothing else refers to it.
1031*2d1272b8SAndroid Build Coastguard Worker     // all other obj idx's will be unaffected.
1032*2d1272b8SAndroid Build Coastguard Worker     hb_swap (vertices_[vertices_.length - 2], *clone);
1033*2d1272b8SAndroid Build Coastguard Worker 
1034*2d1272b8SAndroid Build Coastguard Worker     // Since the root moved, update the parents arrays of all children on the root.
1035*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : root ().obj.all_links ())
1036*2d1272b8SAndroid Build Coastguard Worker       vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
1037*2d1272b8SAndroid Build Coastguard Worker 
1038*2d1272b8SAndroid Build Coastguard Worker     return clone_idx;
1039*2d1272b8SAndroid Build Coastguard Worker   }
1040*2d1272b8SAndroid Build Coastguard Worker 
1041*2d1272b8SAndroid Build Coastguard Worker   /*
1042*2d1272b8SAndroid Build Coastguard Worker    * Creates a copy of child and re-assigns the link from
1043*2d1272b8SAndroid Build Coastguard Worker    * parent to the clone. The copy is a shallow copy, objects
1044*2d1272b8SAndroid Build Coastguard Worker    * linked from child are not duplicated.
1045*2d1272b8SAndroid Build Coastguard Worker    *
1046*2d1272b8SAndroid Build Coastguard Worker    * Returns the index of the newly created duplicate.
1047*2d1272b8SAndroid Build Coastguard Worker    *
1048*2d1272b8SAndroid Build Coastguard Worker    * If the child_idx only has incoming edges from parent_idx, this
1049*2d1272b8SAndroid Build Coastguard Worker    * will do nothing and return the original child_idx.
1050*2d1272b8SAndroid Build Coastguard Worker    */
duplicate_if_sharedgraph::graph_t1051*2d1272b8SAndroid Build Coastguard Worker   unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
1052*2d1272b8SAndroid Build Coastguard Worker   {
1053*2d1272b8SAndroid Build Coastguard Worker     unsigned new_idx = duplicate (parent_idx, child_idx);
1054*2d1272b8SAndroid Build Coastguard Worker     if (new_idx == (unsigned) -1) return child_idx;
1055*2d1272b8SAndroid Build Coastguard Worker     return new_idx;
1056*2d1272b8SAndroid Build Coastguard Worker   }
1057*2d1272b8SAndroid Build Coastguard Worker 
1058*2d1272b8SAndroid Build Coastguard Worker 
1059*2d1272b8SAndroid Build Coastguard Worker   /*
1060*2d1272b8SAndroid Build Coastguard Worker    * Creates a copy of child and re-assigns the link from
1061*2d1272b8SAndroid Build Coastguard Worker    * parent to the clone. The copy is a shallow copy, objects
1062*2d1272b8SAndroid Build Coastguard Worker    * linked from child are not duplicated.
1063*2d1272b8SAndroid Build Coastguard Worker    *
1064*2d1272b8SAndroid Build Coastguard Worker    * Returns the index of the newly created duplicate.
1065*2d1272b8SAndroid Build Coastguard Worker    *
1066*2d1272b8SAndroid Build Coastguard Worker    * If the child_idx only has incoming edges from parent_idx,
1067*2d1272b8SAndroid Build Coastguard Worker    * duplication isn't possible and this will return -1.
1068*2d1272b8SAndroid Build Coastguard Worker    */
duplicategraph::graph_t1069*2d1272b8SAndroid Build Coastguard Worker   unsigned duplicate (unsigned parent_idx, unsigned child_idx)
1070*2d1272b8SAndroid Build Coastguard Worker   {
1071*2d1272b8SAndroid Build Coastguard Worker     update_parents ();
1072*2d1272b8SAndroid Build Coastguard Worker 
1073*2d1272b8SAndroid Build Coastguard Worker     const auto& child = vertices_[child_idx];
1074*2d1272b8SAndroid Build Coastguard Worker     unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
1075*2d1272b8SAndroid Build Coastguard Worker 
1076*2d1272b8SAndroid Build Coastguard Worker     if (child.incoming_edges () <= links_to_child)
1077*2d1272b8SAndroid Build Coastguard Worker     {
1078*2d1272b8SAndroid Build Coastguard Worker       // Can't duplicate this node, doing so would orphan the original one as all remaining links
1079*2d1272b8SAndroid Build Coastguard Worker       // to child are from parent.
1080*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u => %u",
1081*2d1272b8SAndroid Build Coastguard Worker                  parent_idx, child_idx);
1082*2d1272b8SAndroid Build Coastguard Worker       return -1;
1083*2d1272b8SAndroid Build Coastguard Worker     }
1084*2d1272b8SAndroid Build Coastguard Worker 
1085*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %u => %u",
1086*2d1272b8SAndroid Build Coastguard Worker                parent_idx, child_idx);
1087*2d1272b8SAndroid Build Coastguard Worker 
1088*2d1272b8SAndroid Build Coastguard Worker     unsigned clone_idx = duplicate (child_idx);
1089*2d1272b8SAndroid Build Coastguard Worker     if (clone_idx == (unsigned) -1) return -1;
1090*2d1272b8SAndroid Build Coastguard Worker     // duplicate shifts the root node idx, so if parent_idx was root update it.
1091*2d1272b8SAndroid Build Coastguard Worker     if (parent_idx == clone_idx) parent_idx++;
1092*2d1272b8SAndroid Build Coastguard Worker 
1093*2d1272b8SAndroid Build Coastguard Worker     auto& parent = vertices_[parent_idx];
1094*2d1272b8SAndroid Build Coastguard Worker     for (auto& l : parent.obj.all_links_writer ())
1095*2d1272b8SAndroid Build Coastguard Worker     {
1096*2d1272b8SAndroid Build Coastguard Worker       if (l.objidx != child_idx)
1097*2d1272b8SAndroid Build Coastguard Worker         continue;
1098*2d1272b8SAndroid Build Coastguard Worker 
1099*2d1272b8SAndroid Build Coastguard Worker       reassign_link (l, parent_idx, clone_idx);
1100*2d1272b8SAndroid Build Coastguard Worker     }
1101*2d1272b8SAndroid Build Coastguard Worker 
1102*2d1272b8SAndroid Build Coastguard Worker     return clone_idx;
1103*2d1272b8SAndroid Build Coastguard Worker   }
1104*2d1272b8SAndroid Build Coastguard Worker 
1105*2d1272b8SAndroid Build Coastguard Worker   /*
1106*2d1272b8SAndroid Build Coastguard Worker    * Creates a copy of child and re-assigns the links from
1107*2d1272b8SAndroid Build Coastguard Worker    * parents to the clone. The copy is a shallow copy, objects
1108*2d1272b8SAndroid Build Coastguard Worker    * linked from child are not duplicated.
1109*2d1272b8SAndroid Build Coastguard Worker    *
1110*2d1272b8SAndroid Build Coastguard Worker    * Returns the index of the newly created duplicate.
1111*2d1272b8SAndroid Build Coastguard Worker    *
1112*2d1272b8SAndroid Build Coastguard Worker    * If the child_idx only has incoming edges from parents,
1113*2d1272b8SAndroid Build Coastguard Worker    * duplication isn't possible or duplication fails and this will
1114*2d1272b8SAndroid Build Coastguard Worker    * return -1.
1115*2d1272b8SAndroid Build Coastguard Worker    */
duplicategraph::graph_t1116*2d1272b8SAndroid Build Coastguard Worker   unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
1117*2d1272b8SAndroid Build Coastguard Worker   {
1118*2d1272b8SAndroid Build Coastguard Worker     if (parents->is_empty()) {
1119*2d1272b8SAndroid Build Coastguard Worker       return -1;
1120*2d1272b8SAndroid Build Coastguard Worker     }
1121*2d1272b8SAndroid Build Coastguard Worker 
1122*2d1272b8SAndroid Build Coastguard Worker     update_parents ();
1123*2d1272b8SAndroid Build Coastguard Worker 
1124*2d1272b8SAndroid Build Coastguard Worker     const auto& child = vertices_[child_idx];
1125*2d1272b8SAndroid Build Coastguard Worker     unsigned links_to_child = 0;
1126*2d1272b8SAndroid Build Coastguard Worker     unsigned last_parent = parents->get_max();
1127*2d1272b8SAndroid Build Coastguard Worker     unsigned first_parent = parents->get_min();
1128*2d1272b8SAndroid Build Coastguard Worker     for (unsigned parent_idx : *parents) {
1129*2d1272b8SAndroid Build Coastguard Worker       links_to_child += child.incoming_edges_from_parent(parent_idx);
1130*2d1272b8SAndroid Build Coastguard Worker     }
1131*2d1272b8SAndroid Build Coastguard Worker 
1132*2d1272b8SAndroid Build Coastguard Worker     if (child.incoming_edges () <= links_to_child)
1133*2d1272b8SAndroid Build Coastguard Worker     {
1134*2d1272b8SAndroid Build Coastguard Worker       // Can't duplicate this node, doing so would orphan the original one as all remaining links
1135*2d1272b8SAndroid Build Coastguard Worker       // to child are from parent.
1136*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
1137*2d1272b8SAndroid Build Coastguard Worker       return -1;
1138*2d1272b8SAndroid Build Coastguard Worker     }
1139*2d1272b8SAndroid Build Coastguard Worker 
1140*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
1141*2d1272b8SAndroid Build Coastguard Worker 
1142*2d1272b8SAndroid Build Coastguard Worker     unsigned clone_idx = duplicate (child_idx);
1143*2d1272b8SAndroid Build Coastguard Worker     if (clone_idx == (unsigned) -1) return false;
1144*2d1272b8SAndroid Build Coastguard Worker 
1145*2d1272b8SAndroid Build Coastguard Worker     for (unsigned parent_idx : *parents) {
1146*2d1272b8SAndroid Build Coastguard Worker       // duplicate shifts the root node idx, so if parent_idx was root update it.
1147*2d1272b8SAndroid Build Coastguard Worker       if (parent_idx == clone_idx) parent_idx++;
1148*2d1272b8SAndroid Build Coastguard Worker       auto& parent = vertices_[parent_idx];
1149*2d1272b8SAndroid Build Coastguard Worker       for (auto& l : parent.obj.all_links_writer ())
1150*2d1272b8SAndroid Build Coastguard Worker       {
1151*2d1272b8SAndroid Build Coastguard Worker         if (l.objidx != child_idx)
1152*2d1272b8SAndroid Build Coastguard Worker           continue;
1153*2d1272b8SAndroid Build Coastguard Worker 
1154*2d1272b8SAndroid Build Coastguard Worker         reassign_link (l, parent_idx, clone_idx);
1155*2d1272b8SAndroid Build Coastguard Worker       }
1156*2d1272b8SAndroid Build Coastguard Worker     }
1157*2d1272b8SAndroid Build Coastguard Worker 
1158*2d1272b8SAndroid Build Coastguard Worker     return clone_idx;
1159*2d1272b8SAndroid Build Coastguard Worker   }
1160*2d1272b8SAndroid Build Coastguard Worker 
1161*2d1272b8SAndroid Build Coastguard Worker 
1162*2d1272b8SAndroid Build Coastguard Worker   /*
1163*2d1272b8SAndroid Build Coastguard Worker    * Adds a new node to the graph, not connected to anything.
1164*2d1272b8SAndroid Build Coastguard Worker    */
new_nodegraph::graph_t1165*2d1272b8SAndroid Build Coastguard Worker   unsigned new_node (char* head, char* tail)
1166*2d1272b8SAndroid Build Coastguard Worker   {
1167*2d1272b8SAndroid Build Coastguard Worker     positions_invalid = true;
1168*2d1272b8SAndroid Build Coastguard Worker     distance_invalid = true;
1169*2d1272b8SAndroid Build Coastguard Worker 
1170*2d1272b8SAndroid Build Coastguard Worker     auto* clone = vertices_.push ();
1171*2d1272b8SAndroid Build Coastguard Worker     if (vertices_.in_error ()) {
1172*2d1272b8SAndroid Build Coastguard Worker       return -1;
1173*2d1272b8SAndroid Build Coastguard Worker     }
1174*2d1272b8SAndroid Build Coastguard Worker 
1175*2d1272b8SAndroid Build Coastguard Worker     clone->obj.head = head;
1176*2d1272b8SAndroid Build Coastguard Worker     clone->obj.tail = tail;
1177*2d1272b8SAndroid Build Coastguard Worker     clone->distance = 0;
1178*2d1272b8SAndroid Build Coastguard Worker     clone->space = 0;
1179*2d1272b8SAndroid Build Coastguard Worker 
1180*2d1272b8SAndroid Build Coastguard Worker     unsigned clone_idx = vertices_.length - 2;
1181*2d1272b8SAndroid Build Coastguard Worker 
1182*2d1272b8SAndroid Build Coastguard Worker     // The last object is the root of the graph, so swap back the root to the end.
1183*2d1272b8SAndroid Build Coastguard Worker     // The root's obj idx does change, however since it's root nothing else refers to it.
1184*2d1272b8SAndroid Build Coastguard Worker     // all other obj idx's will be unaffected.
1185*2d1272b8SAndroid Build Coastguard Worker     hb_swap (vertices_[vertices_.length - 2], *clone);
1186*2d1272b8SAndroid Build Coastguard Worker 
1187*2d1272b8SAndroid Build Coastguard Worker     // Since the root moved, update the parents arrays of all children on the root.
1188*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : root ().obj.all_links ())
1189*2d1272b8SAndroid Build Coastguard Worker       vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
1190*2d1272b8SAndroid Build Coastguard Worker 
1191*2d1272b8SAndroid Build Coastguard Worker     return clone_idx;
1192*2d1272b8SAndroid Build Coastguard Worker   }
1193*2d1272b8SAndroid Build Coastguard Worker 
1194*2d1272b8SAndroid Build Coastguard Worker   /*
1195*2d1272b8SAndroid Build Coastguard Worker    * Raises the sorting priority of all children.
1196*2d1272b8SAndroid Build Coastguard Worker    */
raise_childrens_prioritygraph::graph_t1197*2d1272b8SAndroid Build Coastguard Worker   bool raise_childrens_priority (unsigned parent_idx)
1198*2d1272b8SAndroid Build Coastguard Worker   {
1199*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %u",
1200*2d1272b8SAndroid Build Coastguard Worker                parent_idx);
1201*2d1272b8SAndroid Build Coastguard Worker     // This operation doesn't change ordering until a sort is run, so no need
1202*2d1272b8SAndroid Build Coastguard Worker     // to invalidate positions. It does not change graph structure so no need
1203*2d1272b8SAndroid Build Coastguard Worker     // to update distances or edge counts.
1204*2d1272b8SAndroid Build Coastguard Worker     auto& parent = vertices_[parent_idx].obj;
1205*2d1272b8SAndroid Build Coastguard Worker     bool made_change = false;
1206*2d1272b8SAndroid Build Coastguard Worker     for (auto& l : parent.all_links_writer ())
1207*2d1272b8SAndroid Build Coastguard Worker       made_change |= vertices_[l.objidx].raise_priority ();
1208*2d1272b8SAndroid Build Coastguard Worker     return made_change;
1209*2d1272b8SAndroid Build Coastguard Worker   }
1210*2d1272b8SAndroid Build Coastguard Worker 
is_fully_connectedgraph::graph_t1211*2d1272b8SAndroid Build Coastguard Worker   bool is_fully_connected ()
1212*2d1272b8SAndroid Build Coastguard Worker   {
1213*2d1272b8SAndroid Build Coastguard Worker     update_parents();
1214*2d1272b8SAndroid Build Coastguard Worker 
1215*2d1272b8SAndroid Build Coastguard Worker     if (root().incoming_edges ())
1216*2d1272b8SAndroid Build Coastguard Worker       // Root cannot have parents.
1217*2d1272b8SAndroid Build Coastguard Worker       return false;
1218*2d1272b8SAndroid Build Coastguard Worker 
1219*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < root_idx (); i++)
1220*2d1272b8SAndroid Build Coastguard Worker     {
1221*2d1272b8SAndroid Build Coastguard Worker       if (!vertices_[i].incoming_edges ())
1222*2d1272b8SAndroid Build Coastguard Worker         return false;
1223*2d1272b8SAndroid Build Coastguard Worker     }
1224*2d1272b8SAndroid Build Coastguard Worker     return true;
1225*2d1272b8SAndroid Build Coastguard Worker   }
1226*2d1272b8SAndroid Build Coastguard Worker 
1227*2d1272b8SAndroid Build Coastguard Worker #if 0
1228*2d1272b8SAndroid Build Coastguard Worker   /*
1229*2d1272b8SAndroid Build Coastguard Worker    * Saves the current graph to a packed binary format which the repacker fuzzer takes
1230*2d1272b8SAndroid Build Coastguard Worker    * as a seed.
1231*2d1272b8SAndroid Build Coastguard Worker    */
1232*2d1272b8SAndroid Build Coastguard Worker   void save_fuzzer_seed (hb_tag_t tag) const
1233*2d1272b8SAndroid Build Coastguard Worker   {
1234*2d1272b8SAndroid Build Coastguard Worker     FILE* f = fopen ("./repacker_fuzzer_seed", "w");
1235*2d1272b8SAndroid Build Coastguard Worker     fwrite ((void*) &tag, sizeof (tag), 1, f);
1236*2d1272b8SAndroid Build Coastguard Worker 
1237*2d1272b8SAndroid Build Coastguard Worker     uint16_t num_objects = vertices_.length;
1238*2d1272b8SAndroid Build Coastguard Worker     fwrite ((void*) &num_objects, sizeof (num_objects), 1, f);
1239*2d1272b8SAndroid Build Coastguard Worker 
1240*2d1272b8SAndroid Build Coastguard Worker     for (const auto& v : vertices_)
1241*2d1272b8SAndroid Build Coastguard Worker     {
1242*2d1272b8SAndroid Build Coastguard Worker       uint16_t blob_size = v.table_size ();
1243*2d1272b8SAndroid Build Coastguard Worker       fwrite ((void*) &blob_size, sizeof (blob_size), 1, f);
1244*2d1272b8SAndroid Build Coastguard Worker       fwrite ((const void*) v.obj.head, blob_size, 1, f);
1245*2d1272b8SAndroid Build Coastguard Worker     }
1246*2d1272b8SAndroid Build Coastguard Worker 
1247*2d1272b8SAndroid Build Coastguard Worker     uint16_t link_count = 0;
1248*2d1272b8SAndroid Build Coastguard Worker     for (const auto& v : vertices_)
1249*2d1272b8SAndroid Build Coastguard Worker       link_count += v.obj.real_links.length;
1250*2d1272b8SAndroid Build Coastguard Worker 
1251*2d1272b8SAndroid Build Coastguard Worker     fwrite ((void*) &link_count, sizeof (link_count), 1, f);
1252*2d1272b8SAndroid Build Coastguard Worker 
1253*2d1272b8SAndroid Build Coastguard Worker     typedef struct
1254*2d1272b8SAndroid Build Coastguard Worker     {
1255*2d1272b8SAndroid Build Coastguard Worker       uint16_t parent;
1256*2d1272b8SAndroid Build Coastguard Worker       uint16_t child;
1257*2d1272b8SAndroid Build Coastguard Worker       uint16_t position;
1258*2d1272b8SAndroid Build Coastguard Worker       uint8_t width;
1259*2d1272b8SAndroid Build Coastguard Worker     } link_t;
1260*2d1272b8SAndroid Build Coastguard Worker 
1261*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < vertices_.length; i++)
1262*2d1272b8SAndroid Build Coastguard Worker     {
1263*2d1272b8SAndroid Build Coastguard Worker       for (const auto& l : vertices_[i].obj.real_links)
1264*2d1272b8SAndroid Build Coastguard Worker       {
1265*2d1272b8SAndroid Build Coastguard Worker         link_t link {
1266*2d1272b8SAndroid Build Coastguard Worker           (uint16_t) i, (uint16_t) l.objidx,
1267*2d1272b8SAndroid Build Coastguard Worker           (uint16_t) l.position, (uint8_t) l.width
1268*2d1272b8SAndroid Build Coastguard Worker         };
1269*2d1272b8SAndroid Build Coastguard Worker         fwrite ((void*) &link, sizeof (link), 1, f);
1270*2d1272b8SAndroid Build Coastguard Worker       }
1271*2d1272b8SAndroid Build Coastguard Worker     }
1272*2d1272b8SAndroid Build Coastguard Worker 
1273*2d1272b8SAndroid Build Coastguard Worker     fclose (f);
1274*2d1272b8SAndroid Build Coastguard Worker   }
1275*2d1272b8SAndroid Build Coastguard Worker #endif
1276*2d1272b8SAndroid Build Coastguard Worker 
print_orphaned_nodesgraph::graph_t1277*2d1272b8SAndroid Build Coastguard Worker   void print_orphaned_nodes ()
1278*2d1272b8SAndroid Build Coastguard Worker   {
1279*2d1272b8SAndroid Build Coastguard Worker     if (!DEBUG_ENABLED(SUBSET_REPACK)) return;
1280*2d1272b8SAndroid Build Coastguard Worker 
1281*2d1272b8SAndroid Build Coastguard Worker     DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected.");
1282*2d1272b8SAndroid Build Coastguard Worker     parents_invalid = true;
1283*2d1272b8SAndroid Build Coastguard Worker     update_parents();
1284*2d1272b8SAndroid Build Coastguard Worker 
1285*2d1272b8SAndroid Build Coastguard Worker     if (root().incoming_edges ()) {
1286*2d1272b8SAndroid Build Coastguard Worker       DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
1287*2d1272b8SAndroid Build Coastguard Worker     }
1288*2d1272b8SAndroid Build Coastguard Worker 
1289*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < root_idx (); i++)
1290*2d1272b8SAndroid Build Coastguard Worker     {
1291*2d1272b8SAndroid Build Coastguard Worker       const auto& v = vertices_[i];
1292*2d1272b8SAndroid Build Coastguard Worker       if (!v.incoming_edges ())
1293*2d1272b8SAndroid Build Coastguard Worker         DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
1294*2d1272b8SAndroid Build Coastguard Worker     }
1295*2d1272b8SAndroid Build Coastguard Worker   }
1296*2d1272b8SAndroid Build Coastguard Worker 
num_roots_for_spacegraph::graph_t1297*2d1272b8SAndroid Build Coastguard Worker   unsigned num_roots_for_space (unsigned space) const
1298*2d1272b8SAndroid Build Coastguard Worker   {
1299*2d1272b8SAndroid Build Coastguard Worker     return num_roots_for_space_[space];
1300*2d1272b8SAndroid Build Coastguard Worker   }
1301*2d1272b8SAndroid Build Coastguard Worker 
next_spacegraph::graph_t1302*2d1272b8SAndroid Build Coastguard Worker   unsigned next_space () const
1303*2d1272b8SAndroid Build Coastguard Worker   {
1304*2d1272b8SAndroid Build Coastguard Worker     return num_roots_for_space_.length;
1305*2d1272b8SAndroid Build Coastguard Worker   }
1306*2d1272b8SAndroid Build Coastguard Worker 
move_to_new_spacegraph::graph_t1307*2d1272b8SAndroid Build Coastguard Worker   void move_to_new_space (const hb_set_t& indices)
1308*2d1272b8SAndroid Build Coastguard Worker   {
1309*2d1272b8SAndroid Build Coastguard Worker     num_roots_for_space_.push (0);
1310*2d1272b8SAndroid Build Coastguard Worker     unsigned new_space = num_roots_for_space_.length - 1;
1311*2d1272b8SAndroid Build Coastguard Worker 
1312*2d1272b8SAndroid Build Coastguard Worker     for (unsigned index : indices) {
1313*2d1272b8SAndroid Build Coastguard Worker       auto& node = vertices_[index];
1314*2d1272b8SAndroid Build Coastguard Worker       num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1;
1315*2d1272b8SAndroid Build Coastguard Worker       num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1;
1316*2d1272b8SAndroid Build Coastguard Worker       node.space = new_space;
1317*2d1272b8SAndroid Build Coastguard Worker       distance_invalid = true;
1318*2d1272b8SAndroid Build Coastguard Worker       positions_invalid = true;
1319*2d1272b8SAndroid Build Coastguard Worker     }
1320*2d1272b8SAndroid Build Coastguard Worker   }
1321*2d1272b8SAndroid Build Coastguard Worker 
space_forgraph::graph_t1322*2d1272b8SAndroid Build Coastguard Worker   unsigned space_for (unsigned index, unsigned* root = nullptr) const
1323*2d1272b8SAndroid Build Coastguard Worker   {
1324*2d1272b8SAndroid Build Coastguard Worker   loop:
1325*2d1272b8SAndroid Build Coastguard Worker     assert (index < vertices_.length);
1326*2d1272b8SAndroid Build Coastguard Worker     const auto& node = vertices_[index];
1327*2d1272b8SAndroid Build Coastguard Worker     if (node.space)
1328*2d1272b8SAndroid Build Coastguard Worker     {
1329*2d1272b8SAndroid Build Coastguard Worker       if (root != nullptr)
1330*2d1272b8SAndroid Build Coastguard Worker         *root = index;
1331*2d1272b8SAndroid Build Coastguard Worker       return node.space;
1332*2d1272b8SAndroid Build Coastguard Worker     }
1333*2d1272b8SAndroid Build Coastguard Worker 
1334*2d1272b8SAndroid Build Coastguard Worker     if (!node.incoming_edges ())
1335*2d1272b8SAndroid Build Coastguard Worker     {
1336*2d1272b8SAndroid Build Coastguard Worker       if (root)
1337*2d1272b8SAndroid Build Coastguard Worker         *root = index;
1338*2d1272b8SAndroid Build Coastguard Worker       return 0;
1339*2d1272b8SAndroid Build Coastguard Worker     }
1340*2d1272b8SAndroid Build Coastguard Worker 
1341*2d1272b8SAndroid Build Coastguard Worker     index = *node.parents_iter ();
1342*2d1272b8SAndroid Build Coastguard Worker     goto loop;
1343*2d1272b8SAndroid Build Coastguard Worker   }
1344*2d1272b8SAndroid Build Coastguard Worker 
err_other_errorgraph::graph_t1345*2d1272b8SAndroid Build Coastguard Worker   void err_other_error () { this->successful = false; }
1346*2d1272b8SAndroid Build Coastguard Worker 
total_size_in_bytesgraph::graph_t1347*2d1272b8SAndroid Build Coastguard Worker   size_t total_size_in_bytes () const {
1348*2d1272b8SAndroid Build Coastguard Worker     size_t total_size = 0;
1349*2d1272b8SAndroid Build Coastguard Worker     unsigned count = vertices_.length;
1350*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++) {
1351*2d1272b8SAndroid Build Coastguard Worker       size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
1352*2d1272b8SAndroid Build Coastguard Worker       total_size += size;
1353*2d1272b8SAndroid Build Coastguard Worker     }
1354*2d1272b8SAndroid Build Coastguard Worker     return total_size;
1355*2d1272b8SAndroid Build Coastguard Worker   }
1356*2d1272b8SAndroid Build Coastguard Worker 
1357*2d1272b8SAndroid Build Coastguard Worker 
1358*2d1272b8SAndroid Build Coastguard Worker  private:
1359*2d1272b8SAndroid Build Coastguard Worker 
1360*2d1272b8SAndroid Build Coastguard Worker   /*
1361*2d1272b8SAndroid Build Coastguard Worker    * Returns the numbers of incoming edges that are 24 or 32 bits wide.
1362*2d1272b8SAndroid Build Coastguard Worker    */
wide_parentsgraph::graph_t1363*2d1272b8SAndroid Build Coastguard Worker   unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
1364*2d1272b8SAndroid Build Coastguard Worker   {
1365*2d1272b8SAndroid Build Coastguard Worker     unsigned count = 0;
1366*2d1272b8SAndroid Build Coastguard Worker     for (unsigned p : vertices_[node_idx].parents_iter ())
1367*2d1272b8SAndroid Build Coastguard Worker     {
1368*2d1272b8SAndroid Build Coastguard Worker       // Only real links can be wide
1369*2d1272b8SAndroid Build Coastguard Worker       for (const auto& l : vertices_[p].obj.real_links)
1370*2d1272b8SAndroid Build Coastguard Worker       {
1371*2d1272b8SAndroid Build Coastguard Worker         if (l.objidx == node_idx
1372*2d1272b8SAndroid Build Coastguard Worker             && (l.width == 3 || l.width == 4)
1373*2d1272b8SAndroid Build Coastguard Worker             && !l.is_signed)
1374*2d1272b8SAndroid Build Coastguard Worker         {
1375*2d1272b8SAndroid Build Coastguard Worker           count++;
1376*2d1272b8SAndroid Build Coastguard Worker           parents.add (p);
1377*2d1272b8SAndroid Build Coastguard Worker         }
1378*2d1272b8SAndroid Build Coastguard Worker       }
1379*2d1272b8SAndroid Build Coastguard Worker     }
1380*2d1272b8SAndroid Build Coastguard Worker     return count;
1381*2d1272b8SAndroid Build Coastguard Worker   }
1382*2d1272b8SAndroid Build Coastguard Worker 
check_successgraph::graph_t1383*2d1272b8SAndroid Build Coastguard Worker   bool check_success (bool success)
1384*2d1272b8SAndroid Build Coastguard Worker   { return this->successful && (success || ((void) err_other_error (), false)); }
1385*2d1272b8SAndroid Build Coastguard Worker 
1386*2d1272b8SAndroid Build Coastguard Worker  public:
1387*2d1272b8SAndroid Build Coastguard Worker   /*
1388*2d1272b8SAndroid Build Coastguard Worker    * Creates a map from objid to # of incoming edges.
1389*2d1272b8SAndroid Build Coastguard Worker    */
update_parentsgraph::graph_t1390*2d1272b8SAndroid Build Coastguard Worker   void update_parents ()
1391*2d1272b8SAndroid Build Coastguard Worker   {
1392*2d1272b8SAndroid Build Coastguard Worker     if (!parents_invalid) return;
1393*2d1272b8SAndroid Build Coastguard Worker 
1394*2d1272b8SAndroid Build Coastguard Worker     unsigned count = vertices_.length;
1395*2d1272b8SAndroid Build Coastguard Worker 
1396*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
1397*2d1272b8SAndroid Build Coastguard Worker       vertices_.arrayZ[i].reset_parents ();
1398*2d1272b8SAndroid Build Coastguard Worker 
1399*2d1272b8SAndroid Build Coastguard Worker     for (unsigned p = 0; p < count; p++)
1400*2d1272b8SAndroid Build Coastguard Worker     {
1401*2d1272b8SAndroid Build Coastguard Worker       for (auto& l : vertices_.arrayZ[p].obj.all_links ())
1402*2d1272b8SAndroid Build Coastguard Worker         vertices_[l.objidx].add_parent (p);
1403*2d1272b8SAndroid Build Coastguard Worker     }
1404*2d1272b8SAndroid Build Coastguard Worker 
1405*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
1406*2d1272b8SAndroid Build Coastguard Worker       // parents arrays must be accurate or downstream operations like cycle detection
1407*2d1272b8SAndroid Build Coastguard Worker       // and sorting won't work correctly.
1408*2d1272b8SAndroid Build Coastguard Worker       check_success (!vertices_.arrayZ[i].in_error ());
1409*2d1272b8SAndroid Build Coastguard Worker 
1410*2d1272b8SAndroid Build Coastguard Worker     parents_invalid = false;
1411*2d1272b8SAndroid Build Coastguard Worker   }
1412*2d1272b8SAndroid Build Coastguard Worker 
1413*2d1272b8SAndroid Build Coastguard Worker   /*
1414*2d1272b8SAndroid Build Coastguard Worker    * compute the serialized start and end positions for each vertex.
1415*2d1272b8SAndroid Build Coastguard Worker    */
update_positionsgraph::graph_t1416*2d1272b8SAndroid Build Coastguard Worker   void update_positions ()
1417*2d1272b8SAndroid Build Coastguard Worker   {
1418*2d1272b8SAndroid Build Coastguard Worker     if (!positions_invalid) return;
1419*2d1272b8SAndroid Build Coastguard Worker 
1420*2d1272b8SAndroid Build Coastguard Worker     unsigned current_pos = 0;
1421*2d1272b8SAndroid Build Coastguard Worker     for (int i = root_idx (); i >= 0; i--)
1422*2d1272b8SAndroid Build Coastguard Worker     {
1423*2d1272b8SAndroid Build Coastguard Worker       auto& v = vertices_[i];
1424*2d1272b8SAndroid Build Coastguard Worker       v.start = current_pos;
1425*2d1272b8SAndroid Build Coastguard Worker       current_pos += v.obj.tail - v.obj.head;
1426*2d1272b8SAndroid Build Coastguard Worker       v.end = current_pos;
1427*2d1272b8SAndroid Build Coastguard Worker     }
1428*2d1272b8SAndroid Build Coastguard Worker 
1429*2d1272b8SAndroid Build Coastguard Worker     positions_invalid = false;
1430*2d1272b8SAndroid Build Coastguard Worker   }
1431*2d1272b8SAndroid Build Coastguard Worker 
1432*2d1272b8SAndroid Build Coastguard Worker   /*
1433*2d1272b8SAndroid Build Coastguard Worker    * Finds the distance to each object in the graph
1434*2d1272b8SAndroid Build Coastguard Worker    * from the initial node.
1435*2d1272b8SAndroid Build Coastguard Worker    */
update_distancesgraph::graph_t1436*2d1272b8SAndroid Build Coastguard Worker   void update_distances ()
1437*2d1272b8SAndroid Build Coastguard Worker   {
1438*2d1272b8SAndroid Build Coastguard Worker     if (!distance_invalid) return;
1439*2d1272b8SAndroid Build Coastguard Worker 
1440*2d1272b8SAndroid Build Coastguard Worker     // Uses Dijkstra's algorithm to find all of the shortest distances.
1441*2d1272b8SAndroid Build Coastguard Worker     // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
1442*2d1272b8SAndroid Build Coastguard Worker     //
1443*2d1272b8SAndroid Build Coastguard Worker     // Implementation Note:
1444*2d1272b8SAndroid Build Coastguard Worker     // Since our priority queue doesn't support fast priority decreases
1445*2d1272b8SAndroid Build Coastguard Worker     // we instead just add new entries into the queue when a priority changes.
1446*2d1272b8SAndroid Build Coastguard Worker     // Redundant ones are filtered out later on by the visited set.
1447*2d1272b8SAndroid Build Coastguard Worker     // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
1448*2d1272b8SAndroid Build Coastguard Worker     // for practical performance this is faster then using a more advanced queue
1449*2d1272b8SAndroid Build Coastguard Worker     // (such as a fibonacci queue) with a fast decrease priority.
1450*2d1272b8SAndroid Build Coastguard Worker     unsigned count = vertices_.length;
1451*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
1452*2d1272b8SAndroid Build Coastguard Worker       vertices_.arrayZ[i].distance = hb_int_max (int64_t);
1453*2d1272b8SAndroid Build Coastguard Worker     vertices_.tail ().distance = 0;
1454*2d1272b8SAndroid Build Coastguard Worker 
1455*2d1272b8SAndroid Build Coastguard Worker     hb_priority_queue_t<int64_t> queue;
1456*2d1272b8SAndroid Build Coastguard Worker     queue.alloc (count);
1457*2d1272b8SAndroid Build Coastguard Worker     queue.insert (0, vertices_.length - 1);
1458*2d1272b8SAndroid Build Coastguard Worker 
1459*2d1272b8SAndroid Build Coastguard Worker     hb_vector_t<bool> visited;
1460*2d1272b8SAndroid Build Coastguard Worker     visited.resize (vertices_.length);
1461*2d1272b8SAndroid Build Coastguard Worker 
1462*2d1272b8SAndroid Build Coastguard Worker     while (!queue.in_error () && !queue.is_empty ())
1463*2d1272b8SAndroid Build Coastguard Worker     {
1464*2d1272b8SAndroid Build Coastguard Worker       unsigned next_idx = queue.pop_minimum ().second;
1465*2d1272b8SAndroid Build Coastguard Worker       if (visited[next_idx]) continue;
1466*2d1272b8SAndroid Build Coastguard Worker       const auto& next = vertices_[next_idx];
1467*2d1272b8SAndroid Build Coastguard Worker       int64_t next_distance = vertices_[next_idx].distance;
1468*2d1272b8SAndroid Build Coastguard Worker       visited[next_idx] = true;
1469*2d1272b8SAndroid Build Coastguard Worker 
1470*2d1272b8SAndroid Build Coastguard Worker       for (const auto& link : next.obj.all_links ())
1471*2d1272b8SAndroid Build Coastguard Worker       {
1472*2d1272b8SAndroid Build Coastguard Worker         if (visited[link.objidx]) continue;
1473*2d1272b8SAndroid Build Coastguard Worker 
1474*2d1272b8SAndroid Build Coastguard Worker         const auto& child = vertices_.arrayZ[link.objidx].obj;
1475*2d1272b8SAndroid Build Coastguard Worker         unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
1476*2d1272b8SAndroid Build Coastguard Worker         int64_t child_weight = (child.tail - child.head) +
1477*2d1272b8SAndroid Build Coastguard Worker                                ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
1478*2d1272b8SAndroid Build Coastguard Worker         int64_t child_distance = next_distance + child_weight;
1479*2d1272b8SAndroid Build Coastguard Worker 
1480*2d1272b8SAndroid Build Coastguard Worker         if (child_distance < vertices_.arrayZ[link.objidx].distance)
1481*2d1272b8SAndroid Build Coastguard Worker         {
1482*2d1272b8SAndroid Build Coastguard Worker           vertices_.arrayZ[link.objidx].distance = child_distance;
1483*2d1272b8SAndroid Build Coastguard Worker           queue.insert (child_distance, link.objidx);
1484*2d1272b8SAndroid Build Coastguard Worker         }
1485*2d1272b8SAndroid Build Coastguard Worker       }
1486*2d1272b8SAndroid Build Coastguard Worker     }
1487*2d1272b8SAndroid Build Coastguard Worker 
1488*2d1272b8SAndroid Build Coastguard Worker     check_success (!queue.in_error ());
1489*2d1272b8SAndroid Build Coastguard Worker     if (!check_success (queue.is_empty ()))
1490*2d1272b8SAndroid Build Coastguard Worker     {
1491*2d1272b8SAndroid Build Coastguard Worker       print_orphaned_nodes ();
1492*2d1272b8SAndroid Build Coastguard Worker       return;
1493*2d1272b8SAndroid Build Coastguard Worker     }
1494*2d1272b8SAndroid Build Coastguard Worker 
1495*2d1272b8SAndroid Build Coastguard Worker     distance_invalid = false;
1496*2d1272b8SAndroid Build Coastguard Worker   }
1497*2d1272b8SAndroid Build Coastguard Worker 
1498*2d1272b8SAndroid Build Coastguard Worker  private:
1499*2d1272b8SAndroid Build Coastguard Worker   /*
1500*2d1272b8SAndroid Build Coastguard Worker    * Updates a link in the graph to point to a different object. Corrects the
1501*2d1272b8SAndroid Build Coastguard Worker    * parents vector on the previous and new child nodes.
1502*2d1272b8SAndroid Build Coastguard Worker    */
reassign_linkgraph::graph_t1503*2d1272b8SAndroid Build Coastguard Worker   void reassign_link (hb_serialize_context_t::object_t::link_t& link,
1504*2d1272b8SAndroid Build Coastguard Worker                       unsigned parent_idx,
1505*2d1272b8SAndroid Build Coastguard Worker                       unsigned new_idx)
1506*2d1272b8SAndroid Build Coastguard Worker   {
1507*2d1272b8SAndroid Build Coastguard Worker     unsigned old_idx = link.objidx;
1508*2d1272b8SAndroid Build Coastguard Worker     link.objidx = new_idx;
1509*2d1272b8SAndroid Build Coastguard Worker     vertices_[old_idx].remove_parent (parent_idx);
1510*2d1272b8SAndroid Build Coastguard Worker     vertices_[new_idx].add_parent (parent_idx);
1511*2d1272b8SAndroid Build Coastguard Worker   }
1512*2d1272b8SAndroid Build Coastguard Worker 
1513*2d1272b8SAndroid Build Coastguard Worker   /*
1514*2d1272b8SAndroid Build Coastguard Worker    * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts.
1515*2d1272b8SAndroid Build Coastguard Worker    */
1516*2d1272b8SAndroid Build Coastguard Worker   template<typename Iterator, hb_requires (hb_is_iterator (Iterator))>
remap_obj_indicesgraph::graph_t1517*2d1272b8SAndroid Build Coastguard Worker   void remap_obj_indices (const hb_map_t& id_map,
1518*2d1272b8SAndroid Build Coastguard Worker                           Iterator subgraph,
1519*2d1272b8SAndroid Build Coastguard Worker                           bool only_wide = false)
1520*2d1272b8SAndroid Build Coastguard Worker   {
1521*2d1272b8SAndroid Build Coastguard Worker     if (!id_map) return;
1522*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i : subgraph)
1523*2d1272b8SAndroid Build Coastguard Worker     {
1524*2d1272b8SAndroid Build Coastguard Worker       for (auto& link : vertices_[i].obj.all_links_writer ())
1525*2d1272b8SAndroid Build Coastguard Worker       {
1526*2d1272b8SAndroid Build Coastguard Worker         const uint32_t *v;
1527*2d1272b8SAndroid Build Coastguard Worker         if (!id_map.has (link.objidx, &v)) continue;
1528*2d1272b8SAndroid Build Coastguard Worker         if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
1529*2d1272b8SAndroid Build Coastguard Worker 
1530*2d1272b8SAndroid Build Coastguard Worker         reassign_link (link, i, *v);
1531*2d1272b8SAndroid Build Coastguard Worker       }
1532*2d1272b8SAndroid Build Coastguard Worker     }
1533*2d1272b8SAndroid Build Coastguard Worker   }
1534*2d1272b8SAndroid Build Coastguard Worker 
1535*2d1272b8SAndroid Build Coastguard Worker   /*
1536*2d1272b8SAndroid Build Coastguard Worker    * Updates all objidx's in all links using the provided mapping.
1537*2d1272b8SAndroid Build Coastguard Worker    */
remap_all_obj_indicesgraph::graph_t1538*2d1272b8SAndroid Build Coastguard Worker   bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
1539*2d1272b8SAndroid Build Coastguard Worker                               hb_vector_t<vertex_t>* sorted_graph) const
1540*2d1272b8SAndroid Build Coastguard Worker   {
1541*2d1272b8SAndroid Build Coastguard Worker     unsigned count = sorted_graph->length;
1542*2d1272b8SAndroid Build Coastguard Worker     for (unsigned i = 0; i < count; i++)
1543*2d1272b8SAndroid Build Coastguard Worker     {
1544*2d1272b8SAndroid Build Coastguard Worker       if (!(*sorted_graph)[i].remap_parents (id_map))
1545*2d1272b8SAndroid Build Coastguard Worker         return false;
1546*2d1272b8SAndroid Build Coastguard Worker       for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
1547*2d1272b8SAndroid Build Coastguard Worker       {
1548*2d1272b8SAndroid Build Coastguard Worker         link.objidx = id_map[link.objidx];
1549*2d1272b8SAndroid Build Coastguard Worker       }
1550*2d1272b8SAndroid Build Coastguard Worker     }
1551*2d1272b8SAndroid Build Coastguard Worker     return true;
1552*2d1272b8SAndroid Build Coastguard Worker   }
1553*2d1272b8SAndroid Build Coastguard Worker 
1554*2d1272b8SAndroid Build Coastguard Worker   /*
1555*2d1272b8SAndroid Build Coastguard Worker    * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
1556*2d1272b8SAndroid Build Coastguard Worker    * For this search the graph is treated as being undirected.
1557*2d1272b8SAndroid Build Coastguard Worker    *
1558*2d1272b8SAndroid Build Coastguard Worker    * Connected targets will be added to connected and removed from targets. All visited nodes
1559*2d1272b8SAndroid Build Coastguard Worker    * will be added to visited.
1560*2d1272b8SAndroid Build Coastguard Worker    */
find_connected_nodesgraph::graph_t1561*2d1272b8SAndroid Build Coastguard Worker   void find_connected_nodes (unsigned start_idx,
1562*2d1272b8SAndroid Build Coastguard Worker                              hb_set_t& targets,
1563*2d1272b8SAndroid Build Coastguard Worker                              hb_set_t& visited,
1564*2d1272b8SAndroid Build Coastguard Worker                              hb_set_t& connected)
1565*2d1272b8SAndroid Build Coastguard Worker   {
1566*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!check_success (!visited.in_error ()))) return;
1567*2d1272b8SAndroid Build Coastguard Worker     if (visited.has (start_idx)) return;
1568*2d1272b8SAndroid Build Coastguard Worker     visited.add (start_idx);
1569*2d1272b8SAndroid Build Coastguard Worker 
1570*2d1272b8SAndroid Build Coastguard Worker     if (targets.has (start_idx))
1571*2d1272b8SAndroid Build Coastguard Worker     {
1572*2d1272b8SAndroid Build Coastguard Worker       targets.del (start_idx);
1573*2d1272b8SAndroid Build Coastguard Worker       connected.add (start_idx);
1574*2d1272b8SAndroid Build Coastguard Worker     }
1575*2d1272b8SAndroid Build Coastguard Worker 
1576*2d1272b8SAndroid Build Coastguard Worker     const auto& v = vertices_[start_idx];
1577*2d1272b8SAndroid Build Coastguard Worker 
1578*2d1272b8SAndroid Build Coastguard Worker     // Graph is treated as undirected so search children and parents of start_idx
1579*2d1272b8SAndroid Build Coastguard Worker     for (const auto& l : v.obj.all_links ())
1580*2d1272b8SAndroid Build Coastguard Worker       find_connected_nodes (l.objidx, targets, visited, connected);
1581*2d1272b8SAndroid Build Coastguard Worker 
1582*2d1272b8SAndroid Build Coastguard Worker     for (unsigned p : v.parents_iter ())
1583*2d1272b8SAndroid Build Coastguard Worker       find_connected_nodes (p, targets, visited, connected);
1584*2d1272b8SAndroid Build Coastguard Worker   }
1585*2d1272b8SAndroid Build Coastguard Worker 
1586*2d1272b8SAndroid Build Coastguard Worker  public:
1587*2d1272b8SAndroid Build Coastguard Worker   // TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
1588*2d1272b8SAndroid Build Coastguard Worker   hb_vector_t<vertex_t> vertices_;
1589*2d1272b8SAndroid Build Coastguard Worker   hb_vector_t<vertex_t> vertices_scratch_;
1590*2d1272b8SAndroid Build Coastguard Worker  private:
1591*2d1272b8SAndroid Build Coastguard Worker   bool parents_invalid;
1592*2d1272b8SAndroid Build Coastguard Worker   bool distance_invalid;
1593*2d1272b8SAndroid Build Coastguard Worker   bool positions_invalid;
1594*2d1272b8SAndroid Build Coastguard Worker   bool successful;
1595*2d1272b8SAndroid Build Coastguard Worker   hb_vector_t<unsigned> num_roots_for_space_;
1596*2d1272b8SAndroid Build Coastguard Worker   hb_vector_t<char*> buffers;
1597*2d1272b8SAndroid Build Coastguard Worker };
1598*2d1272b8SAndroid Build Coastguard Worker 
1599*2d1272b8SAndroid Build Coastguard Worker }
1600*2d1272b8SAndroid Build Coastguard Worker 
1601*2d1272b8SAndroid Build Coastguard Worker #endif  // GRAPH_GRAPH_HH
1602