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