1use super::ICompositionHitTester;
2use crate::media::IntersectionResult;
3use crate::platform::LtrbRect;
4use crate::rendering::composition::{CompositionTarget, CompositionVisual, CompositionVisualCollection};
5use std::collections::HashMap;
6use std::rc::Rc;
7
8const NULL: i32 = -1;
9const ORDER_BUCKET_SIZE: i32 = 32;
10const FAT_BOUNDS_PADDING: f64 = 1.0;
11
12type VisualFilter<'a> = Option<&'a dyn Fn(&Rc<CompositionVisual>) -> bool>;
13
14#[derive(Clone, Copy, PartialEq, Eq)]
15enum BoundsState {
16 Empty,
17 Bounded,
18 Unbounded,
19}
20
21#[derive(Clone)]
22struct Node {
23 bounds: LtrbRect,
24 visual: Option<Rc<CompositionVisual>>,
25 parent: i32,
26 child1: i32,
27 child2: i32,
28 next: i32,
29 height: i32,
30 order: i32,
31 bucket: i32,
32}
33
34impl Node {
35 fn is_leaf(&self) -> bool {
36 self.child1 == NULL
37 }
38}
39
40struct Bucket {
41 root: i32,
42 unbounded: Option<Vec<Rc<CompositionVisual>>>,
43 readback_revision: u64,
44}
45
46impl Bucket {
47 fn new(root: i32) -> Self {
48 Self { root, unbounded: None, readback_revision: 0 }
49 }
50
51 fn is_empty(&self) -> bool {
52 self.root == NULL && self.unbounded.as_ref().is_none_or(Vec::is_empty)
53 }
54}
55
56#[derive(Clone, Copy)]
57struct Entry {
58 order: i32,
59 leaf: i32,
60 revision: u64,
61 is_unbounded: bool,
62}
63
64impl Entry {
65 fn new(order: i32) -> Self {
66 Self { order, leaf: NULL, revision: 0, is_unbounded: false }
67 }
68}
69
70struct Candidate {
71 visual: Rc<CompositionVisual>,
72 order: i32,
73}
74
75fn key(visual: &Rc<CompositionVisual>) -> *const CompositionVisual {
76 Rc::as_ptr(visual)
77}
78
79fn contains_rect(outer: &LtrbRect, rect: LtrbRect) -> bool {
80 rect.left >= outer.left && rect.right <= outer.right && rect.top >= outer.top && rect.bottom <= outer.bottom
81}
82
83pub struct CompositionHitTestAabbTree {
87 children: Rc<CompositionVisualCollection>,
88 entries: HashMap<*const CompositionVisual, Entry>,
89 buckets: Vec<Bucket>,
90 nodes: Vec<Node>,
91 free_list: i32,
92}
93
94impl CompositionHitTestAabbTree {
95 pub fn new(children: Rc<CompositionVisualCollection>) -> Self {
96 let mut tree = Self {
97 children: children.clone(),
98 entries: HashMap::new(),
99 buckets: Vec::new(),
100 nodes: Vec::new(),
101 free_list: NULL,
102 };
103 for (i, child) in children.items().iter().enumerate() {
104 tree.update(child, i as i32);
105 }
106 tree
107 }
108
109 pub fn clear(&mut self) {
110 self.entries.clear();
111 self.buckets.clear();
112 self.nodes.clear();
113 self.free_list = NULL;
114 }
115
116 pub fn update(&mut self, visual: &Rc<CompositionVisual>, order: i32) {
117 let mut entry = match self.entries.get(&key(visual)).copied() {
118 None => {
119 let bucket_index = Self::get_bucket_index(order);
120 self.get_or_create_bucket(bucket_index);
121 Entry::new(order)
122 }
123 Some(mut entry) => {
124 if entry.order != order {
125 self.update_order_core(visual, &mut entry, order);
126 }
127 entry
128 }
129 };
130
131 let (state, bounds, revision) = Self::get_bounds_state(visual);
132 self.update_bounds(visual, &mut entry, state, bounds, revision);
133 self.entries.insert(key(visual), entry);
134 }
135
136 pub fn remove(&mut self, visual: &Rc<CompositionVisual>) {
137 let Some(entry) = self.entries.remove(&key(visual)) else { return };
138
139 if entry.leaf != NULL {
140 self.destroy_leaf(entry.leaf);
141 } else if entry.is_unbounded {
142 self.remove_unbounded(visual, entry.order);
143 }
144
145 self.remove_bucket_if_empty(Self::get_bucket_index(entry.order));
146 }
147
148 pub fn update_order(&mut self, visual: &Rc<CompositionVisual>, order: i32) {
149 let Some(mut entry) = self.entries.get(&key(visual)).copied() else {
150 self.entries.insert(key(visual), Entry::new(order));
151 return;
152 };
153
154 if entry.order != order {
155 self.update_order_core(visual, &mut entry, order);
156 self.entries.insert(key(visual), entry);
157 }
158 }
159
160 fn update_order_core(&mut self, visual: &Rc<CompositionVisual>, entry: &mut Entry, order: i32) {
161 let old_order = entry.order;
162 let old_bucket = Self::get_bucket_index(old_order);
163 let new_bucket = Self::get_bucket_index(order);
164 entry.order = order;
165
166 if entry.leaf != NULL {
167 self.move_leaf(entry.leaf, order);
168 return;
169 }
170
171 if entry.is_unbounded {
172 self.move_unbounded(visual, old_order, order);
173 return;
174 }
175
176 if old_bucket != new_bucket {
177 self.remove_bucket_if_empty(old_bucket);
178 }
179 }
180
181 pub fn query<H: ICompositionHitTester>(
184 &mut self,
185 input: &H::Input,
186 results: &mut Vec<Rc<CompositionVisual>>,
187 readback_revision: u64,
188 ) {
189 let mut candidates: Vec<Candidate> = Vec::with_capacity(ORDER_BUCKET_SIZE as usize);
190 let mut stack: Vec<i32> = Vec::with_capacity(16);
191
192 for i in (0..self.buckets.len()).rev() {
193 self.update_bucket(i, readback_revision);
194 let Some(bucket) = self.buckets.get(i) else { continue };
196 if bucket.is_empty() {
197 continue;
198 }
199
200 candidates.clear();
201 stack.clear();
202 self.query_bucket::<H>(i, input, &mut candidates, &mut stack);
203 candidates.sort_by(|left, right| right.order.cmp(&left.order));
205
206 for candidate in candidates.drain(..) {
207 results.push(candidate.visual);
208 }
209 }
210 }
211
212 pub fn query_first<H: ICompositionHitTester>(
215 &mut self,
216 target: &CompositionTarget,
217 input: &H::Input,
218 filter: VisualFilter<'_>,
219 result_filter: VisualFilter<'_>,
220 readback_revision: u64,
221 ) -> (Option<Rc<CompositionVisual>>, IntersectionResult) {
222 let mut intersection_result = IntersectionResult::NotCalculated;
223 let mut candidates: Vec<Candidate> = Vec::with_capacity(ORDER_BUCKET_SIZE as usize);
224 let mut stack: Vec<i32> = Vec::with_capacity(16);
225
226 for i in (0..self.buckets.len()).rev() {
227 self.update_bucket(i, readback_revision);
228 let Some(bucket) = self.buckets.get(i) else { continue };
229 if bucket.is_empty() {
230 continue;
231 }
232
233 candidates.clear();
234 stack.clear();
235 self.query_bucket::<H>(i, input, &mut candidates, &mut stack);
236 candidates.sort_by(|left, right| right.order.cmp(&left.order));
237
238 for candidate in candidates.drain(..) {
239 let (hit, result) = target.hit_test_first_core::<H>(&candidate.visual, input, filter, result_filter);
240 intersection_result = result;
241 if hit.is_some() {
242 return (hit, intersection_result);
243 }
244 }
245 }
246
247 (None, intersection_result)
248 }
249
250 fn update_bucket(&mut self, bucket_index: usize, readback_revision: u64) {
251 if self.buckets[bucket_index].readback_revision == readback_revision {
252 return;
253 }
254
255 let children = self.children.items();
256 let end = children.len().min((bucket_index + 1) * ORDER_BUCKET_SIZE as usize);
257 for visual in children.iter().take(end).skip(bucket_index * ORDER_BUCKET_SIZE as usize) {
258 let Some(mut entry) = self.entries.get(&key(visual)).copied() else { continue };
259 let (state, bounds, revision) = Self::get_bounds_state(visual);
260 if entry.revision != revision {
261 self.update_bounds(visual, &mut entry, state, bounds, revision);
262 self.entries.insert(key(visual), entry);
263 }
264 }
265
266 if let Some(bucket) = self.buckets.get_mut(bucket_index) {
267 bucket.readback_revision = readback_revision;
268 }
269 }
270
271 fn update_bounds(
272 &mut self,
273 visual: &Rc<CompositionVisual>,
274 entry: &mut Entry,
275 state: BoundsState,
276 bounds: LtrbRect,
277 revision: u64,
278 ) {
279 entry.revision = revision;
280
281 if entry.leaf != NULL {
282 if state == BoundsState::Bounded {
283 self.update_leaf(entry.leaf, bounds, entry.order);
284 } else {
285 self.destroy_leaf(entry.leaf);
286 entry.leaf = NULL;
287 if state == BoundsState::Unbounded {
288 self.add_unbounded(visual, entry.order, entry);
289 }
290 }
291
292 return;
293 }
294
295 if entry.is_unbounded {
296 if state == BoundsState::Unbounded {
297 return;
298 }
299
300 self.remove_unbounded(visual, entry.order);
301 entry.is_unbounded = false;
302 if state == BoundsState::Bounded {
303 entry.leaf = self.create_leaf(visual, bounds, entry.order);
304 }
305
306 return;
307 }
308
309 if state == BoundsState::Bounded {
310 entry.leaf = self.create_leaf(visual, bounds, entry.order);
311 } else if state == BoundsState::Unbounded {
312 self.add_unbounded(visual, entry.order, entry);
313 }
314 }
315
316 fn query_bucket<H: ICompositionHitTester>(
317 &self,
318 bucket_index: usize,
319 input: &H::Input,
320 candidates: &mut Vec<Candidate>,
321 stack: &mut Vec<i32>,
322 ) {
323 let bucket = &self.buckets[bucket_index];
324 if bucket.root != NULL {
325 stack.push(bucket.root);
326 }
327
328 while let Some(node_index) = stack.pop() {
329 let node = &self.nodes[node_index as usize];
330 if !H::transformed_sub_tree_bounds_match(node.bounds, input) {
331 continue;
332 }
333
334 if node.is_leaf() {
335 if let Some(visual) = &node.visual {
336 candidates.push(Candidate { visual: visual.clone(), order: node.order });
337 }
338 } else {
339 if node.child1 != NULL {
340 stack.push(node.child1);
341 }
342 if node.child2 != NULL {
343 stack.push(node.child2);
344 }
345 }
346 }
347
348 if let Some(unbounded) = &bucket.unbounded {
349 for visual in unbounded {
350 if let Some(entry) = self.entries.get(&key(visual)) {
351 candidates.push(Candidate { visual: visual.clone(), order: entry.order });
352 }
353 }
354 }
355 }
356
357 fn get_bucket_index(order: i32) -> i32 {
358 order / ORDER_BUCKET_SIZE
359 }
360
361 fn get_or_create_bucket(&mut self, bucket_index: i32) -> &mut Bucket {
362 while self.buckets.len() as i32 <= bucket_index {
363 self.buckets.push(Bucket::new(NULL));
364 }
365 &mut self.buckets[bucket_index as usize]
366 }
367
368 fn remove_bucket_if_empty(&mut self, bucket_index: i32) {
369 if bucket_index >= self.buckets.len() as i32 {
370 return;
371 }
372
373 let children_count = self.children.count() as i32;
374 let last_required_bucket_index =
375 if children_count == 0 { NULL } else { Self::get_bucket_index(children_count - 1) };
376
377 let remove_trailing_bucket = {
378 let count = self.buckets.len() as i32;
379 let bucket = &mut self.buckets[bucket_index as usize];
380 if bucket.unbounded.as_ref().is_some_and(Vec::is_empty) {
381 bucket.unbounded = None;
382 }
383
384 bucket.is_empty() && bucket_index == count - 1 && bucket_index > last_required_bucket_index
385 };
386
387 if !remove_trailing_bucket {
388 return;
389 }
390
391 loop {
392 self.buckets.pop();
393 let count = self.buckets.len() as i32;
394 if !(count > 0 && count - 1 > last_required_bucket_index && self.buckets[(count - 1) as usize].is_empty()) {
395 break;
396 }
397 }
398 }
399
400 fn create_leaf(&mut self, visual: &Rc<CompositionVisual>, bounds: LtrbRect, order: i32) -> i32 {
401 let leaf = self.allocate_node();
402 {
403 let node = &mut self.nodes[leaf as usize];
404 node.bounds = Self::fatten(bounds);
405 node.visual = Some(visual.clone());
406 node.order = order;
407 node.bucket = Self::get_bucket_index(order);
408 node.height = 0;
409 }
410
411 self.insert_leaf(leaf);
412 leaf
413 }
414
415 fn destroy_leaf(&mut self, leaf: i32) {
416 self.remove_leaf(leaf);
417 self.free_node(leaf);
418 }
419
420 fn update_leaf(&mut self, leaf: i32, bounds: LtrbRect, order: i32) {
421 let bucket = Self::get_bucket_index(order);
422 {
423 let node = &mut self.nodes[leaf as usize];
424 if node.bucket == bucket && contains_rect(&node.bounds, bounds) {
426 node.order = order;
427 return;
428 }
429 }
430
431 self.remove_leaf(leaf);
432
433 {
434 let removed_node = &mut self.nodes[leaf as usize];
435 removed_node.bounds = Self::fatten(bounds);
436 removed_node.bucket = bucket;
437 removed_node.order = order;
438 }
439
440 self.insert_leaf(leaf);
441 }
442
443 fn move_leaf(&mut self, leaf: i32, order: i32) {
444 let bucket = Self::get_bucket_index(order);
445 {
446 let node = &mut self.nodes[leaf as usize];
447 if node.bucket == bucket {
448 node.order = order;
449 return;
450 }
451 }
452
453 self.remove_leaf(leaf);
454
455 {
456 let removed_node = &mut self.nodes[leaf as usize];
457 removed_node.order = order;
458 removed_node.bucket = bucket;
459 }
460
461 self.insert_leaf(leaf);
462 }
463
464 fn allocate_node(&mut self) -> i32 {
465 if self.free_list == NULL {
466 self.nodes.push(Node {
467 bounds: LtrbRect::default(),
468 visual: None,
469 parent: NULL,
470 child1: NULL,
471 child2: NULL,
472 next: NULL,
473 height: 0,
474 order: 0,
475 bucket: 0,
476 });
477 return self.nodes.len() as i32 - 1;
478 }
479
480 let index = self.free_list;
481 let node = &mut self.nodes[index as usize];
482 self.free_list = node.next;
483 node.parent = NULL;
484 node.child1 = NULL;
485 node.child2 = NULL;
486 node.next = NULL;
487 node.height = 0;
488 node.visual = None;
489 node.order = 0;
490 node.bucket = 0;
491 index
492 }
493
494 fn free_node(&mut self, index: i32) {
495 let node = &mut self.nodes[index as usize];
496 node.next = self.free_list;
497 node.parent = NULL;
498 node.child1 = NULL;
499 node.child2 = NULL;
500 node.height = -1;
501 node.visual = None;
502 node.order = 0;
503 node.bucket = 0;
504 self.free_list = index;
505 }
506
507 fn insert_leaf(&mut self, leaf: i32) {
508 let bucket_index = self.nodes[leaf as usize].bucket;
509 let root = self.get_or_create_bucket(bucket_index).root;
510 if root == NULL {
511 self.buckets[bucket_index as usize].root = leaf;
512 self.nodes[leaf as usize].parent = NULL;
513 return;
514 }
515
516 let leaf_bounds = self.nodes[leaf as usize].bounds;
517 let sibling = self.find_best_sibling(root, leaf_bounds);
518 let old_parent = self.nodes[sibling as usize].parent;
519 let new_parent = self.allocate_node();
520
521 let sibling_bounds = self.nodes[sibling as usize].bounds;
529 let sibling_height = self.nodes[sibling as usize].height;
530 {
531 let parent_node = &mut self.nodes[new_parent as usize];
532 parent_node.parent = old_parent;
533 parent_node.bounds = leaf_bounds.union(sibling_bounds);
534 parent_node.height = sibling_height + 1;
535 parent_node.child1 = sibling;
536 parent_node.child2 = leaf;
537 parent_node.visual = None;
538 parent_node.bucket = bucket_index;
539 }
540
541 self.nodes[sibling as usize].parent = new_parent;
542 self.nodes[leaf as usize].parent = new_parent;
543
544 if old_parent == NULL {
545 self.buckets[bucket_index as usize].root = new_parent;
546 } else {
547 let old_parent_node = &mut self.nodes[old_parent as usize];
548 if old_parent_node.child1 == sibling {
549 old_parent_node.child1 = new_parent;
550 } else {
551 old_parent_node.child2 = new_parent;
552 }
553 }
554
555 self.fix_ancestors(new_parent);
556 }
557
558 fn find_best_sibling(&self, root: i32, leaf_bounds: LtrbRect) -> i32 {
559 let mut index = root;
560 while !self.nodes[index as usize].is_leaf() {
561 let node = &self.nodes[index as usize];
562 let child1 = node.child1;
563 let child2 = node.child2;
564
565 let area = Self::perimeter(node.bounds);
566 let combined_area = Self::perimeter(node.bounds.union(leaf_bounds));
567 let cost = 2.0 * combined_area;
568 let inheritance_cost = 2.0 * (combined_area - area);
569
570 let cost1 = self.get_insertion_cost(child1, leaf_bounds, inheritance_cost);
571 let cost2 = self.get_insertion_cost(child2, leaf_bounds, inheritance_cost);
572
573 if cost < cost1 && cost < cost2 {
575 break;
576 }
577
578 index = if cost1 < cost2 { child1 } else { child2 };
579 }
580
581 index
582 }
583
584 fn get_insertion_cost(&self, node_index: i32, leaf_bounds: LtrbRect, inheritance_cost: f64) -> f64 {
585 let node = &self.nodes[node_index as usize];
586 let union = node.bounds.union(leaf_bounds);
587 if node.is_leaf() {
588 return Self::perimeter(union) + inheritance_cost;
589 }
590
591 Self::perimeter(union) - Self::perimeter(node.bounds) + inheritance_cost
592 }
593
594 fn remove_leaf(&mut self, leaf: i32) {
595 let bucket_index = self.nodes[leaf as usize].bucket;
596 let removed_root = {
597 let bucket = &mut self.buckets[bucket_index as usize];
598 if leaf == bucket.root {
599 bucket.root = NULL;
600 true
601 } else {
602 false
603 }
604 };
605
606 if removed_root {
607 self.remove_bucket_if_empty(bucket_index);
608 return;
609 }
610
611 let parent = self.nodes[leaf as usize].parent;
612 let (grand_parent, sibling) = {
613 let parent_node = &self.nodes[parent as usize];
614 (parent_node.parent, if parent_node.child1 == leaf { parent_node.child2 } else { parent_node.child1 })
615 };
616
617 if grand_parent != NULL {
619 {
625 let grand_parent_node = &mut self.nodes[grand_parent as usize];
626 if grand_parent_node.child1 == parent {
627 grand_parent_node.child1 = sibling;
628 } else {
629 grand_parent_node.child2 = sibling;
630 }
631 }
632
633 self.nodes[sibling as usize].parent = grand_parent;
634 self.free_node(parent);
635 self.fix_ancestors(grand_parent);
636 } else {
637 self.buckets[bucket_index as usize].root = sibling;
643 self.nodes[sibling as usize].parent = NULL;
644 self.free_node(parent);
645 }
646
647 self.nodes[leaf as usize].parent = NULL;
648
649 self.remove_bucket_if_empty(bucket_index);
650 }
651
652 fn fix_ancestors(&mut self, mut index: i32) {
653 while index != NULL {
654 index = self.balance(index);
655
656 let (child1, child2) = {
657 let node = &self.nodes[index as usize];
658 (node.child1, node.child2)
659 };
660 let (bounds1, height1) = {
661 let child = &self.nodes[child1 as usize];
662 (child.bounds, child.height)
663 };
664 let (bounds2, height2) = {
665 let child = &self.nodes[child2 as usize];
666 (child.bounds, child.height)
667 };
668
669 let node = &mut self.nodes[index as usize];
670 node.bounds = bounds1.union(bounds2);
672 node.height = 1 + height1.max(height2);
673 index = node.parent;
674 }
675 }
676
677 fn balance(&mut self, index_a: i32) -> i32 {
678 let (is_leaf, height, index_b, index_c) = {
679 let a = &self.nodes[index_a as usize];
680 (a.is_leaf(), a.height, a.child1, a.child2)
681 };
682 if is_leaf || height < 2 {
683 return index_a;
684 }
685
686 let balance = self.nodes[index_c as usize].height - self.nodes[index_b as usize].height;
687
688 if balance > 1 {
690 return self.rotate_c_up(index_a, index_b, index_c);
691 }
692
693 if balance < -1 {
695 return self.rotate_b_up(index_a, index_b, index_c);
696 }
697
698 index_a
699 }
700
701 fn bounds_and_height(&self, index: i32) -> (LtrbRect, i32) {
702 let node = &self.nodes[index as usize];
703 (node.bounds, node.height)
704 }
705
706 fn rotate_c_up(&mut self, index_a: i32, index_b: i32, index_c: i32) -> i32 {
707 let index_f = self.nodes[index_c as usize].child1;
721 let index_g = self.nodes[index_c as usize].child2;
722 let a_parent = self.nodes[index_a as usize].parent;
723
724 self.nodes[index_c as usize].child1 = index_a;
725 self.nodes[index_c as usize].parent = a_parent;
726 self.nodes[index_a as usize].parent = index_c;
727
728 self.replace_parent_child(index_a, index_c, a_parent);
730
731 let (f_bounds, f_height) = self.bounds_and_height(index_f);
732 let (g_bounds, g_height) = self.bounds_and_height(index_g);
733 let (b_bounds, b_height) = self.bounds_and_height(index_b);
734
735 if f_height > g_height {
737 self.nodes[index_c as usize].child2 = index_f;
738 self.nodes[index_a as usize].child2 = index_g;
739 self.nodes[index_g as usize].parent = index_a;
740
741 let a_bounds = b_bounds.union(g_bounds);
742 let a_height = 1 + b_height.max(g_height);
743 self.nodes[index_a as usize].bounds = a_bounds;
744 self.nodes[index_c as usize].bounds = a_bounds.union(f_bounds);
745 self.nodes[index_a as usize].height = a_height;
746 self.nodes[index_c as usize].height = 1 + a_height.max(f_height);
747 } else {
748 self.nodes[index_c as usize].child2 = index_g;
749 self.nodes[index_a as usize].child2 = index_f;
750 self.nodes[index_f as usize].parent = index_a;
751
752 let a_bounds = b_bounds.union(f_bounds);
753 let a_height = 1 + b_height.max(f_height);
754 self.nodes[index_a as usize].bounds = a_bounds;
755 self.nodes[index_c as usize].bounds = a_bounds.union(g_bounds);
756 self.nodes[index_a as usize].height = a_height;
757 self.nodes[index_c as usize].height = 1 + a_height.max(g_height);
758 }
759
760 index_c
761 }
762
763 fn rotate_b_up(&mut self, index_a: i32, index_b: i32, index_c: i32) -> i32 {
764 let index_d = self.nodes[index_b as usize].child1;
778 let index_e = self.nodes[index_b as usize].child2;
779 let a_parent = self.nodes[index_a as usize].parent;
780
781 self.nodes[index_b as usize].child1 = index_a;
782 self.nodes[index_b as usize].parent = a_parent;
783 self.nodes[index_a as usize].parent = index_b;
784
785 self.replace_parent_child(index_a, index_b, a_parent);
787
788 let (d_bounds, d_height) = self.bounds_and_height(index_d);
789 let (e_bounds, e_height) = self.bounds_and_height(index_e);
790 let (c_bounds, c_height) = self.bounds_and_height(index_c);
791
792 if d_height > e_height {
794 self.nodes[index_b as usize].child2 = index_d;
795 self.nodes[index_a as usize].child1 = index_e;
796 self.nodes[index_e as usize].parent = index_a;
797
798 let a_bounds = c_bounds.union(e_bounds);
799 let a_height = 1 + c_height.max(e_height);
800 self.nodes[index_a as usize].bounds = a_bounds;
801 self.nodes[index_b as usize].bounds = a_bounds.union(d_bounds);
802 self.nodes[index_a as usize].height = a_height;
803 self.nodes[index_b as usize].height = 1 + a_height.max(d_height);
804 } else {
805 self.nodes[index_b as usize].child2 = index_e;
806 self.nodes[index_a as usize].child1 = index_d;
807 self.nodes[index_d as usize].parent = index_a;
808
809 let a_bounds = c_bounds.union(d_bounds);
810 let a_height = 1 + c_height.max(d_height);
811 self.nodes[index_a as usize].bounds = a_bounds;
812 self.nodes[index_b as usize].bounds = a_bounds.union(e_bounds);
813 self.nodes[index_a as usize].height = a_height;
814 self.nodes[index_b as usize].height = 1 + a_height.max(e_height);
815 }
816
817 index_b
818 }
819
820 fn replace_parent_child(&mut self, old_child: i32, new_child: i32, parent: i32) {
821 if parent == NULL {
822 let bucket = self.nodes[new_child as usize].bucket;
823 self.buckets[bucket as usize].root = new_child;
824 return;
825 }
826
827 let parent_node = &mut self.nodes[parent as usize];
828 if parent_node.child1 == old_child {
829 parent_node.child1 = new_child;
830 } else {
831 parent_node.child2 = new_child;
832 }
833 }
834
835 fn add_unbounded(&mut self, visual: &Rc<CompositionVisual>, order: i32, entry: &mut Entry) {
836 let bucket_index = Self::get_bucket_index(order);
837 let bucket = self.get_or_create_bucket(bucket_index);
838 bucket.unbounded.get_or_insert_with(Vec::new).push(visual.clone());
839 entry.is_unbounded = true;
840 }
841
842 fn move_unbounded(&mut self, visual: &Rc<CompositionVisual>, old_order: i32, order: i32) {
843 let old_bucket_index = Self::get_bucket_index(old_order);
844 let new_bucket_index = Self::get_bucket_index(order);
845 if old_bucket_index == new_bucket_index {
846 return;
847 }
848
849 self.remove_unbounded(visual, old_order);
850 let new_bucket = self.get_or_create_bucket(new_bucket_index);
851 new_bucket.unbounded.get_or_insert_with(Vec::new).push(visual.clone());
852 }
853
854 fn remove_unbounded(&mut self, visual: &Rc<CompositionVisual>, order: i32) {
855 let bucket_index = Self::get_bucket_index(order);
856 if let Some(unbounded) = self.buckets.get_mut(bucket_index as usize).and_then(|b| b.unbounded.as_mut()) {
857 if let Some(index) = unbounded.iter().position(|v| Rc::ptr_eq(v, visual)) {
858 unbounded.remove(index);
859 }
860 }
861
862 self.remove_bucket_if_empty(bucket_index);
863 }
864
865 fn get_bounds_state(visual: &Rc<CompositionVisual>) -> (BoundsState, LtrbRect, u64) {
866 let Some(readback) = visual.try_get_valid_readback() else {
867 return (BoundsState::Empty, LtrbRect::default(), 0);
868 };
869
870 let revision = readback.revision;
871 if visual.disable_sub_tree_bounds_hit_test_optimization() {
872 return (BoundsState::Unbounded, LtrbRect::default(), revision);
873 }
874
875 match readback.transformed_subtree_bounds {
876 Some(subtree_bounds) if !subtree_bounds.is_zero_size() => (BoundsState::Bounded, subtree_bounds, revision),
877 _ => (BoundsState::Empty, LtrbRect::default(), revision),
878 }
879 }
880
881 fn fatten(bounds: LtrbRect) -> LtrbRect {
883 LtrbRect::new(
884 bounds.left - FAT_BOUNDS_PADDING,
885 bounds.top - FAT_BOUNDS_PADDING,
886 bounds.right + FAT_BOUNDS_PADDING,
887 bounds.bottom + FAT_BOUNDS_PADDING,
888 )
889 }
890
891 fn perimeter(bounds: LtrbRect) -> f64 {
892 2.0 * (bounds.width() + bounds.height())
893 }
894
895 #[cfg(test)]
897 pub(crate) fn bucket_count(&self) -> usize {
898 self.buckets.len()
899 }
900
901 #[cfg(test)]
903 pub(crate) fn validate(&self) {
904 for (bucket_index, bucket) in self.buckets.iter().enumerate() {
905 if bucket.root != NULL {
906 assert_eq!(self.nodes[bucket.root as usize].parent, NULL);
907 self.validate_node(bucket.root, bucket_index as i32);
908 }
909 }
910 }
911
912 #[cfg(test)]
913 fn validate_node(&self, index: i32, bucket: i32) -> i32 {
914 let node = &self.nodes[index as usize];
915 assert_eq!(node.bucket, bucket);
916 if node.is_leaf() {
917 assert!(node.visual.is_some());
918 assert_eq!(node.height, 0);
919 return 0;
920 }
921 let (c1, c2) = (&self.nodes[node.child1 as usize], &self.nodes[node.child2 as usize]);
922 assert_eq!(c1.parent, index);
923 assert_eq!(c2.parent, index);
924 assert!(contains_rect(&node.bounds, c1.bounds) && contains_rect(&node.bounds, c2.bounds));
925 let height = 1 + self.validate_node(node.child1, bucket).max(self.validate_node(node.child2, bucket));
926 assert_eq!(node.height, height);
927 height
928 }
929}