1use std::rc::Rc;
6
7use inset_foundation::{App, Handle, Listener, ValueChanged};
8
9use crate::layer::ErasedLayer;
10use crate::object::AnyRenderObject;
11use crate::painting_context::PaintingContext;
12
13pub trait PipelineManifold {
31 fn request_visual_update(&self, app: &mut App);
49}
50
51pub type FlushedPaintCallback = ValueChanged<bool>;
57
58pub struct PipelineOwner {
62 on_need_visual_update: Option<Listener>,
63 on_flushed_paint: Option<FlushedPaintCallback>,
68 manifold: Option<Rc<dyn PipelineManifold>>,
69 root_node: Option<AnyRenderObject>,
70 nodes_needing_layout: Vec<AnyRenderObject>,
71 nodes_needing_compositing_bits_update: Vec<AnyRenderObject>,
72 should_merge_dirty_nodes: bool,
73 debug_allow_mutations_to_dirty_subtrees: bool,
75 debug_doing_layout: bool,
76 debug_doing_child_layout: bool,
77 nodes_needing_paint: Vec<AnyRenderObject>,
78 debug_doing_paint: bool,
79 children: Vec<Handle<PipelineOwner>>,
80 debug_parent: Option<Handle<PipelineOwner>>,
81}
82
83impl PipelineOwner {
84 pub fn new(
89 app: &mut App,
90 on_need_visual_update: Option<Listener>,
91 on_flushed_paint: Option<FlushedPaintCallback>,
92 ) -> Handle<PipelineOwner> {
93 app.create(PipelineOwner {
94 on_need_visual_update,
95 on_flushed_paint,
96 manifold: None,
97 root_node: None,
98 nodes_needing_layout: Vec::new(),
99 nodes_needing_compositing_bits_update: Vec::new(),
100 should_merge_dirty_nodes: false,
101 debug_allow_mutations_to_dirty_subtrees: false,
102 debug_doing_layout: false,
103 debug_doing_child_layout: false,
104 nodes_needing_paint: Vec::new(),
105 debug_doing_paint: false,
106 children: Vec::new(),
107 debug_parent: None,
108 })
109 }
110
111 pub fn request_visual_update(self: Handle<Self>, app: &mut App) {
117 if let Some(callback) = app.get(self).on_need_visual_update.clone() {
118 callback.call(app);
119 } else if let Some(manifold) = app.get(self).manifold.clone() {
120 manifold.request_visual_update(app);
121 }
122 }
123
124 pub fn root_node(self: Handle<Self>, app: &App) -> Option<AnyRenderObject> {
126 app.get(self).root_node
127 }
128
129 pub fn set_root_node(self: Handle<Self>, app: &mut App, value: Option<AnyRenderObject>) {
131 let current = app.get(self).root_node;
132 if current == value {
133 return;
134 }
135 if let Some(old) = current {
136 old.detach(app);
137 }
138 app.get_mut(self).root_node = value;
139 if let Some(new) = value {
140 new.attach(app, self);
141 }
142 }
143
144 pub fn nodes_needing_layout(self: Handle<Self>, app: &App) -> Vec<AnyRenderObject> {
147 app.get(self).nodes_needing_layout.clone()
148 }
149
150 pub(crate) fn add_node_needing_layout(
151 self: Handle<Self>,
152 app: &mut App,
153 node: AnyRenderObject,
154 ) {
155 app.get_mut(self).nodes_needing_layout.push(node);
156 }
157
158 pub(crate) fn add_node_needing_compositing_bits_update(
159 self: Handle<Self>,
160 app: &mut App,
161 node: AnyRenderObject,
162 ) {
163 app.get_mut(self)
164 .nodes_needing_compositing_bits_update
165 .push(node);
166 }
167
168 pub(crate) fn remove_node_needing_paint(
169 self: Handle<Self>,
170 app: &mut App,
171 node: AnyRenderObject,
172 ) {
173 app.get_mut(self)
174 .nodes_needing_paint
175 .retain(|candidate| *candidate != node);
176 }
177
178 pub fn debug_doing_layout(self: Handle<Self>, app: &App) -> bool {
182 if !cfg!(debug_assertions) {
183 return false;
184 }
185 app.get(self).debug_doing_layout
186 }
187
188 pub(crate) fn enable_mutations_to_dirty_subtrees(
192 self: Handle<Self>,
193 app: &mut App,
194 callback: impl FnOnce(&mut App),
195 ) {
196 debug_assert!(app.get(self).debug_doing_layout);
197 let old_state = app.get(self).debug_allow_mutations_to_dirty_subtrees;
198 if cfg!(debug_assertions) {
199 app.get_mut(self).debug_allow_mutations_to_dirty_subtrees = true;
200 }
201 callback(app);
202 app.get_mut(self).should_merge_dirty_nodes = true;
203 if cfg!(debug_assertions) {
204 app.get_mut(self).debug_allow_mutations_to_dirty_subtrees = old_state;
205 }
206 }
207
208 pub fn flush_layout(self: Handle<Self>, app: &mut App) {
210 if cfg!(debug_assertions) {
211 app.get_mut(self).debug_doing_layout = true;
212 }
213 while !app.get(self).nodes_needing_layout.is_empty() {
214 debug_assert!(!app.get(self).should_merge_dirty_nodes);
215 let mut dirty_nodes = std::mem::take(&mut app.get_mut(self).nodes_needing_layout);
216 dirty_nodes.sort_by_key(|node| node.depth(app));
217 let mut i = 0;
218 while i < dirty_nodes.len() {
219 if app.get(self).should_merge_dirty_nodes {
220 app.get_mut(self).should_merge_dirty_nodes = false;
221 if !app.get(self).nodes_needing_layout.is_empty() {
222 app.get_mut(self)
223 .nodes_needing_layout
224 .extend(dirty_nodes.drain(i..));
225 break;
226 }
227 }
228 let node = dirty_nodes[i];
229 if node.needs_layout(app) && node.owner(app) == Some(self) {
230 node.layout_without_resize(app);
231 }
232 i += 1;
233 }
234 app.get_mut(self).should_merge_dirty_nodes = false;
235 }
236 if cfg!(debug_assertions) {
237 app.get_mut(self).debug_doing_child_layout = true;
238 }
239 let children = app.get(self).children.clone();
240 for child in children {
241 child.flush_layout(app);
242 }
243 debug_assert!(
244 app.get(self).nodes_needing_layout.is_empty(),
245 "Child PipelineOwners must not dirty nodes in their parent."
246 );
247 app.get_mut(self).should_merge_dirty_nodes = false;
248 if cfg!(debug_assertions) {
249 app.get_mut(self).debug_doing_layout = false;
250 app.get_mut(self).debug_doing_child_layout = false;
251 }
252 }
253
254 pub fn flush_compositing_bits(self: Handle<Self>, app: &mut App) {
259 let mut dirty_nodes =
260 std::mem::take(&mut app.get_mut(self).nodes_needing_compositing_bits_update);
261 dirty_nodes.sort_by_key(|node| node.depth(app));
262 for node in dirty_nodes {
263 if node.needs_compositing_bits_update(app) && node.owner(app) == Some(self) {
264 node.update_compositing_bits(app);
265 }
266 }
267 let children = app.get(self).children.clone();
268 for child in children {
269 child.flush_compositing_bits(app);
270 }
271 debug_assert!(
272 app.get(self)
273 .nodes_needing_compositing_bits_update
274 .is_empty(),
275 "Child PipelineOwners must not dirty nodes in their parent."
276 );
277 }
278
279 pub fn nodes_needing_paint(self: Handle<Self>, app: &App) -> Vec<AnyRenderObject> {
282 app.get(self).nodes_needing_paint.clone()
283 }
284
285 pub(crate) fn add_node_needing_paint(self: Handle<Self>, app: &mut App, node: AnyRenderObject) {
286 app.get_mut(self).nodes_needing_paint.push(node);
287 }
288
289 pub fn debug_doing_paint(self: Handle<Self>, app: &App) -> bool {
293 app.get(self).debug_doing_paint
294 }
295
296 pub fn flush_paint(self: Handle<Self>, app: &mut App) {
305 if cfg!(debug_assertions) {
306 app.get_mut(self).debug_doing_paint = true;
307 }
308 let is_dirty = self.paint_dirty_nodes(app);
309 let children = app.get(self).children.clone();
310 for child in children {
311 child.flush_paint(app);
312 }
313 self.did_flush_paint(app, is_dirty);
314 debug_assert!(
315 app.get(self).nodes_needing_paint.is_empty(),
316 "Child PipelineOwners must not dirty nodes in their parent."
317 );
318 if cfg!(debug_assertions) {
319 app.get_mut(self).debug_doing_paint = false;
320 }
321 }
322
323 pub fn flush_paint_without_children(self: Handle<Self>, app: &mut App) {
326 if cfg!(debug_assertions) {
327 app.get_mut(self).debug_doing_paint = true;
328 }
329 let is_dirty = self.paint_dirty_nodes(app);
330 self.did_flush_paint(app, is_dirty);
331 if cfg!(debug_assertions) {
332 app.get_mut(self).debug_doing_paint = false;
333 }
334 }
335
336 fn did_flush_paint(self: Handle<Self>, app: &mut App, is_dirty: bool) {
338 if let Some(on_flushed_paint) = app.get(self).on_flushed_paint.clone() {
339 on_flushed_paint(app, is_dirty);
340 }
341 }
342
343 fn paint_dirty_nodes(self: Handle<Self>, app: &mut App) -> bool {
346 let mut dirty_nodes = std::mem::take(&mut app.get_mut(self).nodes_needing_paint);
347 let is_dirty = !dirty_nodes.is_empty();
348 dirty_nodes.sort_by_key(|node| std::cmp::Reverse(node.depth(app)));
349 for node in dirty_nodes {
350 debug_assert!(node.layer(app).is_some() || !cfg!(debug_assertions));
351 if (node.needs_paint(app) || node.needs_composited_layer_update(app))
352 && node.owner(app) == Some(self)
353 {
354 if node
355 .layer(app)
356 .is_some_and(|layer| layer.as_layer().attached(app))
357 {
358 debug_assert!(node.is_repaint_boundary(app));
359 if node.needs_paint(app) {
360 PaintingContext::repaint_composited_child(app, node);
361 } else {
362 PaintingContext::update_layer_properties(app, node);
363 }
364 } else {
365 node.skipped_painting_on_layer(app);
366 }
367 }
368 }
369 is_dirty
370 }
371
372 pub fn attach(self: Handle<Self>, app: &mut App, manifold: Rc<dyn PipelineManifold>) {
378 debug_assert!(app.get(self).manifold.is_none());
379 app.get_mut(self).manifold = Some(Rc::clone(&manifold));
380 let children = app.get(self).children.clone();
381 for child in children {
382 child.attach(app, Rc::clone(&manifold));
383 }
384 }
385
386 pub fn detach(self: Handle<Self>, app: &mut App) {
392 debug_assert!(app.get(self).manifold.is_some());
393 app.get_mut(self).manifold = None;
394 let children = app.get(self).children.clone();
395 for child in children {
396 child.detach(app);
397 }
398 }
399
400 pub fn adopt_child(self: Handle<Self>, app: &mut App, child: Handle<PipelineOwner>) {
402 debug_assert!(app.get(child).debug_parent.is_none());
403 debug_assert!(!app.get(self).children.contains(&child));
404 debug_assert!(
405 !app.get(self).debug_doing_child_layout,
406 "Cannot modify child list after layout."
407 );
408 app.get_mut(self).children.push(child);
409 if cfg!(debug_assertions) {
410 app.get_mut(child).debug_parent = Some(self);
411 }
412 if let Some(manifold) = app.get(self).manifold.clone() {
413 child.attach(app, manifold);
414 }
415 }
416
417 pub fn drop_child(self: Handle<Self>, app: &mut App, child: Handle<PipelineOwner>) {
420 debug_assert_eq!(app.get(child).debug_parent, Some(self));
421 debug_assert!(app.get(self).children.contains(&child));
422 debug_assert!(
423 !app.get(self).debug_doing_child_layout,
424 "Cannot modify child list after layout."
425 );
426 let children = &mut app.get_mut(self).children;
427 let index = children
428 .iter()
429 .position(|&candidate| candidate == child)
430 .expect("child was in the list");
431 children.remove(index);
432 if cfg!(debug_assertions) {
433 app.get_mut(child).debug_parent = None;
434 }
435 if app.get(self).manifold.is_some() {
436 child.detach(app);
437 }
438 }
439
440 pub fn visit_children(
442 self: Handle<Self>,
443 app: &App,
444 visitor: &mut dyn FnMut(Handle<PipelineOwner>),
445 ) {
446 for child in &app.get(self).children {
447 visitor(*child);
448 }
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use std::cell::{Cell, RefCell};
455 use std::rc::Rc;
456
457 use inset_embedder::Size;
458 use inset_foundation::{App, AppCell};
459
460 use super::*;
461 use crate::box_::{RenderBox, RenderBoxData};
462 use crate::object::{RenderHandle, RenderObject, RenderObjectData};
463
464 struct TestLeaf {
465 render_object: RenderObjectData,
466 render_box: RenderBoxData,
467 on_layout: Option<Rc<dyn Fn()>>,
468 }
469
470 impl RenderObject for TestLeaf {
471 crate::render_object_accessors!();
472
473 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
474 if let Some(on_layout) = self.get(app).on_layout.clone() {
475 on_layout();
476 }
477 let size = self
478 .render_box_data(app)
479 .constraints
480 .map(crate::box_::BoxConstraints::smallest)
481 .unwrap_or(Size::ZERO);
482 self.set_size(app, size);
483 }
484 }
485
486 impl RenderBox for TestLeaf {
487 crate::render_box_accessors!();
488 }
489
490 fn leaf(on_layout: Option<Rc<dyn Fn()>>) -> TestLeaf {
491 TestLeaf {
492 render_object: RenderObjectData::new(),
493 render_box: RenderBoxData::new(),
494 on_layout,
495 }
496 }
497
498 #[test]
501 fn parent_pipeline_lays_out_before_child_pipeline() {
502 let cell = AppCell::new();
503 let mut app = cell.borrow_mut();
504 let log = Rc::new(RefCell::new(Vec::new()));
505
506 let root_log = Rc::clone(&log);
507 let root_node = RenderHandle::new_box(
508 &mut app,
509 leaf(Some(Rc::new(move || {
510 root_log.borrow_mut().push("layout parent")
511 }))),
512 );
513 let root = PipelineOwner::new(&mut app, None, None);
514 root.set_root_node(&mut app, Some(root_node.as_object()));
515 root_node.schedule_initial_layout(&mut app);
516
517 let child_log = Rc::clone(&log);
518 let child_node = RenderHandle::new_box(
519 &mut app,
520 leaf(Some(Rc::new(move || {
521 child_log.borrow_mut().push("layout child")
522 }))),
523 );
524 let child = PipelineOwner::new(&mut app, None, None);
525 child.set_root_node(&mut app, Some(child_node.as_object()));
526 child_node.schedule_initial_layout(&mut app);
527
528 root.adopt_child(&mut app, child);
529 root.flush_layout(&mut app);
530 assert_eq!(*log.borrow(), ["layout parent", "layout child"]);
531 }
532
533 #[test]
534 fn set_root_node_attaches_and_replacing_detaches() {
535 let cell = AppCell::new();
536 let mut app = cell.borrow_mut();
537 let owner = PipelineOwner::new(&mut app, None, None);
538 let first = RenderHandle::new_box(&mut app, leaf(None));
539 let second = RenderHandle::new_box(&mut app, leaf(None));
540 owner.set_root_node(&mut app, Some(first.as_object()));
541 assert!(first.attached(&app));
542 assert_eq!(first.owner(&app), Some(owner));
543
544 owner.set_root_node(&mut app, Some(second.as_object()));
545 assert!(!first.attached(&app));
546 assert!(second.attached(&app));
547 }
548
549 #[test]
550 fn schedule_initial_layout_then_flush() {
551 let cell = AppCell::new();
552 let mut app = cell.borrow_mut();
553 let owner = PipelineOwner::new(&mut app, None, None);
554 let node = RenderHandle::new_box(&mut app, leaf(None));
555 owner.set_root_node(&mut app, Some(node.as_object()));
556 node.schedule_initial_layout(&mut app);
557 assert!(node.debug_needs_layout(&app));
558 owner.flush_layout(&mut app);
559 assert!(!node.debug_needs_layout(&app));
560 assert_eq!(node.size(&app), Size::ZERO);
561 }
562
563 struct CountingManifold {
565 requests: Cell<u32>,
566 }
567
568 impl PipelineManifold for CountingManifold {
569 fn request_visual_update(&self, _app: &mut App) {
570 self.requests.set(self.requests.get() + 1);
571 }
572 }
573
574 #[test]
575 fn an_owner_without_a_callback_requests_visual_updates_through_its_manifold() {
576 let cell = AppCell::new();
577 let mut app = cell.borrow_mut();
578 let manifold = Rc::new(CountingManifold {
579 requests: Cell::new(0),
580 });
581 let root = PipelineOwner::new(&mut app, None, None);
582 let adopted_before = PipelineOwner::new(&mut app, None, None);
583 root.adopt_child(&mut app, adopted_before);
584
585 adopted_before.request_visual_update(&mut app);
586 assert_eq!(
587 manifold.requests.get(),
588 0,
589 "unattached owners request nothing"
590 );
591
592 root.attach(&mut app, manifold.clone());
593 root.request_visual_update(&mut app);
594 adopted_before.request_visual_update(&mut app);
595 assert_eq!(
596 manifold.requests.get(),
597 2,
598 "attach reaches existing children"
599 );
600
601 let adopted_after = PipelineOwner::new(&mut app, None, None);
602 root.adopt_child(&mut app, adopted_after);
603 adopted_after.request_visual_update(&mut app);
604 assert_eq!(manifold.requests.get(), 3, "adopt_child attaches the child");
605
606 root.drop_child(&mut app, adopted_after);
607 adopted_after.request_visual_update(&mut app);
608 assert_eq!(manifold.requests.get(), 3, "drop_child detaches the child");
609
610 root.detach(&mut app);
611 adopted_before.request_visual_update(&mut app);
612 assert_eq!(manifold.requests.get(), 3, "detach reaches the children");
613 }
614
615 #[test]
616 fn a_callback_takes_precedence_over_the_manifold() {
617 let cell = AppCell::new();
618 let mut app = cell.borrow_mut();
619 let manifold = Rc::new(CountingManifold {
620 requests: Cell::new(0),
621 });
622 let callbacks = Rc::new(Cell::new(0));
623 let owner = PipelineOwner::new(
624 &mut app,
625 Some(Listener::new({
626 let callbacks = callbacks.clone();
627 move |_app| callbacks.set(callbacks.get() + 1)
628 })),
629 None,
630 );
631 owner.attach(&mut app, manifold.clone());
632 owner.request_visual_update(&mut app);
633 assert_eq!((callbacks.get(), manifold.requests.get()), (1, 0));
634 }
635}