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