1use super::*;
2
3pub struct Canvas<'a> {
4 pub(in crate::wayland) pixels: &'a mut [u8],
5 pub(in crate::wayland) width: u32,
6 pub(in crate::wayland) height: u32,
7 pub(in crate::wayland) stride: u32,
8 pub(in crate::wayland) scale: u32,
9 pub(in crate::wayland) damage: Option<DamageRect>,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct DamageRect {
14 pub x: u32,
15 pub y: u32,
16 pub width: u32,
17 pub height: u32,
18}
19
20impl<'a> Canvas<'a> {
21 pub fn from_bgra_pixels(
22 pixels: &'a mut [u8],
23 width: u32,
24 height: u32,
25 stride: u32,
26 scale: u32,
27 ) -> Option<Self> {
28 if stride < width.checked_mul(4)? {
29 return None;
30 }
31 let required = if height == 0 {
32 0
33 } else {
34 stride
35 .checked_mul(height.saturating_sub(1))?
36 .checked_add(width.checked_mul(4)?)?
37 };
38 if pixels.len() < required as usize {
39 return None;
40 }
41
42 Some(Self {
43 pixels,
44 width,
45 height,
46 stride,
47 scale: scale.max(1),
48 damage: None,
49 })
50 }
51
52 pub fn pixels(&self) -> &[u8] {
53 self.pixels
54 }
55
56 pub fn pixels_mut(&mut self) -> &mut [u8] {
57 self.damage_all();
58 self.pixels
59 }
60
61 pub fn width(&self) -> u32 {
62 self.width
63 }
64
65 pub fn height(&self) -> u32 {
66 self.height
67 }
68
69 pub fn stride(&self) -> u32 {
70 self.stride
71 }
72
73 pub fn scale(&self) -> u32 {
74 self.scale
75 }
76
77 pub fn clear(&mut self, rgba: [u8; 4]) {
78 let bgra = rgba_to_bgra(rgba);
79 for pixel in self.pixels.chunks_exact_mut(4) {
80 pixel.copy_from_slice(&bgra);
81 }
82 self.damage_all();
83 }
84
85 pub fn put_pixel(&mut self, x: u32, y: u32, rgba: [u8; 4]) {
86 if x >= self.width || y >= self.height {
87 return;
88 }
89
90 let index = ((y * self.stride) + (x * 4)) as usize;
91 self.pixels[index..index + 4].copy_from_slice(&rgba_to_bgra(rgba));
92 self.damage_rect(DamageRect::new(x, y, 1, 1));
93 }
94
95 pub fn blend_pixel(&mut self, x: u32, y: u32, rgba: [u8; 4]) {
96 if x >= self.width || y >= self.height || rgba[3] == 0 {
97 return;
98 }
99
100 let index = ((y * self.stride) + (x * 4)) as usize;
101 let background = bgra_to_rgba([
102 self.pixels[index],
103 self.pixels[index + 1],
104 self.pixels[index + 2],
105 self.pixels[index + 3],
106 ]);
107 self.pixels[index..index + 4].copy_from_slice(&rgba_to_bgra(blend_color(background, rgba)));
108 self.damage_rect(DamageRect::new(x, y, 1, 1));
109 }
110
111 pub fn damage(&self) -> Option<DamageRect> {
112 self.damage
113 }
114
115 pub fn damage_rect(&mut self, rect: DamageRect) {
116 let Some(rect) = rect.clamp(self.width, self.height) else {
117 return;
118 };
119 self.damage = Some(match self.damage {
120 Some(damage) => damage.union(rect),
121 None => rect,
122 });
123 }
124
125 pub fn damage_all(&mut self) {
126 self.damage_rect(DamageRect::new(0, 0, self.width, self.height));
127 }
128}
129
130impl fmt::Debug for Canvas<'_> {
131 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
132 formatter
133 .debug_struct("Canvas")
134 .field("width", &self.width)
135 .field("height", &self.height)
136 .field("stride", &self.stride)
137 .finish_non_exhaustive()
138 }
139}
140
141impl DamageRect {
142 pub const fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
143 Self {
144 x,
145 y,
146 width,
147 height,
148 }
149 }
150
151 fn right(self) -> u32 {
152 self.x.saturating_add(self.width)
153 }
154
155 fn bottom(self) -> u32 {
156 self.y.saturating_add(self.height)
157 }
158
159 fn union(self, other: Self) -> Self {
160 let x = self.x.min(other.x);
161 let y = self.y.min(other.y);
162 let right = self.right().max(other.right());
163 let bottom = self.bottom().max(other.bottom());
164 Self {
165 x,
166 y,
167 width: right.saturating_sub(x),
168 height: bottom.saturating_sub(y),
169 }
170 }
171
172 fn clamp(self, width: u32, height: u32) -> Option<Self> {
173 let x = self.x.min(width);
174 let y = self.y.min(height);
175 let right = self.right().min(width);
176 let bottom = self.bottom().min(height);
177 let width = right.saturating_sub(x);
178 let height = bottom.saturating_sub(y);
179 (width > 0 && height > 0).then_some(Self {
180 x,
181 y,
182 width,
183 height,
184 })
185 }
186}
187
188fn rgba_to_bgra([red, green, blue, alpha]: [u8; 4]) -> [u8; 4] {
189 [blue, green, red, alpha]
190}
191
192fn bgra_to_rgba([blue, green, red, alpha]: [u8; 4]) -> [u8; 4] {
193 [red, green, blue, alpha]
194}
195
196pub(in crate::wayland) fn blend_color(background: [u8; 4], foreground: [u8; 4]) -> [u8; 4] {
197 let foreground_alpha = u32::from(foreground[3]);
198 if foreground_alpha == 0 {
199 return background;
200 }
201 if foreground_alpha == 255 {
202 return foreground;
203 }
204
205 let background_alpha = u32::from(background[3]);
206 let inverse_foreground_alpha = 255 - foreground_alpha;
207 let output_alpha = foreground_alpha + background_alpha * inverse_foreground_alpha / 255;
208 if output_alpha == 0 {
209 return [0, 0, 0, 0];
210 }
211
212 let blend_component = |foreground: u8, background: u8| {
213 let foreground = u32::from(foreground) * foreground_alpha;
214 let background = u32::from(background) * background_alpha * inverse_foreground_alpha / 255;
215 ((foreground + background) / output_alpha).min(255) as u8
216 };
217
218 [
219 blend_component(foreground[0], background[0]),
220 blend_component(foreground[1], background[1]),
221 blend_component(foreground[2], background[2]),
222 output_alpha.min(255) as u8,
223 ]
224}