1use std::collections::{BTreeMap, BTreeSet, HashMap};
5
6use kurbo::{Rect as KRect, Vec2};
7use peniko::ImageData;
8
9use crate::display::{
10 Blend, Builder, Chunk, Clip, Effect, Id, List, Order, Placed, RunId, Space, Transform,
11};
12use crate::resolve::{self, ImageId, Node, Origin, Scene, Theme};
13use crate::tree::{NodeId as SceneId, OrderKey};
14
15use super::*;
16
17#[derive(Clone)]
20pub(super) struct Painted {
21 pub(super) data: ImageData,
22 pub(super) file: Option<ImageId>,
23}
24
25impl Painted {
26 pub(super) fn same(&self, other: &Painted) -> bool {
28 match (self.file, other.file) {
29 (Some(a), Some(b)) => a == b,
30 (None, None) => {
31 (self.data.width, self.data.height) == (other.data.width, other.data.height)
32 && self.data.data.data() == other.data.data.data()
33 }
34 _ => false,
35 }
36 }
37}
38
39pub struct Drawing {
44 pub(super) laid: Laid,
46 pub(super) theme: Theme,
47 pub(super) frames: BTreeMap<Order, Frame>,
49 pub(super) recs: BTreeMap<Order, Rec>,
50 pub(super) shown: HashMap<u32, RunId>,
52 pub(super) shifts: HashMap<RunId, f64>,
55 pub(super) contexts: HashMap<RunId, RunContext>,
57 pub(super) orders: HashMap<SceneId, Order>,
59 pub list: List,
61 pub(super) blobs: HashMap<ImageId, ImageData>,
63 pub images: Vec<ImageData>,
67 pub(super) shows: Vec<Painted>,
69 pub(super) painters: BTreeSet<Order>,
71 pub(super) fits: Result<(), Undrawable>,
73 pub(super) visited: usize,
75}
76
77#[derive(Debug, Clone, Default, PartialEq)]
82pub struct Damage {
83 pub rects: Vec<KRect>,
84 pub all: bool,
85}
86
87#[derive(Clone)]
90pub(super) struct Rec {
91 pub(super) node: SceneId,
92 pub(super) space: Space,
94 pub(super) transform: Id,
95 pub(super) effect: Option<Id>,
96 pub(super) clip: Option<Id>,
97 pub(super) painted: Vec<(Painted, Origin)>,
98}
99
100impl Drawing {
101 pub fn area(&self) -> Frame {
104 self.list.area
105 }
106
107 pub fn frames(&self) -> Vec<Frame> {
109 self.frames
110 .iter()
111 .map(|(o, f)| {
112 let at = self.list.space_at(&self.recs[o].space);
113 Frame {
114 x: f.x + at.x as f32,
115 y: f.y + at.y as f32,
116 ..*f
117 }
118 })
119 .collect()
120 }
121
122 pub fn theme(&self) -> Theme {
123 self.theme
124 }
125
126 pub fn view_tiles(&self, view: &crate::tiles::View) -> Vec<(u32, u32)> {
129 let a = self.area();
130 let area = KRect::new(
131 a.x as f64,
132 a.y as f64,
133 (a.x + a.width) as f64,
134 (a.y + a.height) as f64,
135 );
136 view.tiles(area, crate::tiles::Level::of(view.zoom))
137 }
138
139 pub fn action_at(&self, x: f32, y: f32) -> Option<&str> {
142 self.list.action_at(x as f64, y as f64)
143 }
144
145 pub fn update(
154 &mut self,
155 renderer: &mut Renderer,
156 new: &Scene,
157 applied: &crate::wire::Applied,
158 ) -> Result<Damage, Undrawable> {
159 renderer.update(self, new, applied)
160 }
161
162 pub fn prepare(&mut self, renderer: &mut Renderer, scene: &Scene, area: KRect) {
169 let mut rounded = false;
170 loop {
171 let stale = self.list.unrounded(area);
172 if stale.is_empty() {
173 break;
174 }
175 for (drid, key) in stale {
176 renderer.reround(self, scene, drid, &key);
177 }
178 self.list.flush();
179 rounded = true;
180 }
181 if rounded {
182 renderer.settle_area(self);
183 }
184 }
185
186 pub fn prepare_all(&mut self, renderer: &mut Renderer, scene: &Scene) {
188 let everything = KRect::new(-1e12, -1e12, 1e12, 1e12);
189 self.prepare(renderer, scene, everything);
190 }
191
192 pub fn update_between(
197 &mut self,
198 renderer: &mut Renderer,
199 old: &mut Scene,
200 new: &Scene,
201 ) -> Result<Damage, Undrawable> {
202 let mut uses = crate::wire::Uses::of(&old.root);
203 let applied = crate::wire::bring(old, &mut uses, new)
204 .expect("the patch between two scenes applies to the first");
205 renderer.update(self, old, &applied)
206 }
207}
208
209impl Renderer {
210 pub fn drawing(
221 &mut self,
222 scene: &Scene,
223 theme: Theme,
224 after: Option<&Drawing>,
225 ) -> Result<Drawing, Undrawable> {
226 self.register(&scene.fonts);
227 let mut laid = Laid::build(self, scene);
228 let hugs = std::mem::take(&mut laid.hugs);
229 laid.settle_top(self, &hugs);
230 let root = laid.root;
231 let mut d = Drawing {
232 laid,
233 theme,
234 frames: BTreeMap::new(),
235 recs: BTreeMap::new(),
236 shown: HashMap::new(),
237 shifts: HashMap::new(),
238 contexts: HashMap::new(),
239 orders: HashMap::new(),
240 list: List::new(),
241 blobs: HashMap::new(),
242 images: Vec::new(),
243 shows: Vec::new(),
244 painters: BTreeSet::new(),
245 fits: Ok(()),
246 visited: 0,
247 };
248 self.blobs.clear();
249 let mut made = Vec::new();
250 let (t, c) = (d.list.root_transform, d.list.root_clip);
251 let mut walk = Walk {
252 scene,
253 dirty: &|_| true,
254 reflow: None,
255 path: None,
256 damage: None,
257 fresh: Some(&mut made),
258 images: true,
259 };
260 self.sync(
261 &mut d,
262 &mut walk,
263 &scene.root,
264 Vec::new(),
265 Owner::Top,
266 root,
267 t,
268 Place::default(),
269 (&Space::Root, Vec2::ZERO),
270 c,
271 None,
272 None,
273 (false, true),
274 None,
275 );
276 d.list.load(made);
277 d.blobs = std::mem::take(&mut self.blobs);
278 self.settle_area(&mut d);
279 self.settle_images(&mut d)?;
280 if let Some(last) = after
281 && last.shows.len() == d.shows.len()
282 && last.shows.iter().zip(&d.shows).all(|(a, b)| a.same(b))
283 {
284 let last_of: HashMap<u64, ImageData> = d
285 .shows
286 .iter()
287 .zip(&last.shows)
288 .map(|(new, old)| (new.data.data.id(), old.data.clone()))
289 .collect();
290 d.list.swap_images(&last_of);
291 for rec in d.recs.values_mut() {
292 for (p, _) in &mut rec.painted {
293 if let Some(old) = last_of.get(&p.data.data.id()) {
294 p.data = old.clone();
295 }
296 }
297 }
298 for data in d.blobs.values_mut() {
299 if let Some(old) = last_of.get(&data.data.id()) {
300 *data = old.clone();
301 }
302 }
303 d.shows = last.shows.clone();
304 d.images = d.shows.iter().map(|p| p.data.clone()).collect();
305 }
306 Ok(d)
307 }
308
309 pub(super) fn settle_area(&mut self, d: &mut Drawing) {
313 let root = d.frames[&Vec::new()];
314 let mut area = frame_rect(root);
315 if let Some(covered) = d.list.covered() {
316 area = area.union(covered);
317 }
318 const SLIVER: f64 = 0.01;
319 let area = KRect::new(
320 (area.x0 + SLIVER).floor(),
321 (area.y0 + SLIVER).floor(),
322 (area.x1 - SLIVER).ceil(),
323 (area.y1 - SLIVER).ceil(),
324 );
325 d.list.set_area(Frame {
326 x: area.x0 as f32,
327 y: area.y0 as f32,
328 width: area.width() as f32,
329 height: area.height() as f32,
330 });
331 }
332
333 pub(super) fn settle_images(&mut self, d: &mut Drawing) -> Result<(), Undrawable> {
336 d.fits = self.fit_images(d);
337 d.fits.clone()
338 }
339
340 pub(super) fn fit_images(&mut self, d: &mut Drawing) -> Result<(), Undrawable> {
341 let mut files = BTreeSet::new();
342 let mut painted: Vec<(Painted, Origin)> = Vec::new();
343 for order in &d.painters {
344 for (p, at) in &d.recs[order].painted {
345 if p.file.is_none_or(|id| files.insert(id)) {
346 painted.push((p.clone(), at.clone()));
347 }
348 }
349 }
350 d.blobs.retain(|id, _| files.contains(id));
351 d.shows = painted.iter().map(|(p, _)| p.clone()).collect();
352 d.images = d.shows.iter().map(|p| p.data.clone()).collect();
353 let sizes: Vec<(u32, u32)> = painted
354 .iter()
355 .map(|(p, _)| (p.data.width, p.data.height))
356 .collect();
357 if let Err(n) = crate::atlas::place(&sizes) {
358 let (Painted { data, .. }, at) = &painted[n];
359 let what = if at.file.is_empty() {
360 "an image"
361 } else {
362 "this"
363 };
364 return Err(Undrawable {
365 message: format!(
366 "{what} doesn't fit: the images a drawing paints — its image files, \
367 at most {side} pixels a side, and its shadows — share the GPU's one \
368 {atlas}×{atlas} atlas, and the {n} before this {w}×{h} fill it",
369 side = resolve::MAX_IMAGE_SIDE,
370 atlas = crate::atlas::SIDE,
371 w = data.width,
372 h = data.height,
373 ),
374 at: Some(at.clone()),
375 });
376 }
377 Ok(())
378 }
379
380 #[allow(clippy::too_many_arguments)]
388 pub(super) fn sync(
389 &mut self,
390 d: &mut Drawing,
391 w: &mut Walk,
392 node: &Node,
393 order: Order,
394 owner: Owner,
395 id: NodeId,
396 parent_t: Id,
397 parent: Place,
398 (space, space_at): (&Space, Vec2),
399 clip: Id,
400 cut: Option<KRect>,
401 effect: Option<Id>,
402 (remade, all_below): (bool, bool),
403 item: Option<(RunId, OrderKey)>,
404 ) -> bool {
405 let (abs, place) = placed(d.laid.tree(owner), id, parent, order.is_empty());
406 let f = Frame {
407 x: abs.x - space_at.x as f32,
408 y: abs.y - space_at.y as f32,
409 ..abs
410 };
411 let parent_origin = Vec2::new(
412 parent.at.0 as f64 - space_at.x,
413 parent.at.1 as f64 - space_at.y,
414 );
415 let origin = Vec2::new(f.x as f64, f.y as f64);
416 d.visited += 1;
417 let old = d.recs.remove(&order);
418 let is_new = old.is_none();
419 let was = d.frames.insert(order.clone(), f);
420 let resized = was.is_none_or(|was| (was.width, was.height) != (f.width, f.height));
421 let moved = was.is_none_or(|was| (was.x, was.y) != (f.x, f.y));
422 let cut_changed = d.list.chunk(&order).is_none_or(|c| c.cut != cut);
423 let dirty = (w.dirty)(&order);
424 let remake = old.is_none() || remade || dirty || resized;
425 let trees = &mut d.list.trees;
426 let offset = if item.is_some() {
427 Vec2::ZERO
428 } else {
429 origin - parent_origin
430 };
431 let transform = match &old {
433 Some(rec) => {
434 let t = trees.transforms.get_mut(rec.transform);
435 t.offset = offset;
436 t.item = item.clone();
437 rec.transform
438 }
439 None => trees.transforms.add(Transform {
440 parent: Some(parent_t),
441 offset,
442 item: item.clone(),
443 }),
444 };
445 let mut children_remade = remade;
446 let (own_effect, own_clip) = if remake {
447 let opacity = (node.opacity < 1.0).then_some(node.opacity);
450 let had = old.as_ref().and_then(|r| r.effect);
451 let new_effect = match (had, opacity) {
452 (Some(e), Some(o)) if !remade => {
453 trees.effects.get_mut(e).blend = Blend::Opacity(o);
454 Some(e)
455 }
456 (had, o) => {
457 if let Some(e) = had {
458 trees.effects.remove(e);
459 }
460 children_remade |= had.is_some() || o.is_some();
461 o.map(|o| {
462 trees.effects.add(Effect {
463 parent: effect,
464 clip,
465 transform,
466 blend: Blend::Opacity(o),
467 bounds: None,
468 })
469 })
470 }
471 };
472 let shape = node.clip.then(|| {
473 node_shape(
474 node,
475 KRect::new(0.0, 0.0, f.width as f64, f.height as f64),
476 0.0,
477 )
478 });
479 let had = old.as_ref().and_then(|r| r.clip);
480 let new_clip = match (had, shape) {
481 (Some(c), Some(path)) if !remade => {
482 trees.clips.get_mut(c).path = path;
483 Some(c)
484 }
485 (had, shape) => {
486 if let Some(c) = had {
487 trees.clips.remove(c);
488 }
489 children_remade |= had.is_some() || shape.is_some();
490 shape.map(|path| {
491 trees.clips.add(Clip {
492 parent: Some(clip),
493 transform,
494 path,
495 })
496 })
497 }
498 };
499 (new_effect, new_clip)
500 } else {
501 let rec = old.as_ref().expect("kept");
502 (rec.effect, rec.clip)
503 };
504 let under = own_effect.or(effect);
505 let was = d.list.take(&order);
506 let (chunk, painted) = match was {
507 Some(c) if !remake => {
508 let moved = c.origin != origin || c.cut != cut;
509 let at = d.list.space_at(space);
510 if moved && let Some(damage) = w.damage.as_deref_mut() {
511 damage.rects.extend(c.bounds.map(|b| b + at));
512 }
513 let c = c.moved(origin, cut);
514 if moved && let Some(damage) = w.damage.as_deref_mut() {
515 damage.rects.extend(c.bounds.map(|b| b + space_at));
516 }
517 (c, old.expect("kept").painted)
518 }
519 was => {
520 if let Some(c) = &was {
521 if let Some(damage) = w.damage.as_deref_mut() {
522 let at = d.list.space_at(&c.space);
523 damage.rects.extend(c.bounds.map(|b| b + at));
524 }
525 d.list.free(&c.made);
526 }
527 let local = Frame {
528 x: 0.0,
529 y: 0.0,
530 width: f.width,
531 height: f.height,
532 };
533 self.painted.clear();
534 let mut covers = Vec::new();
535 let mut b = Builder::new(&mut d.list.trees, transform, clip, under);
536 self.own(w.scene, node, local, d.theme, &mut b, &mut covers);
537 let mut built = b.finish();
538 let mut painted = std::mem::take(&mut self.painted);
539 if let Some(rec) = &old
542 && rec.painted.len() == painted.len()
543 && rec
544 .painted
545 .iter()
546 .zip(&painted)
547 .all(|(a, b)| a.0.same(&b.0))
548 {
549 let last_of: HashMap<u64, ImageData> = painted
550 .iter()
551 .zip(&rec.painted)
552 .map(|(new, old)| (new.0.data.data.id(), old.0.data.clone()))
553 .collect();
554 swap(&mut built.0, &last_of);
555 painted = rec.painted.clone();
556 }
557 let action = node
558 .on_click
559 .clone()
560 .map(|a| (a, KRect::new(0.0, 0.0, f.width as f64, f.height as f64)));
561 let c = Chunk::new(transform, space.clone(), origin, built, covers, action, cut);
562 if let Some(damage) = w.damage.as_deref_mut() {
563 damage.rects.extend(c.bounds.map(|b| b + space_at));
564 }
565 if !painted.is_empty() || old.as_ref().is_some_and(|r| !r.painted.is_empty()) {
566 w.images = true;
567 }
568 (c, painted)
569 }
570 };
571 if painted.is_empty() {
572 d.painters.remove(&order);
573 } else {
574 d.painters.insert(order.clone());
575 }
576 d.orders.insert(node.id.clone(), order.clone());
577 d.recs.insert(
578 order.clone(),
579 Rec {
580 node: node.id.clone(),
581 space: space.clone(),
582 transform,
583 effect: own_effect,
584 clip: own_clip,
585 painted,
586 },
587 );
588 match w.fresh.as_deref_mut() {
589 Some(fresh) if *space == Space::Root => fresh.push((order.clone(), chunk)),
590 _ => d.list.put(order.clone(), chunk),
591 }
592 let rect = frame_rect(f);
593 let (inner, inner_cut) = match own_clip {
594 Some(c) => (c, Some(cut.map_or(rect, |k| rect.intersect(k)))),
595 None => (clip, cut),
596 };
597 let all = w.path.is_none()
601 || all_below
602 || is_new
603 || dirty
604 || resized
605 || moved
606 || cut_changed
607 || children_remade
608 || w.reflow.is_some_and(|r| r.contains(&order));
609 if leaf_of(node, &w.scene.images).is_some() {
610 return resized;
611 }
612 let on_path = match (all, w.path) {
613 (false, Some(path)) => path.get(&order).cloned().unwrap_or_default(),
614 _ => BTreeSet::new(),
615 };
616 let down = Down {
617 transform,
618 place,
619 space,
620 space_at,
621 clip: inner,
622 cut: inner_cut,
623 effect: under,
624 remade: children_remade,
625 };
626 if let Some(&rid) = d.laid.run_of.get(&order) {
627 let every = w.path.is_none() || all_below || is_new || dirty || children_remade;
632 let on_path = match w.path {
633 Some(path) if !every => path.get(&order).cloned().unwrap_or_default(),
634 _ => BTreeSet::new(),
635 };
636 self.sync_run(
637 d, w, node, &order, owner, id, rid, &down, every, &on_path, is_new,
638 );
639 return resized;
640 }
641 let visit = |r: &mut Renderer, d: &mut Drawing, w: &mut Walk, k: &OrderKey, all: bool| {
642 let Some(child) = node.children.get(k) else {
643 return false;
644 };
645 let mut o = order.clone();
646 o.push(k.clone());
647 let (owner, id) = d.laid.nodes[&o];
648 r.sync(
649 d,
650 w,
651 child,
652 o,
653 owner,
654 id,
655 down.transform,
656 down.place,
657 (down.space, down.space_at),
658 down.clip,
659 down.cut,
660 down.effect,
661 (down.remade, all),
662 None,
663 )
664 };
665 let flows = node.layout != resolve::Layout::None;
667 if all {
668 for k in node.children.entries().map(|(k, _)| k) {
669 visit(self, d, w, k, all_below);
670 }
671 } else {
672 let mut moves = false;
673 for k in &on_path {
674 moves |= visit(self, d, w, k, false);
675 }
676 if moves && flows {
677 for k in node.children.entries().map(|(k, _)| k) {
678 if !on_path.contains(k) {
679 visit(self, d, w, k, false);
680 }
681 }
682 }
683 }
684 resized
685 }
686
687 #[allow(clippy::too_many_arguments)]
694 fn sync_run(
695 &mut self,
696 d: &mut Drawing,
697 w: &mut Walk,
698 node: &Node,
699 order: &Order,
700 owner: Owner,
701 id: NodeId,
702 rid: u32,
703 down: &Down,
704 all: bool,
705 on_path: &BTreeSet<OrderKey>,
706 is_new: bool,
707 ) {
708 let size = d.laid.tree(owner).unrounded_layout(id).size;
709 let Some((run, asked, lead)) = d.laid.run_places(rid, size) else {
710 return;
711 };
712 let (pc0, _) = run.padding_across();
713 let (row, gap, line) = (run.row, run.gap as f64, asked.line);
714 let drid = match d.shown.get(&rid) {
715 Some(&r) => r,
716 None => {
717 let r = d.list.add_run(down.space.clone());
718 d.shown.insert(rid, r);
719 r
720 }
721 };
722 let raw = Vec2::new(
723 down.place.raw.0 as f64 - down.space_at.x,
724 down.place.raw.1 as f64 - down.space_at.y,
725 );
726 let at = Vec2::new(
727 down.place.at.0 as f64 - down.space_at.x,
728 down.place.at.1 as f64 - down.space_at.y,
729 );
730 let old_entry = d.list.run(drid).entry().map(|e| e + down.space_at);
731 let changed = {
732 let dr = d.list.run(drid);
733 is_new || dr.row != row || dr.gap != gap || dr.line != line as f64
738 };
739 {
740 let dr = d.list.run_mut(drid);
741 dr.raw = raw;
742 dr.at = at;
743 dr.origin = down.space_at;
744 dr.row = row;
745 dr.start = lead as f64;
746 dr.across = pc0 as f64;
747 dr.gap = gap;
748 dr.line = line as f64;
749 dr.cut = down.cut;
750 }
751 d.list.resum(drid);
752 let every = all || changed;
753 let local = |v: (f32, f32)| (v.0 - down.space_at.x as f32, v.1 - down.space_at.y as f32);
754 d.contexts.insert(
755 drid,
756 RunContext {
757 order: order.clone(),
758 owner,
759 id,
760 rid,
761 transform: down.transform,
762 place: Place {
763 at: local(down.place.at),
764 raw: local(down.place.raw),
765 },
766 space: down.space.clone(),
767 clip: down.clip,
768 effect: down.effect,
769 },
770 );
771 let mut shift: Option<f64> = d.shifts.remove(&drid);
772 let keys: Vec<OrderKey> = if every {
773 node.children.entries().map(|(k, _)| k.clone()).collect()
774 } else {
775 on_path.iter().cloned().collect()
776 };
777 let mut queue: std::collections::VecDeque<OrderKey> = keys.into();
778 let mut seen = BTreeSet::new();
779 while let Some(k) = queue.pop_front() {
780 if !seen.insert(k.clone()) {
781 continue;
782 }
783 let Some(child) = node.children.get(&k) else {
784 continue;
785 };
786 let (run, asked, _) = d.laid.run_places(rid, size).expect("placed");
787 let Some(s) = asked.sizes.get(&k).copied() else {
788 continue;
789 };
790 let stretch = run.children[&k].stretch;
791 let offset = run.across(line, &s, stretch) as f64;
792 let child_node = run.children[&k].node;
793 self.relay(&mut d.laid.runs, rid, &k, line);
794 let (before, old_size) = {
795 let dr = d.list.run(drid);
796 let before = dr.prefix(&k);
797 (before, dr.child(&k).map(|(_, p)| p.size))
798 };
799 let item = child_place(down.place, row, lead as f64 + before, pc0 as f64 + offset);
800 let item_at = Vec2::new(item.at.0 as f64, item.at.1 as f64);
801 let mut o = order.clone();
802 o.push(k.clone());
803 self.sync(
804 d,
805 w,
806 child,
807 o,
808 Owner::Run(rid),
809 child_node,
810 down.transform,
811 item,
812 (&Space::Item(drid, k.clone()), item_at),
813 down.clip,
814 None,
815 down.effect,
816 (down.remade, every),
817 Some((drid, k.clone())),
818 );
819 let delta = {
820 let (raw, at) = d.list.run(drid).place(before, offset);
821 at - raw
822 };
823 d.list.place_child(
824 drid,
825 k.clone(),
826 Some(Placed::new(s.along as f64, gap, offset, delta)),
827 );
828 let grew = old_size.map_or(s.along as f64 + gap, |o| s.along as f64 - o);
829 if grew != 0.0 {
830 let start = d.list.space_at(down.space) + d.list.run(drid).place(before, offset).1;
831 let start = if row { start.x } else { start.y };
832 shift = Some(shift.map_or(start, |s: f64| s.min(start)));
835 }
836 }
837 d.list.flush();
838 if let Some(start) = shift
839 && let Some(damage) = w.damage.as_deref_mut()
840 {
841 let new_entry = d.list.run(drid).entry().map(|e| e + down.space_at);
842 if let Some(both) = match (old_entry, new_entry) {
843 (Some(a), Some(b)) => Some(a.union(b)),
844 (a, b) => a.or(b),
845 } {
846 let r = if row {
847 KRect::new(start.max(both.x0), both.y0, both.x1, both.y1)
848 } else {
849 KRect::new(both.x0, start.max(both.y0), both.x1, both.y1)
850 };
851 if r.width() > 0.0 && r.height() > 0.0 {
852 damage.rects.push(r);
853 }
854 }
855 }
856 }
857}
858
859impl Renderer {
860 pub(super) fn reround(&mut self, d: &mut Drawing, scene: &Scene, drid: RunId, key: &OrderKey) {
864 let Some(ctx) = d.contexts.get(&drid).cloned() else {
865 return;
866 };
867 let space_at = d.list.space_at(&ctx.space);
868 let abs = |v: (f32, f32)| (v.0 + space_at.x as f32, v.1 + space_at.y as f32);
869 let place = Place {
870 at: abs(ctx.place.at),
871 raw: abs(ctx.place.raw),
872 };
873 let size = d.laid.tree(ctx.owner).unrounded_layout(ctx.id).size;
874 let Some((run, asked, lead)) = d.laid.run_places(ctx.rid, size) else {
875 return;
876 };
877 let line = asked.line;
878 let Some(s) = asked.sizes.get(key).copied() else {
879 return;
880 };
881 let offset = run.across(line, &s, run.children[key].stretch) as f64;
882 let (pc0, _) = run.padding_across();
883 let (row, gap, child_node) = (run.row, run.gap as f64, run.children[key].node);
884 self.relay(&mut d.laid.runs, ctx.rid, key, line);
885 let before = d.list.run(drid).prefix(key);
886 let item = child_place(place, row, lead as f64 + before, pc0 as f64 + offset);
887 let item_at = Vec2::new(item.at.0 as f64, item.at.1 as f64);
888 let mut order = ctx.order.clone();
889 order.push(key.clone());
890 let Some(node) = scene.at(&order) else {
891 return;
892 };
893 let mut walk = Walk {
894 scene,
895 dirty: &|_| false,
896 reflow: None,
897 path: None,
898 damage: None,
899 fresh: None,
900 images: false,
901 };
902 self.blobs = std::mem::take(&mut d.blobs);
903 self.sync(
904 d,
905 &mut walk,
906 node,
907 order,
908 Owner::Run(ctx.rid),
909 child_node,
910 ctx.transform,
911 item,
912 (&Space::Item(drid, key.clone()), item_at),
913 ctx.clip,
914 None,
915 ctx.effect,
916 (false, true),
917 Some((drid, key.clone())),
918 );
919 d.blobs = std::mem::take(&mut self.blobs);
920 let delta = {
921 let (raw, at) = d.list.run(drid).place(before, offset);
922 at - raw
923 };
924 d.list.place_child(
925 drid,
926 key.clone(),
927 Some(Placed::new(s.along as f64, gap, offset, delta)),
928 );
929 if walk.images {
930 let _ = self.settle_images(d);
931 }
932 }
933}
934
935#[derive(Clone)]
939pub(super) struct RunContext {
940 pub(super) order: Order,
941 pub(super) owner: Owner,
942 pub(super) id: NodeId,
943 pub(super) rid: u32,
944 pub(super) transform: Id,
945 pub(super) place: Place,
946 pub(super) space: Space,
947 pub(super) clip: Id,
948 pub(super) effect: Option<Id>,
949}
950
951pub(super) struct Down<'a> {
953 pub(super) transform: Id,
954 pub(super) place: Place,
955 pub(super) space: &'a Space,
956 pub(super) space_at: Vec2,
957 pub(super) clip: Id,
958 pub(super) cut: Option<KRect>,
959 pub(super) effect: Option<Id>,
960 pub(super) remade: bool,
961}
962
963pub(super) struct Walk<'a> {
965 pub(super) scene: &'a Scene,
966 pub(super) dirty: &'a dyn Fn(&Order) -> bool,
968 pub(super) reflow: Option<&'a BTreeSet<Order>>,
971 pub(super) path: Option<&'a HashMap<Order, BTreeSet<OrderKey>>>,
974 pub(super) damage: Option<&'a mut Damage>,
975 pub(super) fresh: Option<&'a mut Vec<(Order, Chunk)>>,
977 pub(super) images: bool,
979}
980
981pub(super) fn swap(commands: &mut [crate::display::Command], last_of: &HashMap<u64, ImageData>) {
983 for c in commands {
984 if let Draw::Fill(_, Paint::Image(data, _)) = &mut c.draw
985 && let Some(old) = last_of.get(&data.data.id())
986 {
987 *data = old.clone();
988 }
989 }
990}
991
992#[cfg(test)]
993mod tests;