Skip to main content

devpage_design/display/
paint.rs

1//! The one paint entry point: an area of the list at a scale into a
2//! [`Target`] — the port both backends adapt — opening and closing exactly
3//! the layers each command's property state needs.
4
5use kurbo::{Affine, BezPath, Rect as KRect};
6
7use crate::render::Draw;
8
9use super::*;
10
11/// What a backend does with the commands [`paint`] hands it, each already
12/// under the transform from its coordinates to the target's pixels. A
13/// backend translates each into its library's call and decides nothing.
14pub trait Target {
15    fn draw(&mut self, draw: &Draw, t: Affine);
16    fn push_clip(&mut self, path: &BezPath, t: Affine);
17    /// A layer with `blend`, bounded by `bounds` under `t` — or, when
18    /// `None`, by `area`, the whole of what is painted, in the target's
19    /// pixels.
20    fn push_layer(&mut self, blend: Blend, bounds: Option<&BezPath>, t: Affine, area: KRect);
21    fn pop(&mut self);
22}
23
24#[derive(Clone, Copy, PartialEq, Debug)]
25pub(super) enum Layer {
26    Clip(Id),
27    Effect(Id),
28}
29
30/// The engine's one paint entry point: `area` of the list — in the design's
31/// coordinates — at `scale` device pixels per design pixel into `target`,
32/// whose top-left is the area's. The commands that touch it, in paint order,
33/// each under exactly the layers its property state needs.
34pub fn paint(list: &List, area: KRect, scale: f64, target: &mut impl Target) {
35    let view = Affine::scale(scale) * Affine::translate((-area.x0, -area.y0));
36    let pixels = KRect::new(0.0, 0.0, area.width() * scale, area.height() * scale);
37    let mut open: Vec<Layer> = Vec::new();
38    let place = |transform: Id| view * Affine::translate(list.world(transform));
39    for (origin, _, command) in list.query(area, 1.0 / scale) {
40        let want = layers(list, command.clip, command.effect);
41        let keep = open.iter().zip(&want).take_while(|(a, b)| a == b).count();
42        while open.len() > keep {
43            open.pop();
44            target.pop();
45        }
46        for layer in &want[keep..] {
47            match *layer {
48                Layer::Clip(id) => {
49                    let c = list.trees.clips.get(id);
50                    target.push_clip(&c.path, place(c.transform));
51                }
52                Layer::Effect(id) => {
53                    let e = list.trees.effects.get(id);
54                    target.push_layer(e.blend, e.bounds.as_ref(), place(e.transform), pixels);
55                }
56            }
57            open.push(*layer);
58        }
59        target.draw(&command.draw, view * Affine::translate(origin));
60    }
61    for _ in open {
62        target.pop();
63    }
64}
65
66/// The layers a command under `clip` and `effect` is drawn in, outermost
67/// first: each effect from the root down, inside its own clip, then the
68/// command's clips inside the innermost effect.
69pub(super) fn layers(list: &List, clip: Id, effect: Option<Id>) -> Vec<Layer> {
70    let mut effects = Vec::new();
71    let mut at = effect;
72    while let Some(e) = at {
73        effects.push(e);
74        at = list.trees.effects.get(e).parent;
75    }
76    effects.reverse();
77    let mut out = Vec::new();
78    let mut inside: Option<Id> = None;
79    for e in effects {
80        let to = list.trees.effects.get(e).clip;
81        clips(list, inside, to, &mut out);
82        out.push(Layer::Effect(e));
83        inside = Some(to);
84    }
85    clips(list, inside, clip, &mut out);
86    out
87}
88
89/// The clips from just below `from` down to `to`, outermost first.
90pub(super) fn clips(list: &List, from: Option<Id>, to: Id, out: &mut Vec<Layer>) {
91    let mut chain = Vec::new();
92    let mut at = Some(to);
93    while let Some(c) = at {
94        if Some(c) == from {
95            break;
96        }
97        chain.push(Layer::Clip(c));
98        at = list.trees.clips.get(c).parent;
99    }
100    out.extend(chain.into_iter().rev());
101}