cranpose_render_common/
raster_cache.rs1use cranpose_core::NodeId;
2use cranpose_ui_graphics::Rect;
3
4const SCALE_BUCKET_STEPS: f32 = 256.0;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7pub struct ScaleBucket(u32);
8
9impl ScaleBucket {
10 pub fn from_scale(scale: f32) -> Self {
11 let normalized = if scale.is_finite() && scale > 0.0 {
12 scale
13 } else {
14 1.0
15 };
16 Self((normalized * SCALE_BUCKET_STEPS).round().max(1.0) as u32)
17 }
18
19 pub fn raw(self) -> u32 {
20 self.0
21 }
22}
23
24#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
25pub struct LayerRasterCacheHashes {
26 pub target_content: u64,
27 pub effect: u64,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31pub struct LayerRasterCacheKey {
32 stable_id: Option<NodeId>,
33 content_hash: u64,
34 effect_hash: u64,
35 local_bounds_bits: [u32; 4],
36 pixel_size: [u32; 2],
37 scale_bucket: ScaleBucket,
38}
39
40impl LayerRasterCacheKey {
41 pub fn new(
42 stable_id: Option<NodeId>,
43 content_hash: u64,
44 effect_hash: u64,
45 local_bounds: Rect,
46 pixel_size: (u32, u32),
47 scale_bucket: ScaleBucket,
48 ) -> Self {
49 Self {
50 stable_id,
51 content_hash,
52 effect_hash,
53 local_bounds_bits: [
54 local_bounds.x.to_bits(),
55 local_bounds.y.to_bits(),
56 local_bounds.width.to_bits(),
57 local_bounds.height.to_bits(),
58 ],
59 pixel_size: [pixel_size.0, pixel_size.1],
60 scale_bucket,
61 }
62 }
63
64 pub fn stable_id(self) -> Option<NodeId> {
65 self.stable_id
66 }
67
68 pub fn pixel_size(self) -> (u32, u32) {
69 (self.pixel_size[0], self.pixel_size[1])
70 }
71
72 pub fn scale_bucket(self) -> ScaleBucket {
73 self.scale_bucket
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn scale_bucket_normalizes_invalid_values() {
83 assert_eq!(
84 ScaleBucket::from_scale(0.0).raw(),
85 ScaleBucket::from_scale(1.0).raw()
86 );
87 assert_eq!(
88 ScaleBucket::from_scale(-3.0).raw(),
89 ScaleBucket::from_scale(1.0).raw()
90 );
91 assert_eq!(
92 ScaleBucket::from_scale(f32::NAN).raw(),
93 ScaleBucket::from_scale(1.0).raw()
94 );
95 }
96
97 #[test]
98 fn scale_bucket_quantizes_small_fractional_changes() {
99 let a = ScaleBucket::from_scale(1.0);
100 let b = ScaleBucket::from_scale(1.001);
101 let c = ScaleBucket::from_scale(1.01);
102 assert_eq!(a, b);
103 assert_ne!(a, c);
104 }
105
106 #[test]
107 fn layer_raster_cache_key_captures_bounds_and_pixel_size() {
108 let rect = Rect {
109 x: 1.0,
110 y: 2.0,
111 width: 30.0,
112 height: 40.0,
113 };
114 let base = LayerRasterCacheKey::new(
115 Some(7),
116 11,
117 13,
118 rect,
119 (30, 40),
120 ScaleBucket::from_scale(1.0),
121 );
122 let moved = LayerRasterCacheKey::new(
123 Some(7),
124 11,
125 13,
126 Rect { x: 2.0, ..rect },
127 (30, 40),
128 ScaleBucket::from_scale(1.0),
129 );
130 let resized = LayerRasterCacheKey::new(
131 Some(7),
132 11,
133 13,
134 rect,
135 (60, 80),
136 ScaleBucket::from_scale(2.0),
137 );
138
139 assert_ne!(base, moved);
140 assert_ne!(base, resized);
141 assert_eq!(base.stable_id(), Some(7));
142 assert_eq!(base.pixel_size(), (30, 40));
143 }
144}