1use core::num::{NonZeroU16, NonZeroUsize};
2
3use anyhow::Result;
4use bytes::{Bytes, BytesMut};
5use ironrdp_displaycontrol::pdu::DisplayControlMonitorLayout;
6use ironrdp_graphics::diff;
7use ironrdp_pdu::pointer::PointerPositionAttribute;
8use tracing::{debug, warn};
9
10#[rustfmt::skip]
11pub use ironrdp_acceptor::DesktopSize;
12pub use ironrdp_graphics::image_processing::PixelFormat;
13
14#[derive(Debug, Clone)]
20pub enum DisplayUpdate {
21 Resize(DesktopSize),
22 Bitmap(BitmapUpdate),
23 PointerPosition(PointerPositionAttribute),
24 ColorPointer(ColorPointer),
25 RGBAPointer(RGBAPointer),
26 HidePointer,
27 DefaultPointer,
28}
29
30#[derive(Clone)]
31pub struct RGBAPointer {
32 pub width: u16,
33 pub height: u16,
34 pub hot_x: u16,
35 pub hot_y: u16,
36 pub data: Vec<u8>,
37}
38
39impl core::fmt::Debug for RGBAPointer {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 f.debug_struct("RGBAPointer")
42 .field("with", &self.width)
43 .field("height", &self.height)
44 .field("hot_x", &self.hot_x)
45 .field("hot_y", &self.hot_y)
46 .field("data_len", &self.data.len())
47 .finish()
48 }
49}
50
51#[derive(Debug, Clone)]
52pub struct ColorPointer {
53 pub width: u16,
54 pub height: u16,
55 pub hot_x: u16,
56 pub hot_y: u16,
57 pub and_mask: Vec<u8>,
58 pub xor_mask: Vec<u8>,
59}
60
61pub struct Framebuffer {
62 pub width: NonZeroU16,
63 pub height: NonZeroU16,
64 pub format: PixelFormat,
65 pub data: BytesMut,
66 pub stride: usize,
67}
68
69impl TryInto<Framebuffer> for BitmapUpdate {
70 type Error = &'static str;
71
72 fn try_into(self) -> Result<Framebuffer, Self::Error> {
73 assert_eq!(self.x, 0);
74 assert_eq!(self.y, 0);
75 Ok(Framebuffer {
76 width: self.width,
77 height: self.height,
78 format: self.format,
79 data: self.data.into(),
80 stride: self.stride.get(),
81 })
82 }
83}
84
85impl Framebuffer {
86 pub fn new(width: NonZeroU16, height: NonZeroU16, format: PixelFormat) -> Self {
87 let mut data = BytesMut::new();
88 let w = NonZeroUsize::from(width).get();
89 let h = NonZeroUsize::from(height).get();
90 let bpp = usize::from(format.bytes_per_pixel());
91 data.resize(bpp * w * h, 0);
92
93 Self {
94 width,
95 height,
96 format,
97 data,
98 stride: bpp * w,
99 }
100 }
101
102 pub fn update(&mut self, bitmap: &BitmapUpdate) {
103 if self.format != bitmap.format {
104 warn!("Bitmap format mismatch, unsupported");
105 return;
106 }
107 let bpp = usize::from(self.format.bytes_per_pixel());
108 let x = usize::from(bitmap.x);
109 let y = usize::from(bitmap.y);
110 let width = NonZeroUsize::from(bitmap.width).get();
111 let height = NonZeroUsize::from(bitmap.height).get();
112
113 let data = &mut self.data;
114 let start = y * self.stride + x * bpp;
115 let end = start + (height - 1) * self.stride + width * bpp;
116 let dst = &mut data[start..end];
117
118 for y in 0..height {
119 let start = y * bitmap.stride.get();
120 let end = start + width * bpp;
121
122 let src = bitmap.data.slice(start..end);
123
124 let start = y * self.stride;
125 let end = start + width * bpp;
126 let dst = &mut dst[start..end];
127
128 dst.copy_from_slice(&src);
129 }
130 }
131
132 pub(crate) fn update_diffs(&mut self, bitmap: &BitmapUpdate, diffs: &[diff::Rect]) {
133 diffs
134 .iter()
135 .filter_map(|diff| {
136 let x = u16::try_from(diff.x).ok()?;
137 let y = u16::try_from(diff.y).ok()?;
138 let width = u16::try_from(diff.width).ok().and_then(NonZeroU16::new)?;
139 let height = u16::try_from(diff.height).ok().and_then(NonZeroU16::new)?;
140
141 bitmap.sub(x, y, width, height)
142 })
143 .for_each(|sub| self.update(&sub));
144 }
145}
146
147#[derive(Clone)]
153pub struct BitmapUpdate {
154 pub x: u16,
155 pub y: u16,
156 pub width: NonZeroU16,
157 pub height: NonZeroU16,
158 pub format: PixelFormat,
159 pub data: Bytes,
160 pub stride: NonZeroUsize,
161}
162
163impl BitmapUpdate {
164 #[must_use]
200 pub fn sub(&self, x: u16, y: u16, width: NonZeroU16, height: NonZeroU16) -> Option<Self> {
201 if x + width.get() > self.width.get() || y + height.get() > self.height.get() {
202 None
203 } else {
204 let bpp = usize::from(self.format.bytes_per_pixel());
205 let start = usize::from(y) * self.stride.get() + usize::from(x) * bpp;
206 let end = start + usize::from(height.get() - 1) * self.stride.get() + usize::from(width.get()) * bpp;
207 Some(Self {
208 x: self.x + x,
209 y: self.y + y,
210 width,
211 height,
212 format: self.format,
213 data: self.data.slice(start..end),
214 stride: self.stride,
215 })
216 }
217 }
218}
219
220impl core::fmt::Debug for BitmapUpdate {
221 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222 f.debug_struct("BitmapUpdate")
223 .field("x", &self.x)
224 .field("y", &self.y)
225 .field("width", &self.width)
226 .field("height", &self.height)
227 .field("format", &self.format)
228 .field("stride", &self.stride)
229 .finish()
230 }
231}
232
233#[async_trait::async_trait]
240pub trait RdpServerDisplayUpdates {
241 async fn next_update(&mut self) -> Result<Option<DisplayUpdate>>;
247}
248
249#[async_trait::async_trait]
285pub trait RdpServerDisplay: Send {
286 async fn size(&mut self) -> DesktopSize;
290
291 async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>>;
293
294 fn request_layout(&mut self, layout: DisplayControlMonitorLayout) {
296 debug!(?layout, "Requesting layout")
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use core::num::{NonZeroU16, NonZeroUsize};
303
304 use ironrdp_graphics::diff::Rect;
305 use ironrdp_graphics::image_processing::PixelFormat;
306
307 use super::{BitmapUpdate, Framebuffer};
308
309 #[test]
310 fn framebuffer_update() {
311 let width = NonZeroU16::new(800).unwrap();
312 let height = NonZeroU16::new(600).unwrap();
313 let fmt = PixelFormat::ABgr32;
314 let bpp = usize::from(fmt.bytes_per_pixel());
315 let mut fb = Framebuffer::new(width, height, fmt);
316
317 let width = 15;
318 let stride = NonZeroUsize::new(width * bpp).unwrap();
319 let height = 20;
320 let data = vec![1u8; height * stride.get()];
321 let update = BitmapUpdate {
322 x: 1,
323 y: 2,
324 width: NonZeroU16::new(15).unwrap(),
325 height: NonZeroU16::new(20).unwrap(),
326 format: fmt,
327 data: data.into(),
328 stride,
329 };
330 let diffs = vec![Rect::new(2, 3, 4, 5)];
331 fb.update_diffs(&update, &diffs);
332 let data = fb.data;
333 for y in 5..10 {
334 for x in 3..7 {
335 for b in 0..bpp {
336 assert_eq!(data[y * fb.stride + x * bpp + b], 1);
337 }
338 }
339 }
340 }
341}