cranpose_render_common/graph/inline_node.rs
1// A layout node drawn in its parent's layer.
2
3use std::cell::Cell;
4
5use cranpose_core::NodeId;
6use cranpose_ui::{Point, Rect, Size};
7
8use super::{
9 CONTAINED_DRAW_SLACK, LayerChange, ProjectiveTransform, RenderNode, inflate_rect,
10 nodes_draw_within, rect_within,
11};
12
13/// A layout node drawn into its parent's layer instead of a layer of its
14/// own, as Compose draws a node without a graphics layer into the display
15/// list of the layer above it: a leaf with no layer properties, pointer
16/// handling or window origins to publish. The scene matches it with its
17/// node as it matches a child layer, and a renderer places its content as it
18/// would place a child layer that only moves.
19#[derive(Clone, Default)]
20pub struct InlineNode {
21 /// Layout node drawn here.
22 pub node_id: NodeId,
23 /// The node's top left in its parent's layer: its placement and the
24 /// parent's content offset, where a layer of its own would lie.
25 pub origin: Point,
26 /// The node's size: its rect in its own space starts at the origin.
27 pub size: Size,
28 /// Whether the node lies in a motion context such as an animated scroll,
29 /// where a renderer must not snap its content rigidly to the pixel grid.
30 pub motion_context_animated: bool,
31 /// The number the node took when it last changed.
32 pub change: LayerChange,
33 /// The node's draws and text in draw order, in its own space: primitives
34 /// and draw runs only.
35 pub content: Vec<RenderNode>,
36 contained: Cell<Option<bool>>,
37 content_hash: Cell<Option<u64>>,
38}
39
40impl InlineNode {
41 /// The node's rect in its own space.
42 pub fn node_rect(&self) -> Rect {
43 Rect::from_size(self.size)
44 }
45
46 /// Maps the node's space to its parent layer's: a translation to
47 /// [`Self::origin`].
48 pub fn transform_to_parent(&self) -> ProjectiveTransform {
49 ProjectiveTransform::translation(self.origin.x, self.origin.y)
50 }
51
52 /// Whether everything the node draws lies within its rect, give or take
53 /// [`CONTAINED_DRAW_SLACK`], as [`super::LayerNode::draws_within_bounds`]
54 /// says of a layer. Worked out at the first call after a change.
55 pub fn draws_within_bounds(&self) -> bool {
56 if let Some(contained) = self.contained.get() {
57 return contained;
58 }
59 let contained = nodes_draw_within(
60 &self.content,
61 inflate_rect(self.node_rect(), CONTAINED_DRAW_SLACK),
62 );
63 self.contained.set(Some(contained));
64 contained
65 }
66
67 // Whether the node puts nothing outside `bounds` of its parent's layer.
68 pub(crate) fn draws_within_parent(&self, bounds: Rect) -> bool {
69 self.draws_within_bounds()
70 && rect_within(
71 inflate_rect(self.node_rect(), CONTAINED_DRAW_SLACK)
72 .translate(self.origin.x, self.origin.y),
73 bounds,
74 )
75 }
76
77 // The hash of the node's content, worked out at the first call after a
78 // change: a layer above it hashes its own content again whenever it
79 // changes, as it reads a child layer's kept hash.
80 pub(crate) fn content_hash(&self) -> u64 {
81 if let Some(hash) = self.content_hash.get() {
82 return hash;
83 }
84 let hash = crate::graph_hash::inline_content_hash(self);
85 self.content_hash.set(Some(hash));
86 hash
87 }
88
89 // Takes a new change number after the node's content or place changed.
90 pub(crate) fn note_change(&mut self) {
91 self.change = LayerChange::next();
92 self.contained.set(None);
93 self.content_hash.set(None);
94 }
95}