1use std::rc::Rc;
6
7use inset_foundation::{App, Handle, Listener};
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 struct PipelineOwner {
55 on_need_visual_update: Option<Listener>,
56 manifold: Option<Rc<dyn PipelineManifold>>,
57 root_node: Option<AnyRenderObject>,
58 nodes_needing_layout: Vec<AnyRenderObject>,
59 nodes_needing_compositing_bits_update: Vec<AnyRenderObject>,
60 should_merge_dirty_nodes: bool,
61 debug_allow_mutations_to_dirty_subtrees: bool,
63 debug_doing_layout: bool,
64 debug_doing_child_layout: bool,
65 nodes_needing_paint: Vec<AnyRenderObject>,
66 debug_doing_paint: bool,
67 children: Vec<Handle<PipelineOwner>>,
68 debug_parent: Option<Handle<PipelineOwner>>,
69}
70
71impl PipelineOwner {
72 pub fn new(app: &mut App, on_need_visual_update: Option<Listener>) -> Handle<PipelineOwner> {
77 app.create(PipelineOwner {
78 on_need_visual_update,
79 manifold: None,
80 root_node: None,
81 nodes_needing_layout: Vec::new(),
82 nodes_needing_compositing_bits_update: Vec::new(),
83 should_merge_dirty_nodes: false,
84 debug_allow_mutations_to_dirty_subtrees: false,
85 debug_doing_layout: false,
86 debug_doing_child_layout: false,
87 nodes_needing_paint: Vec::new(),
88 debug_doing_paint: false,
89 children: Vec::new(),
90 debug_parent: None,
91 })
92 }
93
94 pub fn request_visual_update(self: Handle<Self>, app: &mut App) {
100 if let Some(callback) = app.get(self).on_need_visual_update.clone() {
101 callback.call(app);
102 } else if let Some(manifold) = app.get(self).manifold.clone() {
103 manifold.request_visual_update(app);
104 }
105 }
106
107 pub fn root_node(self: Handle<Self>, app: &App) -> Option<AnyRenderObject> {
109 app.get(self).root_node
110 }
111
112 pub fn set_root_node(self: Handle<Self>, app: &mut App, value: Option<AnyRenderObject>) {
114 let current = app.get(self).root_node;
115 if current == value {
116 return;
117 }
118 if let Some(old) = current {
119 old.detach(app);
120 }
121 app.get_mut(self).root_node = value;
122 if let Some(new) = value {
123 new.attach(app, self);
124 }
125 }
126
127 pub fn nodes_needing_layout(self: Handle<Self>, app: &App) -> Vec<AnyRenderObject> {
130 app.get(self).nodes_needing_layout.clone()
131 }
132
133 pub(crate) fn add_node_needing_layout(
134 self: Handle<Self>,
135 app: &mut App,
136 node: AnyRenderObject,
137 ) {
138 app.get_mut(self).nodes_needing_layout.push(node);
139 }
140
141 pub(crate) fn add_node_needing_compositing_bits_update(
142 self: Handle<Self>,
143 app: &mut App,
144 node: AnyRenderObject,
145 ) {
146 app.get_mut(self)
147 .nodes_needing_compositing_bits_update
148 .push(node);
149 }
150
151 pub(crate) fn remove_node_needing_paint(
152 self: Handle<Self>,
153 app: &mut App,
154 node: AnyRenderObject,
155 ) {
156 app.get_mut(self)
157 .nodes_needing_paint
158 .retain(|candidate| *candidate != node);
159 }
160
161 pub fn debug_doing_layout(self: Handle<Self>, app: &App) -> bool {
165 if !cfg!(debug_assertions) {
166 return false;
167 }
168 app.get(self).debug_doing_layout
169 }
170
171 pub(crate) fn enable_mutations_to_dirty_subtrees(
175 self: Handle<Self>,
176 app: &mut App,
177 callback: impl FnOnce(&mut App),
178 ) {
179 debug_assert!(app.get(self).debug_doing_layout);
180 let old_state = app.get(self).debug_allow_mutations_to_dirty_subtrees;
181 if cfg!(debug_assertions) {
182 app.get_mut(self).debug_allow_mutations_to_dirty_subtrees = true;
183 }
184 callback(app);
185 app.get_mut(self).should_merge_dirty_nodes = true;
186 if cfg!(debug_assertions) {
187 app.get_mut(self).debug_allow_mutations_to_dirty_subtrees = old_state;
188 }
189 }
190
191 pub fn flush_layout(self: Handle<Self>, app: &mut App) {
193 if cfg!(debug_assertions) {
194 app.get_mut(self).debug_doing_layout = true;
195 }
196 while !app.get(self).nodes_needing_layout.is_empty() {
197 debug_assert!(!app.get(self).should_merge_dirty_nodes);
198 let mut dirty_nodes = std::mem::take(&mut app.get_mut(self).nodes_needing_layout);
199 dirty_nodes.sort_by_key(|node| node.depth(app));
200 let mut i = 0;
201 while i < dirty_nodes.len() {
202 if app.get(self).should_merge_dirty_nodes {
203 app.get_mut(self).should_merge_dirty_nodes = false;
204 if !app.get(self).nodes_needing_layout.is_empty() {
205 app.get_mut(self)
206 .nodes_needing_layout
207 .extend(dirty_nodes.drain(i..));
208 break;
209 }
210 }
211 let node = dirty_nodes[i];
212 if node.needs_layout(app) && node.owner(app) == Some(self) {
213 node.layout_without_resize(app);
214 }
215 i += 1;
216 }
217 app.get_mut(self).should_merge_dirty_nodes = false;
218 }
219 if cfg!(debug_assertions) {
220 app.get_mut(self).debug_doing_child_layout = true;
221 }
222 let children = app.get(self).children.clone();
223 for child in children {
224 child.flush_layout(app);
225 }
226 debug_assert!(
227 app.get(self).nodes_needing_layout.is_empty(),
228 "Child PipelineOwners must not dirty nodes in their parent."
229 );
230 app.get_mut(self).should_merge_dirty_nodes = false;
231 if cfg!(debug_assertions) {
232 app.get_mut(self).debug_doing_layout = false;
233 app.get_mut(self).debug_doing_child_layout = false;
234 }
235 }
236
237 pub fn flush_compositing_bits(self: Handle<Self>, app: &mut App) {
242 let mut dirty_nodes =
243 std::mem::take(&mut app.get_mut(self).nodes_needing_compositing_bits_update);
244 dirty_nodes.sort_by_key(|node| node.depth(app));
245 for node in dirty_nodes {
246 if node.needs_compositing_bits_update(app) && node.owner(app) == Some(self) {
247 node.update_compositing_bits(app);
248 }
249 }
250 let children = app.get(self).children.clone();
251 for child in children {
252 child.flush_compositing_bits(app);
253 }
254 debug_assert!(
255 app.get(self)
256 .nodes_needing_compositing_bits_update
257 .is_empty(),
258 "Child PipelineOwners must not dirty nodes in their parent."
259 );
260 }
261
262 pub fn nodes_needing_paint(self: Handle<Self>, app: &App) -> Vec<AnyRenderObject> {
265 app.get(self).nodes_needing_paint.clone()
266 }
267
268 pub(crate) fn add_node_needing_paint(self: Handle<Self>, app: &mut App, node: AnyRenderObject) {
269 app.get_mut(self).nodes_needing_paint.push(node);
270 }
271
272 pub fn debug_doing_paint(self: Handle<Self>, app: &App) -> bool {
276 app.get(self).debug_doing_paint
277 }
278
279 pub fn flush_paint(self: Handle<Self>, app: &mut App) {
285 if cfg!(debug_assertions) {
286 app.get_mut(self).debug_doing_paint = true;
287 }
288 let mut dirty_nodes = std::mem::take(&mut app.get_mut(self).nodes_needing_paint);
289 dirty_nodes.sort_by_key(|node| std::cmp::Reverse(node.depth(app)));
290 for node in dirty_nodes {
291 debug_assert!(node.layer(app).is_some() || !cfg!(debug_assertions));
292 if (node.needs_paint(app) || node.needs_composited_layer_update(app))
293 && node.owner(app) == Some(self)
294 {
295 if node
296 .layer(app)
297 .is_some_and(|layer| layer.as_layer().attached(app))
298 {
299 debug_assert!(node.is_repaint_boundary(app));
300 if node.needs_paint(app) {
301 PaintingContext::repaint_composited_child(app, node);
302 } else {
303 PaintingContext::update_layer_properties(app, node);
304 }
305 } else {
306 node.skipped_painting_on_layer(app);
307 }
308 }
309 }
310 let children = app.get(self).children.clone();
311 for child in children {
312 child.flush_paint(app);
313 }
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 attach(self: Handle<Self>, app: &mut App, manifold: Rc<dyn PipelineManifold>) {
329 debug_assert!(app.get(self).manifold.is_none());
330 app.get_mut(self).manifold = Some(Rc::clone(&manifold));
331 let children = app.get(self).children.clone();
332 for child in children {
333 child.attach(app, Rc::clone(&manifold));
334 }
335 }
336
337 pub fn detach(self: Handle<Self>, app: &mut App) {
343 debug_assert!(app.get(self).manifold.is_some());
344 app.get_mut(self).manifold = None;
345 let children = app.get(self).children.clone();
346 for child in children {
347 child.detach(app);
348 }
349 }
350
351 pub fn adopt_child(self: Handle<Self>, app: &mut App, child: Handle<PipelineOwner>) {
353 debug_assert!(app.get(child).debug_parent.is_none());
354 debug_assert!(!app.get(self).children.contains(&child));
355 debug_assert!(
356 !app.get(self).debug_doing_child_layout,
357 "Cannot modify child list after layout."
358 );
359 app.get_mut(self).children.push(child);
360 if cfg!(debug_assertions) {
361 app.get_mut(child).debug_parent = Some(self);
362 }
363 if let Some(manifold) = app.get(self).manifold.clone() {
364 child.attach(app, manifold);
365 }
366 }
367
368 pub fn drop_child(self: Handle<Self>, app: &mut App, child: Handle<PipelineOwner>) {
371 debug_assert_eq!(app.get(child).debug_parent, Some(self));
372 debug_assert!(app.get(self).children.contains(&child));
373 debug_assert!(
374 !app.get(self).debug_doing_child_layout,
375 "Cannot modify child list after layout."
376 );
377 let children = &mut app.get_mut(self).children;
378 let index = children
379 .iter()
380 .position(|&candidate| candidate == child)
381 .expect("child was in the list");
382 children.remove(index);
383 if cfg!(debug_assertions) {
384 app.get_mut(child).debug_parent = None;
385 }
386 if app.get(self).manifold.is_some() {
387 child.detach(app);
388 }
389 }
390
391 pub fn visit_children(
393 self: Handle<Self>,
394 app: &App,
395 visitor: &mut dyn FnMut(Handle<PipelineOwner>),
396 ) {
397 for child in &app.get(self).children {
398 visitor(*child);
399 }
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use std::cell::{Cell, RefCell};
406 use std::rc::Rc;
407
408 use inset_embedder::Size;
409 use inset_foundation::{App, AppCell};
410
411 use super::*;
412 use crate::box_::{RenderBox, RenderBoxData};
413 use crate::object::{RenderHandle, RenderObject, RenderObjectData};
414
415 struct TestLeaf {
416 render_object: RenderObjectData,
417 render_box: RenderBoxData,
418 on_layout: Option<Rc<dyn Fn()>>,
419 }
420
421 impl RenderObject for TestLeaf {
422 crate::render_object_accessors!();
423
424 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
425 if let Some(on_layout) = self.get(app).on_layout.clone() {
426 on_layout();
427 }
428 let size = self
429 .render_box_data(app)
430 .constraints
431 .map(crate::box_::BoxConstraints::smallest)
432 .unwrap_or(Size::ZERO);
433 self.set_size(app, size);
434 }
435 }
436
437 impl RenderBox for TestLeaf {
438 crate::render_box_accessors!();
439 }
440
441 fn leaf(on_layout: Option<Rc<dyn Fn()>>) -> TestLeaf {
442 TestLeaf {
443 render_object: RenderObjectData::new(),
444 render_box: RenderBoxData::new(),
445 on_layout,
446 }
447 }
448
449 #[test]
452 fn parent_pipeline_lays_out_before_child_pipeline() {
453 let cell = AppCell::new();
454 let mut app = cell.borrow_mut();
455 let log = Rc::new(RefCell::new(Vec::new()));
456
457 let root_log = Rc::clone(&log);
458 let root_node = RenderHandle::new_box(
459 &mut app,
460 leaf(Some(Rc::new(move || {
461 root_log.borrow_mut().push("layout parent")
462 }))),
463 );
464 let root = PipelineOwner::new(&mut app, None);
465 root.set_root_node(&mut app, Some(root_node.as_object()));
466 root_node.schedule_initial_layout(&mut app);
467
468 let child_log = Rc::clone(&log);
469 let child_node = RenderHandle::new_box(
470 &mut app,
471 leaf(Some(Rc::new(move || {
472 child_log.borrow_mut().push("layout child")
473 }))),
474 );
475 let child = PipelineOwner::new(&mut app, None);
476 child.set_root_node(&mut app, Some(child_node.as_object()));
477 child_node.schedule_initial_layout(&mut app);
478
479 root.adopt_child(&mut app, child);
480 root.flush_layout(&mut app);
481 assert_eq!(*log.borrow(), ["layout parent", "layout child"]);
482 }
483
484 #[test]
485 fn set_root_node_attaches_and_replacing_detaches() {
486 let cell = AppCell::new();
487 let mut app = cell.borrow_mut();
488 let owner = PipelineOwner::new(&mut app, None);
489 let first = RenderHandle::new_box(&mut app, leaf(None));
490 let second = RenderHandle::new_box(&mut app, leaf(None));
491 owner.set_root_node(&mut app, Some(first.as_object()));
492 assert!(first.attached(&app));
493 assert_eq!(first.owner(&app), Some(owner));
494
495 owner.set_root_node(&mut app, Some(second.as_object()));
496 assert!(!first.attached(&app));
497 assert!(second.attached(&app));
498 }
499
500 #[test]
501 fn schedule_initial_layout_then_flush() {
502 let cell = AppCell::new();
503 let mut app = cell.borrow_mut();
504 let owner = PipelineOwner::new(&mut app, None);
505 let node = RenderHandle::new_box(&mut app, leaf(None));
506 owner.set_root_node(&mut app, Some(node.as_object()));
507 node.schedule_initial_layout(&mut app);
508 assert!(node.debug_needs_layout(&app));
509 owner.flush_layout(&mut app);
510 assert!(!node.debug_needs_layout(&app));
511 assert_eq!(node.size(&app), Size::ZERO);
512 }
513
514 struct CountingManifold {
516 requests: Cell<u32>,
517 }
518
519 impl PipelineManifold for CountingManifold {
520 fn request_visual_update(&self, _app: &mut App) {
521 self.requests.set(self.requests.get() + 1);
522 }
523 }
524
525 #[test]
526 fn an_owner_without_a_callback_requests_visual_updates_through_its_manifold() {
527 let cell = AppCell::new();
528 let mut app = cell.borrow_mut();
529 let manifold = Rc::new(CountingManifold {
530 requests: Cell::new(0),
531 });
532 let root = PipelineOwner::new(&mut app, None);
533 let adopted_before = PipelineOwner::new(&mut app, None);
534 root.adopt_child(&mut app, adopted_before);
535
536 adopted_before.request_visual_update(&mut app);
537 assert_eq!(
538 manifold.requests.get(),
539 0,
540 "unattached owners request nothing"
541 );
542
543 root.attach(&mut app, manifold.clone());
544 root.request_visual_update(&mut app);
545 adopted_before.request_visual_update(&mut app);
546 assert_eq!(
547 manifold.requests.get(),
548 2,
549 "attach reaches existing children"
550 );
551
552 let adopted_after = PipelineOwner::new(&mut app, None);
553 root.adopt_child(&mut app, adopted_after);
554 adopted_after.request_visual_update(&mut app);
555 assert_eq!(manifold.requests.get(), 3, "adopt_child attaches the child");
556
557 root.drop_child(&mut app, adopted_after);
558 adopted_after.request_visual_update(&mut app);
559 assert_eq!(manifold.requests.get(), 3, "drop_child detaches the child");
560
561 root.detach(&mut app);
562 adopted_before.request_visual_update(&mut app);
563 assert_eq!(manifold.requests.get(), 3, "detach reaches the children");
564 }
565
566 #[test]
567 fn a_callback_takes_precedence_over_the_manifold() {
568 let cell = AppCell::new();
569 let mut app = cell.borrow_mut();
570 let manifold = Rc::new(CountingManifold {
571 requests: Cell::new(0),
572 });
573 let callbacks = Rc::new(Cell::new(0));
574 let owner = PipelineOwner::new(
575 &mut app,
576 Some(Listener::new({
577 let callbacks = callbacks.clone();
578 move |_app| callbacks.set(callbacks.get() + 1)
579 })),
580 );
581 owner.attach(&mut app, manifold.clone());
582 owner.request_visual_update(&mut app);
583 assert_eq!((callbacks.get(), manifold.requests.get()), (1, 0));
584 }
585}