1use rustc_hash::FxHashMap;
2use super::layout_queue::LayoutQueue;
3use super::{
4 BringIntoViewRequest, EffectiveViewportChangedEventArgs, IBringIntoViewLayoutManager, ILayoutManager, ILayoutRoot,
5 Layoutable,
6};
7use crate::animation::TimeSpan;
8use crate::logging::{LogArea, LogEventLevel, Logger};
9use crate::media::MediaContext;
10use crate::rendering::LayoutPassTiming;
11use crate::threading::Dispatcher;
12use crate::utilities::HandlerList;
13use crate::{Matrix, Rect, Ref, Size, Visual};
14use std::any::Any;
15use std::cell::{Cell, RefCell};
16use std::rc::{Rc, Weak};
17use std::time::Duration;
18
19const MAX_PASSES: i32 = 10;
20
21struct EffectiveViewportChangedListener {
22 listener: Ref<Layoutable>,
23 viewport: Cell<Option<Rect>>,
24}
25
26#[derive(Clone, Copy, PartialEq, Eq)]
27enum ArrangeResult {
28 Arranged,
29 NotVisible,
30 AncestorMeasureInvalid,
31}
32
33pub struct LayoutManager {
35 this: Weak<LayoutManager>,
36 owner: Weak<dyn ILayoutRoot>,
37 to_measure: RefCell<LayoutQueue<Ref<Layoutable>>>,
38 to_arrange: RefCell<LayoutQueue<Ref<Layoutable>>>,
39 to_arrange_after_measure: RefCell<Vec<Ref<Layoutable>>>,
40 effective_viewport_changed_listeners: RefCell<Vec<Rc<EffectiveViewportChangedListener>>>,
41 effective_viewport_scratch: RefCell<(Vec<Rc<EffectiveViewportChangedListener>>, FxHashMap<usize, Rect>)>,
45 bring_into_view_requests: RefCell<Option<Vec<Rc<dyn BringIntoViewRequest>>>>,
46 disposed: Cell<bool>,
47 queued: Cell<bool>,
48 running: Cell<bool>,
49 processing_bring_into_view_requests: Cell<bool>,
50 total_pass_count: Cell<i32>,
51 layout_updated: HandlerList<dyn Fn()>,
52 layout_pass_timed: RefCell<Option<Rc<dyn Fn(LayoutPassTiming)>>>,
53}
54
55impl LayoutManager {
56 pub fn new(owner: Weak<dyn ILayoutRoot>) -> Rc<Self> {
58 Rc::new_cyclic(|this| Self {
59 this: this.clone(),
60 owner,
61 to_measure: RefCell::new(LayoutQueue::new(|v| !v.is_measure_valid())),
62 to_arrange: RefCell::new(LayoutQueue::new(|v| !v.is_arrange_valid())),
63 to_arrange_after_measure: RefCell::new(Vec::new()),
64 effective_viewport_changed_listeners: RefCell::new(Vec::new()),
65 effective_viewport_scratch: RefCell::new((Vec::new(), FxHashMap::default())),
66 bring_into_view_requests: RefCell::new(None),
67 disposed: Cell::new(false),
68 queued: Cell::new(false),
69 running: Cell::new(false),
70 processing_bring_into_view_requests: Cell::new(false),
71 total_pass_count: Cell::new(0),
72 layout_updated: HandlerList::new(),
73 layout_pass_timed: RefCell::new(None),
74 })
75 }
76
77 pub fn is_in_layout_pass(&self) -> bool {
79 self.running.get()
80 }
81
82 pub fn total_pass_count(&self) -> i32 {
84 self.total_pass_count.get()
85 }
86
87 pub fn layout_pass_timed(&self) -> Option<Rc<dyn Fn(LayoutPassTiming)>> {
90 self.layout_pass_timed.borrow().clone()
91 }
92
93 pub fn set_layout_pass_timed(&self, value: Option<Rc<dyn Fn(LayoutPassTiming)>>) {
95 *self.layout_pass_timed.borrow_mut() = value;
96 }
97
98 #[cfg(any(test, feature = "testing"))]
100 pub fn to_measure_count(&self) -> usize {
101 self.to_measure.borrow().count()
102 }
103
104 #[cfg(any(test, feature = "testing"))]
106 pub fn to_arrange_count(&self) -> usize {
107 self.to_arrange.borrow().count()
108 }
109
110 fn is_owned_root(&self, control: &Layoutable) -> bool {
111 match (control.get_layout_root(), self.owner.upgrade()) {
112 (Some(root), Some(owner)) => std::ptr::addr_eq(Rc::as_ptr(&root), Rc::as_ptr(&owner)),
113 _ => false,
114 }
115 }
116
117 fn is_root_visual(control: &Layoutable) -> bool {
118 control.get_layout_root().is_some_and(|root| {
119 let root_visual = root.root_visual();
120 std::ptr::eq(&*root_visual as *const Layoutable, control as *const Layoutable)
121 })
122 }
123
124 fn get_timestamp() -> i64 {
127 Dispatcher::current_dispatcher().now()
128 }
129
130 fn execute_queued_layout_pass(&self) {
131 if !self.queued.get() {
132 return;
133 }
134 self.execute_layout_pass();
135 }
136
137 fn process_bring_into_view_requests(&self) -> bool {
142 if self.processing_bring_into_view_requests.get()
143 || !self.bring_into_view_requests.borrow().as_ref().is_some_and(|requests| !requests.is_empty())
144 {
145 return false;
146 }
147
148 self.processing_bring_into_view_requests.set(true);
149 let _guard = RunningGuard(&self.processing_bring_into_view_requests);
150
151 let is_at = |requests: &Option<Vec<Rc<dyn BringIntoViewRequest>>>, i: usize, request: &Rc<dyn BringIntoViewRequest>| {
152 requests
153 .as_ref()
154 .and_then(|requests| requests.get(i))
155 .is_some_and(|current| std::ptr::addr_eq(Rc::as_ptr(current), Rc::as_ptr(request)))
156 };
157
158 let mut executed_any = false;
159 let mut i = 0;
160
161 loop {
162 let request = match self.bring_into_view_requests.borrow().as_ref().and_then(|requests| requests.get(i)) {
163 Some(request) => request.clone(),
164 None => break,
165 };
166
167 if !self.is_owned_root(&request.target()) {
169 let mut requests = self.bring_into_view_requests.borrow_mut();
170 if is_at(&requests, i, &request) {
171 if let Some(requests) = requests.as_mut() {
172 requests.remove(i);
173 }
174 }
175 continue;
176 }
177
178 let executed = request.try_execute();
179 executed_any |= executed;
180
181 let mut requests = self.bring_into_view_requests.borrow_mut();
184 if executed && is_at(&requests, i, &request) {
185 if let Some(requests) = requests.as_mut() {
186 requests.remove(i);
187 }
188 } else {
189 i += 1;
190 }
191 }
192
193 executed_any
194 }
195
196 fn inner_layout_pass(&self) {
197 for _ in 0..MAX_PASSES {
198 self.execute_measure_pass();
199 self.execute_arrange_pass();
200
201 if self.to_measure.borrow().count() == 0 {
202 break;
203 }
204 }
205 }
206
207 fn execute_measure_pass(&self) {
208 while self.to_measure.borrow().count() > 0 {
209 let control = self.to_measure.borrow_mut().dequeue();
210
211 if !control.is_measure_valid() {
212 Self::measure(&control);
213 }
214 self.to_arrange.borrow_mut().enqueue(control);
215 }
216 }
217
218 fn execute_arrange_pass(&self) {
219 while self.to_arrange.borrow().count() > 0 {
220 let control = self.to_arrange.borrow_mut().dequeue();
221
222 if !control.is_arrange_valid() && Self::arrange(&control) == ArrangeResult::AncestorMeasureInvalid {
223 self.to_arrange_after_measure.borrow_mut().push(control);
224 }
225 }
226
227 let pending = std::mem::take(&mut *self.to_arrange_after_measure.borrow_mut());
228 for control in pending {
229 self.invalidate_arrange(&control);
230 }
231 }
232
233 fn measure(control: &Layoutable) -> bool {
234 if !control.is_visible() || !control.is_attached_to_visual_tree() {
235 return false;
236 }
237
238 if let Some(parent) = control.visual_parent() {
244 if let Some(parent) = parent.downcast_ref::<Layoutable>() {
245 if !Self::measure(parent) {
246 return false;
247 }
248 }
249 }
250
251 if !control.is_measure_valid() {
255 if Self::is_root_visual(control) {
256 control.measure(Size::INFINITY);
257 } else if let Some(previous) = control.previous_measure() {
258 control.measure(previous);
259 }
260 }
261
262 true
263 }
264
265 fn arrange(control: &Layoutable) -> ArrangeResult {
266 if !control.is_visible() || !control.is_attached_to_visual_tree() {
267 return ArrangeResult::NotVisible;
268 }
269
270 if let Some(parent) = control.visual_parent() {
271 if let Some(parent) = parent.downcast_ref::<Layoutable>() {
272 let parent_result = Self::arrange(parent);
273 if parent_result != ArrangeResult::Arranged {
274 return parent_result;
275 }
276 }
277 }
278
279 if !control.is_measure_valid() {
280 return ArrangeResult::AncestorMeasureInvalid;
281 }
282
283 if !control.is_arrange_valid() {
284 if Self::is_root_visual(control) {
285 control.arrange(Rect::from_size(control.desired_size()));
286 } else if let Some(previous) = control.previous_arrange() {
287 control.arrange(previous);
288 }
289 }
290
291 ArrangeResult::Arranged
292 }
293
294 fn queue_layout_pass(&self) {
295 if !self.queued.get() && !self.running.get() {
296 self.queued.set(true);
297 let this = self.this.clone();
298 MediaContext::instance().begin_invoke_on_render(Rc::new(move || {
299 if let Some(this) = this.upgrade() {
300 this.execute_queued_layout_pass();
301 }
302 }));
303 }
304 }
305
306 fn raise_effective_viewport_changed(&self) -> bool {
307 let start_count = self.to_measure.borrow().count() + self.to_arrange.borrow().count();
308
309 let (mut listeners, mut ancestors) = std::mem::take(&mut *self.effective_viewport_scratch.borrow_mut());
313 let mut version = crate::visual::geometry_version();
314
315 listeners.extend(self.effective_viewport_changed_listeners.borrow().iter().cloned());
316 for l in &listeners {
317 if !l.listener.is_attached_to_visual_tree() {
318 continue;
319 }
320 let current = crate::visual::geometry_version();
321 if current != version {
322 ancestors.clear();
323 version = current;
324 }
325 let viewport = Self::calculate_effective_viewport_with(&l.listener, &mut ancestors);
326 if Some(viewport) != l.viewport.get() {
327 l.listener.raise_effective_viewport_changed(&EffectiveViewportChangedEventArgs::new(viewport));
328 l.viewport.set(Some(viewport));
329 }
330 }
331 listeners.clear();
332 ancestors.clear();
333 *self.effective_viewport_scratch.borrow_mut() = (listeners, ancestors);
334
335 start_count != self.to_measure.borrow().count() + self.to_arrange.borrow().count()
336 }
337
338 fn calculate_effective_viewport_with(control: &Visual, ancestors: &mut FxHashMap<usize, Rect>) -> Rect {
343 let viewport = match control.visual_parent() {
344 Some(parent) => Self::ancestor_viewport(&parent, ancestors),
345 None => Rect::from_size(control.bounds().size()),
346 };
347 viewport.translate((-control.bounds().position()).into())
349 }
350
351 fn ancestor_viewport(control: &Visual, ancestors: &mut FxHashMap<usize, Rect>) -> Rect {
354 let key = control as *const Visual as usize;
355 if let Some(viewport) = ancestors.get(&key) {
356 return *viewport;
357 }
358 let mut viewport = match control.visual_parent() {
359 Some(parent) => Self::ancestor_viewport(&parent, ancestors),
360 None => Rect::from_size(control.bounds().size()),
361 };
362 if control.clip_to_bounds() {
363 viewport = control.bounds().intersect(viewport);
364 }
365 viewport = viewport.translate((-control.bounds().position()).into());
366 if control.has_render_transform() {
367 if let Some(transform) = control.render_transform() {
368 match transform.value().try_invert() {
369 Some(inverted_matrix) => {
370 let origin = control.render_transform_origin().to_pixels(control.bounds().size());
371 let offset = Matrix::create_translation(origin.x, origin.y);
372 viewport = viewport.transform_to_aabb(-offset * inverted_matrix * offset);
373 }
374 None => viewport = Rect::default(),
375 }
376 }
377 }
378 ancestors.insert(key, viewport);
379 viewport
380 }
381}
382
383impl ILayoutManager for LayoutManager {
384 fn add_layout_updated(&self, handler: Rc<dyn Fn()>) -> u64 {
385 self.layout_updated.add(handler)
386 }
387
388 fn remove_layout_updated(&self, token: u64) {
389 self.layout_updated.remove(token);
390 }
391
392 fn invalidate_measure(&self, control: &Layoutable) {
393 Dispatcher::ui_thread().verify_access();
394
395 if self.disposed.get() {
396 return;
397 }
398 if !control.is_attached_to_visual_tree() {
399 debug_assert!(
400 false,
401 "LayoutManager.InvalidateMeasure called on a control that is detached from the visual tree."
402 );
403 return;
404 }
405 assert!(self.is_owned_root(control), "Attempt to call InvalidateMeasure on wrong LayoutManager.");
406
407 self.to_measure.borrow_mut().enqueue(control.to_ref());
408 self.queue_layout_pass();
409 }
410
411 fn invalidate_arrange(&self, control: &Layoutable) {
412 Dispatcher::ui_thread().verify_access();
413
414 if self.disposed.get() {
415 return;
416 }
417 if !control.is_attached_to_visual_tree() {
418 debug_assert!(
419 false,
420 "LayoutManager.InvalidateArrange called on a control that is detached from the visual tree."
421 );
422 return;
423 }
424 assert!(self.is_owned_root(control), "Attempt to call InvalidateArrange on wrong LayoutManager.");
425
426 self.to_arrange.borrow_mut().enqueue(control.to_ref());
427 self.queue_layout_pass();
428 }
429
430 fn execute_layout_pass(&self) {
431 Dispatcher::ui_thread().verify_access();
432
433 if self.disposed.get() {
434 return;
435 }
436
437 if !self.running.get() {
438 const TIMING_LOG_LEVEL: LogEventLevel = LogEventLevel::Information;
439 let capture_timing =
440 self.layout_pass_timed.borrow().is_some() || Logger::is_enabled(TIMING_LOG_LEVEL, LogArea::LAYOUT);
441 let mut starting_timestamp = 0;
442
443 if capture_timing {
444 if let Some(logger) = Logger::try_get(TIMING_LOG_LEVEL, LogArea::LAYOUT) {
445 logger.log_with_values(
446 Some(self as &dyn Any),
447 "Started layout pass. To measure: {Measure} To arrange: {Arrange}",
448 &[&self.to_measure.borrow().count(), &self.to_arrange.borrow().count()],
449 );
450 }
451
452 starting_timestamp = Self::get_timestamp();
453 }
454
455 self.to_measure.borrow_mut().begin_loop(MAX_PASSES);
456 self.to_arrange.borrow_mut().begin_loop(MAX_PASSES);
457
458 self.running.set(true);
459 {
460 let _guard = RunningGuard(&self.running);
461 self.total_pass_count.set(self.total_pass_count.get() + 1);
462
463 for _ in 0..MAX_PASSES {
464 self.inner_layout_pass();
465 if self.raise_effective_viewport_changed() {
466 continue;
467 }
468
469 if !self.process_bring_into_view_requests()
473 || (self.to_measure.borrow().count() == 0 && self.to_arrange.borrow().count() == 0)
474 {
475 break;
476 }
477 }
478 }
479
480 self.to_measure.borrow_mut().end_loop();
481 self.to_arrange.borrow_mut().end_loop();
482
483 if capture_timing {
484 let elapsed =
485 Duration::from_millis(Self::get_timestamp().saturating_sub(starting_timestamp).max(0) as u64);
486 let layout_pass_timed = self.layout_pass_timed.borrow().clone();
487 if let Some(layout_pass_timed) = layout_pass_timed {
488 layout_pass_timed(LayoutPassTiming::new(self.total_pass_count.get(), elapsed));
489 }
490
491 if let Some(logger) = Logger::try_get(TIMING_LOG_LEVEL, LogArea::LAYOUT) {
492 logger.log_with_values(
493 Some(self as &dyn Any),
494 "Layout pass finished in {Time}",
495 &[&TimeSpan::from(elapsed)],
496 );
497 }
498 }
499 } else if self.processing_bring_into_view_requests.get() {
500 for _ in 0..MAX_PASSES {
505 self.inner_layout_pass();
506
507 if !self.raise_effective_viewport_changed() {
508 break;
509 }
510 }
511
512 return;
513 }
514
515 self.queued.set(false);
516 if !self.layout_updated.is_empty() {
517 for (_, handler) in self.layout_updated.snapshot().iter() {
518 handler();
519 }
520 }
521 }
522
523 fn execute_initial_layout_pass(&self) {
524 if self.disposed.get() {
525 return;
526 }
527
528 let Some(owner) = self.owner.upgrade() else { return };
529 let root = owner.root_visual();
530
531 self.running.set(true);
532 {
533 let _guard = RunningGuard(&self.running);
534 Self::measure(&root);
535 Self::arrange(&root);
536 }
537
538 self.execute_layout_pass();
544 }
545
546 fn register_effective_viewport_listener(&self, control: &Layoutable) {
547 self.effective_viewport_changed_listeners
548 .borrow_mut()
549 .push(Rc::new(EffectiveViewportChangedListener { listener: control.to_ref(), viewport: Cell::new(None) }));
550 }
551
552 fn unregister_effective_viewport_listener(&self, control: &Layoutable) {
553 self.effective_viewport_changed_listeners
554 .borrow_mut()
555 .retain(|l| !std::ptr::eq(&*l.listener as *const Layoutable, control as *const Layoutable));
556 }
557
558 fn dispose(&self) {
559 self.disposed.set(true);
560 self.to_measure.borrow_mut().dispose();
561 self.to_arrange.borrow_mut().dispose();
562 *self.bring_into_view_requests.borrow_mut() = None;
563 }
564
565 fn as_bring_into_view_layout_manager(&self) -> Option<&dyn IBringIntoViewLayoutManager> {
566 Some(self)
567 }
568}
569
570impl IBringIntoViewLayoutManager for LayoutManager {
571 fn is_in_layout_pass(&self) -> bool {
572 LayoutManager::is_in_layout_pass(self)
573 }
574
575 fn enqueue_bring_into_view(&self, request: Rc<dyn BringIntoViewRequest>) {
576 Dispatcher::ui_thread().verify_access();
577
578 if self.disposed.get() {
579 return;
580 }
581
582 let target = request.target();
584 let pending: Vec<_> = self.bring_into_view_requests.borrow().clone().unwrap_or_default();
585 let existing = pending.iter().position(|existing| existing.target() == target);
586
587 {
588 let mut requests = self.bring_into_view_requests.borrow_mut();
589 let requests = requests.get_or_insert_with(Vec::new);
590
591 match existing.and_then(|i| requests.get_mut(i)) {
592 Some(existing) => *existing = request,
593 None => requests.push(request),
594 }
595 }
596
597 self.queue_layout_pass();
601 }
602}
603
604struct RunningGuard<'a>(&'a Cell<bool>);
605
606impl Drop for RunningGuard<'_> {
607 fn drop(&mut self) {
608 self.0.set(false);
609 }
610}