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::scene::{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(crate) list: List,
61 pub(super) blobs: HashMap<ImageId, ImageData>,
63 pub(crate) 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, PartialEq)]
80pub enum Damage {
81 All,
84 Rects {
89 origin: (f64, f64),
90 rects: Vec<KRect>,
91 },
92}
93
94#[derive(Clone)]
97pub(super) struct Rec {
98 pub(super) node: SceneId,
99 pub(super) space: Space,
101 pub(super) transform: Id,
102 pub(super) effect: Option<Id>,
103 pub(super) clip: Option<Id>,
104 pub(super) painted: Vec<(Painted, Origin)>,
105}
106
107impl Drawing {
108 pub fn area(&self) -> Frame {
111 self.list.area
112 }
113
114 pub fn frames(&self) -> Vec<Frame> {
116 self.frames
117 .iter()
118 .map(|(o, f)| {
119 let at = self.list.space_at(&self.recs[o].space);
120 Frame {
121 x: f.x + at.x as f32,
122 y: f.y + at.y as f32,
123 ..*f
124 }
125 })
126 .collect()
127 }
128
129 pub fn theme(&self) -> Theme {
130 self.theme
131 }
132
133 pub fn action_at(&self, x: f32, y: f32) -> Option<&str> {
136 self.list.action_at(x as f64, y as f64)
137 }
138
139 pub(crate) fn update(
148 &mut self,
149 renderer: &mut Renderer,
150 new: &Scene,
151 applied: &crate::scene::Applied,
152 ) -> Result<Damage, Undrawable> {
153 renderer.update(self, new, applied)
154 }
155
156 pub(crate) fn prepare(&mut self, renderer: &mut Renderer, scene: &Scene, area: KRect) {
163 let mut rounded = false;
164 loop {
165 let stale = self.list.unrounded(area);
166 if stale.is_empty() {
167 break;
168 }
169 for (drid, key) in stale {
170 renderer.reround(self, scene, drid, &key);
171 }
172 self.list.flush();
173 rounded = true;
174 }
175 if rounded {
176 renderer.settle_area(self);
177 }
178 }
179
180 #[cfg(test)]
182 pub(crate) fn prepare_all(&mut self, renderer: &mut Renderer, scene: &Scene) {
183 let everything = KRect::new(-1e12, -1e12, 1e12, 1e12);
184 self.prepare(renderer, scene, everything);
185 }
186}
187
188impl Renderer {
189 pub fn drawing(
200 &mut self,
201 scene: &Scene,
202 theme: Theme,
203 after: Option<&Drawing>,
204 ) -> Result<Drawing, Undrawable> {
205 self.register(&scene.fonts);
206 let mut laid = Laid::build(self, scene);
207 laid.settle_top(self);
208 let root = laid.root;
209 let mut d = Drawing {
210 laid,
211 theme,
212 frames: BTreeMap::new(),
213 recs: BTreeMap::new(),
214 shown: HashMap::new(),
215 shifts: HashMap::new(),
216 contexts: HashMap::new(),
217 orders: HashMap::new(),
218 list: List::new(),
219 blobs: HashMap::new(),
220 images: Vec::new(),
221 shows: Vec::new(),
222 painters: BTreeSet::new(),
223 fits: Ok(()),
224 visited: 0,
225 };
226 self.blobs.clear();
227 let mut made = Vec::new();
228 let (t, c) = (d.list.root_transform, d.list.root_clip);
229 let mut walk = Walk {
230 scene,
231 dirty: &|_| true,
232 relaid: &|_| true,
233 path: None,
234 damage: None,
235 fresh: Some(&mut made),
236 images: true,
237 };
238 self.sync(
239 &mut d,
240 &mut walk,
241 &scene.root,
242 Vec::new(),
243 Owner::Top,
244 root,
245 t,
246 Place::default(),
247 (&Space::Root, Vec2::ZERO),
248 c,
249 None,
250 None,
251 (false, true),
252 None,
253 );
254 d.list.load(made);
255 d.blobs = std::mem::take(&mut self.blobs);
256 self.settle_area(&mut d);
257 self.settle_images(&mut d)?;
258 if let Some(last) = after
259 && last.shows.len() == d.shows.len()
260 && last.shows.iter().zip(&d.shows).all(|(a, b)| a.same(b))
261 {
262 let last_of: HashMap<u64, ImageData> = d
263 .shows
264 .iter()
265 .zip(&last.shows)
266 .map(|(new, old)| (new.data.data.id(), old.data.clone()))
267 .collect();
268 d.list.swap_images(&last_of);
269 for rec in d.recs.values_mut() {
270 for (p, _) in &mut rec.painted {
271 if let Some(old) = last_of.get(&p.data.data.id()) {
272 p.data = old.clone();
273 }
274 }
275 }
276 for data in d.blobs.values_mut() {
277 if let Some(old) = last_of.get(&data.data.id()) {
278 *data = old.clone();
279 }
280 }
281 d.shows = last.shows.clone();
282 d.images = d.shows.iter().map(|p| p.data.clone()).collect();
283 }
284 Ok(d)
285 }
286
287 pub(super) fn settle_area(&mut self, d: &mut Drawing) {
291 let root = d.frames[&Vec::new()];
292 let mut area = frame_rect(root);
293 if let Some(covered) = d.list.covered() {
294 area = area.union(covered);
295 }
296 const SLIVER: f64 = 0.01;
297 let area = KRect::new(
298 (area.x0 + SLIVER).floor(),
299 (area.y0 + SLIVER).floor(),
300 (area.x1 - SLIVER).ceil(),
301 (area.y1 - SLIVER).ceil(),
302 );
303 d.list.set_area(Frame {
304 x: area.x0 as f32,
305 y: area.y0 as f32,
306 width: area.width() as f32,
307 height: area.height() as f32,
308 });
309 }
310
311 pub(super) fn settle_images(&mut self, d: &mut Drawing) -> Result<(), Undrawable> {
314 d.fits = self.fit_images(d);
315 d.fits.clone()
316 }
317
318 pub(super) fn fit_images(&mut self, d: &mut Drawing) -> Result<(), Undrawable> {
319 let mut files = BTreeSet::new();
320 let mut painted: Vec<(Painted, Origin)> = Vec::new();
321 for order in &d.painters {
322 for (p, at) in &d.recs[order].painted {
323 if p.file.is_none_or(|id| files.insert(id)) {
324 painted.push((p.clone(), at.clone()));
325 }
326 }
327 }
328 d.blobs.retain(|id, _| files.contains(id));
329 d.shows = painted.iter().map(|(p, _)| p.clone()).collect();
330 d.images = d.shows.iter().map(|p| p.data.clone()).collect();
331 let sizes: Vec<(u32, u32)> = painted
332 .iter()
333 .map(|(p, _)| (p.data.width, p.data.height))
334 .collect();
335 if let Err(n) = crate::atlas::place(&sizes) {
336 let (Painted { data, .. }, at) = &painted[n];
337 let what = if at.file.is_empty() {
338 "an image"
339 } else {
340 "this"
341 };
342 return Err(Undrawable {
343 message: format!(
344 "{what} doesn't fit: the images a drawing paints — its image files, \
345 at most {side} pixels a side, and its shadows — share the GPU's one \
346 {atlas}×{atlas} atlas, and the {n} before this {w}×{h} fill it",
347 side = scene::MAX_IMAGE_SIDE,
348 atlas = crate::atlas::SIDE,
349 w = data.width,
350 h = data.height,
351 ),
352 at: Some(at.clone()),
353 });
354 }
355 Ok(())
356 }
357
358 #[allow(clippy::too_many_arguments)]
366 pub(super) fn sync(
367 &mut self,
368 d: &mut Drawing,
369 w: &mut Walk,
370 node: &Node,
371 order: Order,
372 owner: Owner,
373 id: NodeId,
374 parent_t: Id,
375 parent: Place,
376 (space, space_at): (&Space, Vec2),
377 clip: Id,
378 cut: Option<KRect>,
379 effect: Option<Id>,
380 (remade, all_below): (bool, bool),
381 item: Option<(RunId, OrderKey)>,
382 ) -> bool {
383 let (abs, place) = placed(d.laid.tree(owner), id, parent, order.is_empty());
384 let f = Frame {
385 x: abs.x - space_at.x as f32,
386 y: abs.y - space_at.y as f32,
387 ..abs
388 };
389 let parent_origin = Vec2::new(
390 parent.at.0 as f64 - space_at.x,
391 parent.at.1 as f64 - space_at.y,
392 );
393 let origin = Vec2::new(f.x as f64, f.y as f64);
394 d.visited += 1;
395 let old = d.recs.remove(&order);
396 let is_new = old.is_none();
397 let was = d.frames.insert(order.clone(), f);
398 let resized = was.is_none_or(|was| (was.width, was.height) != (f.width, f.height));
399 let moved = was.is_none_or(|was| (was.x, was.y) != (f.x, f.y));
400 let cut_changed = d.list.chunk(&order).is_none_or(|c| c.cut != cut);
401 let dirty = (w.dirty)(&order);
402 let remake = old.is_none() || remade || dirty || resized;
403 let trees = &mut d.list.trees;
404 let offset = if item.is_some() {
405 Vec2::ZERO
406 } else {
407 origin - parent_origin
408 };
409 let transform = match &old {
411 Some(rec) => {
412 let t = trees.transforms.get_mut(rec.transform);
413 t.offset = offset;
414 t.item = item.clone();
415 rec.transform
416 }
417 None => trees.transforms.add(Transform {
418 parent: Some(parent_t),
419 offset,
420 item: item.clone(),
421 }),
422 };
423 let mut children_remade = remade;
424 let (own_effect, own_clip) = if remake {
425 let parent_node = !node.children.is_empty();
432 let opacity = (node.opacity < 1.0 || parent_node).then_some(node.opacity);
433 let had = old.as_ref().and_then(|r| r.effect);
434 let new_effect = match (had, opacity) {
435 (Some(e), Some(o)) if !remade => {
436 trees.effects.get_mut(e).blend = Blend::Opacity(o);
437 Some(e)
438 }
439 (had, o) => {
440 if let Some(e) = had {
441 trees.effects.remove(e);
442 }
443 children_remade |= had.is_some() || o.is_some();
444 o.map(|o| {
445 trees.effects.add(Effect {
446 parent: effect,
447 clip,
448 transform,
449 blend: Blend::Opacity(o),
450 bounds: None,
451 })
452 })
453 }
454 };
455 let shape = if node.clip {
456 Some(node_shape(
457 node,
458 KRect::new(0.0, 0.0, f.width as f64, f.height as f64),
459 0.0,
460 ))
461 } else {
462 parent_node.then(kurbo::BezPath::new)
463 };
464 let had = old.as_ref().and_then(|r| r.clip);
465 let new_clip = match (had, shape) {
466 (Some(c), Some(path)) if !remade => {
467 trees.clips.get_mut(c).path = path;
468 Some(c)
469 }
470 (had, shape) => {
471 if let Some(c) = had {
472 trees.clips.remove(c);
473 }
474 children_remade |= had.is_some() || shape.is_some();
475 shape.map(|path| {
476 trees.clips.add(Clip {
477 parent: Some(clip),
478 transform,
479 path,
480 })
481 })
482 }
483 };
484 (new_effect, new_clip)
485 } else {
486 let rec = old.as_ref().expect("kept");
487 (rec.effect, rec.clip)
488 };
489 let under = own_effect.or(effect);
490 let was = d.list.take(&order);
491 let (chunk, painted) = match was {
492 Some(c) if !remake => {
493 let moved = c.origin != origin || c.cut != cut;
494 let at = d.list.space_at(space);
495 if moved && let Some(damage) = w.damage.as_deref_mut() {
496 damage.extend(c.bounds.map(|b| b + at));
497 }
498 let c = c.moved(origin, cut);
499 if moved && let Some(damage) = w.damage.as_deref_mut() {
500 damage.extend(c.bounds.map(|b| b + space_at));
501 }
502 (c, old.expect("kept").painted)
503 }
504 was => {
505 if let Some(c) = &was {
506 if let Some(damage) = w.damage.as_deref_mut() {
507 let at = d.list.space_at(&c.space);
508 damage.extend(c.bounds.map(|b| b + at));
509 }
510 d.list.free(&c.made);
511 }
512 let local = Frame {
513 x: 0.0,
514 y: 0.0,
515 width: f.width,
516 height: f.height,
517 };
518 self.painted.clear();
519 let mut covers = Vec::new();
520 let mut b = Builder::new(&mut d.list.trees, transform, clip, under);
521 self.own(w.scene, node, local, d.theme, &mut b, &mut covers);
522 let mut built = b.finish();
523 let mut painted = std::mem::take(&mut self.painted);
524 if let Some(rec) = &old
527 && rec.painted.len() == painted.len()
528 && rec
529 .painted
530 .iter()
531 .zip(&painted)
532 .all(|(a, b)| a.0.same(&b.0))
533 {
534 let last_of: HashMap<u64, ImageData> = painted
535 .iter()
536 .zip(&rec.painted)
537 .map(|(new, old)| (new.0.data.data.id(), old.0.data.clone()))
538 .collect();
539 swap(&mut built.0, &last_of);
540 painted = rec.painted.clone();
541 }
542 let action = node
543 .on_click
544 .clone()
545 .map(|a| (a, KRect::new(0.0, 0.0, f.width as f64, f.height as f64)));
546 let c = Chunk::new(transform, space.clone(), origin, built, covers, action, cut);
547 if let Some(damage) = w.damage.as_deref_mut() {
548 damage.extend(c.bounds.map(|b| b + space_at));
549 }
550 if !painted.is_empty() || old.as_ref().is_some_and(|r| !r.painted.is_empty()) {
551 w.images = true;
552 }
553 (c, painted)
554 }
555 };
556 if painted.is_empty() {
557 d.painters.remove(&order);
558 } else {
559 d.painters.insert(order.clone());
560 }
561 d.orders.insert(node.id.clone(), order.clone());
562 d.recs.insert(
563 order.clone(),
564 Rec {
565 node: node.id.clone(),
566 space: space.clone(),
567 transform,
568 effect: own_effect,
569 clip: own_clip,
570 painted,
571 },
572 );
573 match w.fresh.as_deref_mut() {
574 Some(fresh) if *space == Space::Root => fresh.push((order.clone(), chunk)),
575 _ => d.list.put(order.clone(), chunk),
576 }
577 let rect = frame_rect(f);
578 let (inner, inner_cut) = match own_clip {
579 Some(c) if node.clip => (c, Some(cut.map_or(rect, |k| rect.intersect(k)))),
580 Some(c) => (c, cut),
581 None => (clip, cut),
582 };
583 let all = w.path.is_none()
587 || all_below
588 || is_new
589 || (w.relaid)(&order)
590 || resized
591 || moved
592 || cut_changed
593 || children_remade;
594 if leaf_of(node, &w.scene.images).is_some() {
595 return resized;
596 }
597 let on_path = match (all, w.path) {
598 (false, Some(path)) => path.get(&order).cloned().unwrap_or_default(),
599 _ => BTreeSet::new(),
600 };
601 let down = Down {
602 transform,
603 place,
604 space,
605 space_at,
606 clip: inner,
607 cut: inner_cut,
608 effect: under,
609 remade: children_remade,
610 };
611 if let Some(&rid) = d.laid.run_of.get(&order) {
612 let every = w.path.is_none() || all_below || is_new || children_remade;
617 let on_path = match w.path {
618 Some(path) if !every => path.get(&order).cloned().unwrap_or_default(),
619 _ => BTreeSet::new(),
620 };
621 self.sync_run(
622 d, w, node, &order, owner, id, rid, &down, every, &on_path, is_new,
623 );
624 return resized;
625 }
626 let visit = |r: &mut Renderer, d: &mut Drawing, w: &mut Walk, k: &OrderKey, all: bool| {
627 let Some(child) = node.children.get(k) else {
628 return false;
629 };
630 let mut o = order.clone();
631 o.push(k.clone());
632 let (owner, id) = d.laid.nodes[&o];
633 r.sync(
634 d,
635 w,
636 child,
637 o,
638 owner,
639 id,
640 down.transform,
641 down.place,
642 (down.space, down.space_at),
643 down.clip,
644 down.cut,
645 down.effect,
646 (down.remade, all),
647 None,
648 )
649 };
650 let flows = node.layout != scene::Layout::None;
652 if all {
653 for k in node.children.entries().map(|(k, _)| k) {
654 visit(self, d, w, k, all_below);
655 }
656 } else {
657 let mut moves = false;
658 for k in &on_path {
659 moves |= visit(self, d, w, k, false);
660 }
661 if moves && flows {
662 for k in node.children.entries().map(|(k, _)| k) {
663 if !on_path.contains(k) {
664 visit(self, d, w, k, false);
665 }
666 }
667 }
668 }
669 resized
670 }
671
672 #[allow(clippy::too_many_arguments)]
679 fn sync_run(
680 &mut self,
681 d: &mut Drawing,
682 w: &mut Walk,
683 node: &Node,
684 order: &Order,
685 owner: Owner,
686 id: NodeId,
687 rid: u32,
688 down: &Down,
689 all: bool,
690 on_path: &BTreeSet<OrderKey>,
691 is_new: bool,
692 ) {
693 if d.laid.runs.get(rid).free {
694 return self.sync_free(
695 d, w, node, order, owner, id, rid, down, all, on_path, is_new,
696 );
697 }
698 let size = d.laid.tree(owner).unrounded_layout(id).size;
699 let Some((run, asked, lead, gap)) = d.laid.run_places(rid, size) else {
700 return;
701 };
702 let (pc0, _) = run.padding_across();
703 let (row, line, align) = (run.row, asked.line, run.align);
704 let drid = match d.shown.get(&rid) {
705 Some(&r) => r,
706 None => {
707 let r = d.list.add_run(down.space.clone());
708 d.shown.insert(rid, r);
709 r
710 }
711 };
712 let raw = Vec2::new(
713 down.place.raw.0 as f64 - down.space_at.x,
714 down.place.raw.1 as f64 - down.space_at.y,
715 );
716 let at = Vec2::new(
717 down.place.at.0 as f64 - down.space_at.x,
718 down.place.at.1 as f64 - down.space_at.y,
719 );
720 let old_entry = d.list.run(drid).entry().map(|e| e + down.space_at);
721 let changed = {
722 let dr = d.list.run(drid);
723 is_new
731 || dr.row != row
732 || (dr.line != line as f64 && run.align != crate::scene::Align::Start)
733 };
734 let spaced = {
738 let dr = d.list.run(drid);
739 !is_new && (dr.gap != gap || dr.start != lead as f64)
740 };
741 let realign = !is_new && d.contexts.get(&drid).is_some_and(|c| c.align != align);
745 let relaid = std::mem::take(&mut d.laid.runs.get_mut(rid).relaid);
746 {
747 let dr = d.list.run_mut(drid);
748 dr.raw = raw;
749 dr.at = at;
750 dr.origin = down.space_at;
751 dr.row = row;
752 dr.start = lead as f64;
753 dr.across = pc0 as f64;
754 dr.gap = gap;
755 dr.line = line as f64;
756 dr.cut = down.cut;
757 }
758 d.list.resum(drid);
759 let every = all || changed;
760 let local = |v: (f32, f32)| (v.0 - down.space_at.x as f32, v.1 - down.space_at.y as f32);
761 d.contexts.insert(
762 drid,
763 RunContext {
764 order: order.clone(),
765 owner,
766 id,
767 rid,
768 transform: down.transform,
769 place: Place {
770 at: local(down.place.at),
771 raw: local(down.place.raw),
772 },
773 space: down.space.clone(),
774 clip: down.clip,
775 effect: down.effect,
776 align,
777 },
778 );
779 let mut shift: Option<f64> = d.shifts.remove(&drid);
780 let keys: Vec<OrderKey> = if every || realign {
781 node.children.entries().map(|(k, _)| k.clone()).collect()
782 } else {
783 on_path.union(&relaid).cloned().collect()
784 };
785 let mut queue: std::collections::VecDeque<OrderKey> = keys.into();
786 let mut seen = BTreeSet::new();
787 while let Some(k) = queue.pop_front() {
788 if !seen.insert(k.clone()) {
789 continue;
790 }
791 let Some(child) = node.children.get(&k) else {
792 continue;
793 };
794 let (run, asked, _, _) = d.laid.run_places(rid, size).expect("placed");
795 let Some(s) = run.size_of(asked, &k) else {
796 continue;
797 };
798 let stretch = run.children[&k].stretch;
799 let offset = run.across(line, &s, stretch) as f64;
800 let child_node = run.children[&k].node;
801 self.relay(&mut d.laid.runs, rid, &k, line);
802 let (before, old_size) = {
803 let dr = d.list.run(drid);
804 let before = dr.prefix(&k);
805 (before, dr.child(&k).map(|(_, p)| p.size))
806 };
807 let item = child_place(down.place, row, lead as f64 + before, pc0 as f64 + offset);
808 let item_at = Vec2::new(item.at.0 as f64, item.at.1 as f64);
809 let mut o = order.clone();
810 o.push(k.clone());
811 self.sync(
812 d,
813 w,
814 child,
815 o,
816 Owner::Run(rid),
817 child_node,
818 down.transform,
819 item,
820 (&Space::Item(drid, k.clone()), item_at),
821 down.clip,
822 None,
823 down.effect,
824 (down.remade, every),
825 Some((drid, k.clone())),
826 );
827 let delta = {
828 let (raw, at) = d.list.run(drid).place(before, offset);
829 at - raw
830 };
831 d.list.place_child(
832 drid,
833 k.clone(),
834 Some(Placed::new(s.along as f64, offset, delta)),
835 );
836 let grew = old_size.map_or(s.along as f64 + 1.0, |o| s.along as f64 - o);
837 if grew != 0.0 {
838 let start = d.list.space_at(down.space) + d.list.run(drid).place(before, offset).1;
839 let start = if row { start.x } else { start.y };
840 shift = Some(shift.map_or(start, |s: f64| s.min(start)));
843 }
844 }
845 d.list.flush();
846 if spaced {
847 let first = d.list.space_at(down.space) + d.list.run(drid).place(0.0, 0.0).1;
848 let first = if row { first.x } else { first.y };
849 shift = Some(shift.map_or(first, |s: f64| s.min(first)));
850 }
851 if let Some(start) = shift
852 && let Some(damage) = w.damage.as_deref_mut()
853 {
854 let new_entry = d.list.run(drid).entry().map(|e| e + down.space_at);
855 if let Some(both) = match (old_entry, new_entry) {
856 (Some(a), Some(b)) => Some(a.union(b)),
857 (a, b) => a.or(b),
858 } {
859 let r = if row {
860 KRect::new(start.max(both.x0), both.y0, both.x1, both.y1)
861 } else {
862 KRect::new(both.x0, start.max(both.y0), both.x1, both.y1)
863 };
864 if r.width() > 0.0 && r.height() > 0.0 {
865 damage.push(r);
866 }
867 }
868 }
869 }
870}
871
872impl Renderer {
873 #[allow(clippy::too_many_arguments)]
878 fn sync_free(
879 &mut self,
880 d: &mut Drawing,
881 w: &mut Walk,
882 node: &Node,
883 order: &Order,
884 owner: Owner,
885 id: NodeId,
886 rid: u32,
887 down: &Down,
888 all: bool,
889 on_path: &BTreeSet<OrderKey>,
890 is_new: bool,
891 ) {
892 let drid = match d.shown.get(&rid) {
893 Some(&r) => r,
894 None => {
895 let r = d.list.add_run(down.space.clone());
896 d.shown.insert(rid, r);
897 r
898 }
899 };
900 let local = |v: (f32, f32)| (v.0 - down.space_at.x as f32, v.1 - down.space_at.y as f32);
901 {
902 let dr = d.list.run_mut(drid);
903 dr.free = true;
904 let (raw, at) = (local(down.place.raw), local(down.place.at));
905 dr.raw = Vec2::new(raw.0 as f64, raw.1 as f64);
906 dr.at = Vec2::new(at.0 as f64, at.1 as f64);
907 dr.origin = down.space_at;
908 dr.cut = down.cut;
909 }
910 d.list.resum(drid);
911 d.contexts.insert(
912 drid,
913 RunContext {
914 order: order.clone(),
915 owner,
916 id,
917 rid,
918 transform: down.transform,
919 place: Place {
920 at: local(down.place.at),
921 raw: local(down.place.raw),
922 },
923 space: down.space.clone(),
924 clip: down.clip,
925 effect: down.effect,
926 align: crate::scene::Align::Start,
927 },
928 );
929 let relaid = std::mem::take(&mut d.laid.runs.get_mut(rid).relaid);
930 let keys: Vec<OrderKey> = if all || is_new {
931 node.children.entries().map(|(k, _)| k.clone()).collect()
932 } else {
933 on_path.union(&relaid).cloned().collect()
934 };
935 for k in keys {
936 if node.children.get(&k).is_none() {
937 continue;
938 }
939 self.free_item(d, w, node, order, rid, drid, &k, down, all);
940 }
941 d.list.flush();
942 }
943
944 #[allow(clippy::too_many_arguments)]
947 fn free_item(
948 &mut self,
949 d: &mut Drawing,
950 w: &mut Walk,
951 node: &Node,
952 order: &Order,
953 rid: u32,
954 drid: RunId,
955 k: &OrderKey,
956 down: &Down,
957 all: bool,
958 ) {
959 let child = node.children.get(k).expect("a child");
960 self.relay_free(&mut d.laid.runs, rid, k);
961 let child_node = d.laid.runs.get(rid).children[k].node;
962 let (abs, _) = placed(d.laid.tree(Owner::Run(rid)), child_node, down.place, false);
963 let l = *d.laid.tree(Owner::Run(rid)).unrounded_layout(child_node);
964 let item_at = Vec2::new(abs.x as f64, abs.y as f64);
965 let mut o = order.clone();
966 o.push(k.clone());
967 self.sync(
968 d,
969 w,
970 child,
971 o,
972 Owner::Run(rid),
973 child_node,
974 down.transform,
975 down.place,
976 (&Space::Item(drid, k.clone()), item_at),
977 down.clip,
978 None,
979 down.effect,
980 (down.remade, all),
981 Some((drid, k.clone())),
982 );
983 let at = Vec2::new(l.location.x as f64, l.location.y as f64);
984 let delta = {
985 let (raw, rounded) = d.list.run(drid).place_at(at);
986 rounded - raw
987 };
988 d.list
989 .place_child(drid, k.clone(), Some(Placed::at(at, delta)));
990 }
991
992 pub(super) fn reround(&mut self, d: &mut Drawing, scene: &Scene, drid: RunId, key: &OrderKey) {
996 let Some(ctx) = d.contexts.get(&drid).cloned() else {
997 return;
998 };
999 let space_at = d.list.space_at(&ctx.space);
1000 let abs = |v: (f32, f32)| (v.0 + space_at.x as f32, v.1 + space_at.y as f32);
1001 let place = Place {
1002 at: abs(ctx.place.at),
1003 raw: abs(ctx.place.raw),
1004 };
1005 if d.laid.runs.get(ctx.rid).free {
1006 let Some(node) = scene.at(&ctx.order) else {
1007 return;
1008 };
1009 let mut walk = Walk {
1010 scene,
1011 dirty: &|_| false,
1012 relaid: &|_| false,
1013 path: None,
1014 damage: None,
1015 fresh: None,
1016 images: false,
1017 };
1018 let down = Down {
1019 transform: ctx.transform,
1020 place,
1021 space: &ctx.space,
1022 space_at,
1023 clip: ctx.clip,
1024 cut: None,
1025 effect: ctx.effect,
1026 remade: false,
1027 };
1028 self.blobs = std::mem::take(&mut d.blobs);
1029 self.free_item(
1030 d, &mut walk, node, &ctx.order, ctx.rid, drid, key, &down, true,
1031 );
1032 d.blobs = std::mem::take(&mut self.blobs);
1033 if walk.images {
1034 let _ = self.settle_images(d);
1035 }
1036 return;
1037 }
1038 let size = d.laid.tree(ctx.owner).unrounded_layout(ctx.id).size;
1039 let Some((run, asked, lead, _)) = d.laid.run_places(ctx.rid, size) else {
1040 return;
1041 };
1042 let line = asked.line;
1043 let Some(s) = run.size_of(asked, key) else {
1044 return;
1045 };
1046 let offset = run.across(line, &s, run.children[key].stretch) as f64;
1047 let (pc0, _) = run.padding_across();
1048 let (row, child_node) = (run.row, run.children[key].node);
1049 self.relay(&mut d.laid.runs, ctx.rid, key, line);
1050 let before = d.list.run(drid).prefix(key);
1051 let item = child_place(place, row, lead as f64 + before, pc0 as f64 + offset);
1052 let item_at = Vec2::new(item.at.0 as f64, item.at.1 as f64);
1053 let mut order = ctx.order.clone();
1054 order.push(key.clone());
1055 let Some(node) = scene.at(&order) else {
1056 return;
1057 };
1058 let mut walk = Walk {
1059 scene,
1060 dirty: &|_| false,
1061 relaid: &|_| false,
1062 path: None,
1063 damage: None,
1064 fresh: None,
1065 images: false,
1066 };
1067 self.blobs = std::mem::take(&mut d.blobs);
1068 self.sync(
1069 d,
1070 &mut walk,
1071 node,
1072 order,
1073 Owner::Run(ctx.rid),
1074 child_node,
1075 ctx.transform,
1076 item,
1077 (&Space::Item(drid, key.clone()), item_at),
1078 ctx.clip,
1079 None,
1080 ctx.effect,
1081 (false, true),
1082 Some((drid, key.clone())),
1083 );
1084 d.blobs = std::mem::take(&mut self.blobs);
1085 let delta = {
1086 let (raw, at) = d.list.run(drid).place(before, offset);
1087 at - raw
1088 };
1089 d.list.place_child(
1090 drid,
1091 key.clone(),
1092 Some(Placed::new(s.along as f64, offset, delta)),
1093 );
1094 if walk.images {
1095 let _ = self.settle_images(d);
1096 }
1097 }
1098}
1099
1100#[derive(Clone)]
1104pub(super) struct RunContext {
1105 pub(super) order: Order,
1106 pub(super) owner: Owner,
1107 pub(super) id: NodeId,
1108 pub(super) rid: u32,
1109 pub(super) transform: Id,
1110 pub(super) place: Place,
1111 pub(super) space: Space,
1112 pub(super) clip: Id,
1113 pub(super) effect: Option<Id>,
1114 pub(super) align: crate::scene::Align,
1116}
1117
1118pub(super) struct Down<'a> {
1120 pub(super) transform: Id,
1121 pub(super) place: Place,
1122 pub(super) space: &'a Space,
1123 pub(super) space_at: Vec2,
1124 pub(super) clip: Id,
1125 pub(super) cut: Option<KRect>,
1126 pub(super) effect: Option<Id>,
1127 pub(super) remade: bool,
1128}
1129
1130pub(super) struct Walk<'a> {
1132 pub(super) scene: &'a Scene,
1133 pub(super) dirty: &'a dyn Fn(&Order) -> bool,
1135 pub(super) relaid: &'a dyn Fn(&Order) -> bool,
1138 pub(super) path: Option<&'a HashMap<Order, BTreeSet<OrderKey>>>,
1143 pub(super) damage: Option<&'a mut Vec<KRect>>,
1144 pub(super) fresh: Option<&'a mut Vec<(Order, Chunk)>>,
1146 pub(super) images: bool,
1148}
1149
1150pub(super) fn swap(commands: &mut [crate::display::Command], last_of: &HashMap<u64, ImageData>) {
1152 for c in commands {
1153 if let Draw::Fill(_, Paint::Image(data, _)) = &mut c.draw
1154 && let Some(old) = last_of.get(&data.data.id())
1155 {
1156 *data = old.clone();
1157 }
1158 }
1159}
1160
1161#[cfg(test)]
1162mod tests;