Use u32/NonZeroU32 for Rect, and return error if out of range
This commit is contained in:
parent
199a016f44
commit
a147a15d45
6 changed files with 129 additions and 136 deletions
|
|
@ -36,6 +36,11 @@ pub enum SoftBufferError {
|
||||||
height: NonZeroU32,
|
height: NonZeroU32,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error(
|
||||||
|
"Damage rect {}x{} at ({}, {}) out of range for backend.", .rect.width, .rect.height, .rect.x, .rect.y,
|
||||||
|
)]
|
||||||
|
DamageOutOfRange { rect: crate::Rect },
|
||||||
|
|
||||||
#[error("Platform error")]
|
#[error("Platform error")]
|
||||||
PlatformError(Option<String>, Option<Box<dyn Error>>),
|
PlatformError(Option<String>, Option<Box<dyn Error>>),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,13 +233,13 @@ impl Context {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
/// x coordinate of top left corner
|
/// x coordinate of top left corner
|
||||||
pub x: i32,
|
pub x: u32,
|
||||||
/// y coordinate of top left corner
|
/// y coordinate of top left corner
|
||||||
pub y: i32,
|
pub y: u32,
|
||||||
/// width
|
/// width
|
||||||
pub width: i32,
|
pub width: NonZeroU32,
|
||||||
/// height
|
/// height
|
||||||
pub height: i32,
|
pub height: NonZeroU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A surface for drawing to a window with software buffers.
|
/// A surface for drawing to a window with software buffers.
|
||||||
|
|
|
||||||
|
|
@ -159,15 +159,18 @@ impl WaylandImpl {
|
||||||
if self.surface.version() < 4 {
|
if self.surface.version() < 4 {
|
||||||
self.surface.damage(0, 0, i32::MAX, i32::MAX);
|
self.surface.damage(0, 0, i32::MAX, i32::MAX);
|
||||||
} else {
|
} else {
|
||||||
for Rect {
|
for rect in damage {
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} in damage
|
|
||||||
{
|
|
||||||
// Introduced in version 4, it is an error to use this request in version 3 or lower.
|
// Introduced in version 4, it is an error to use this request in version 3 or lower.
|
||||||
self.surface.damage_buffer(*x, *y, *width, *height);
|
let (x, y, width, height) = (|| {
|
||||||
|
Some((
|
||||||
|
i32::try_from(rect.x).ok()?,
|
||||||
|
i32::try_from(rect.y).ok()?,
|
||||||
|
i32::try_from(rect.width.get()).ok()?,
|
||||||
|
i32::try_from(rect.height.get()).ok()?,
|
||||||
|
))
|
||||||
|
})()
|
||||||
|
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
|
||||||
|
self.surface.damage_buffer(x, y, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,8 +215,9 @@ impl<'a> BufferImpl<'a> {
|
||||||
imp.present_with_damage(&[Rect {
|
imp.present_with_damage(&[Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: width.get(),
|
// We know width/height will be non-negative
|
||||||
height: height.get(),
|
width: width.try_into().unwrap(),
|
||||||
|
height: height.try_into().unwrap(),
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
src/web.rs
65
src/web.rs
|
|
@ -45,11 +45,8 @@ pub struct WebImpl {
|
||||||
/// Buffer has been presented.
|
/// Buffer has been presented.
|
||||||
buffer_presented: bool,
|
buffer_presented: bool,
|
||||||
|
|
||||||
/// The current width of the canvas.
|
/// The current canvas width/height.
|
||||||
width: u32,
|
size: Option<(NonZeroU32, NonZeroU32)>,
|
||||||
|
|
||||||
/// The current height of the canvas.
|
|
||||||
height: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebImpl {
|
impl WebImpl {
|
||||||
|
|
@ -82,8 +79,7 @@ impl WebImpl {
|
||||||
ctx,
|
ctx,
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
buffer_presented: false,
|
buffer_presented: false,
|
||||||
width: 0,
|
size: None,
|
||||||
height: 0,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,16 +89,12 @@ impl WebImpl {
|
||||||
width: NonZeroU32,
|
width: NonZeroU32,
|
||||||
height: NonZeroU32,
|
height: NonZeroU32,
|
||||||
) -> Result<(), SoftBufferError> {
|
) -> Result<(), SoftBufferError> {
|
||||||
let width = width.get();
|
if self.size != Some((width, height)) {
|
||||||
let height = height.get();
|
|
||||||
|
|
||||||
if width != self.width || height != self.height {
|
|
||||||
self.buffer_presented = false;
|
self.buffer_presented = false;
|
||||||
self.buffer.resize(total_len(width, height), 0);
|
self.buffer.resize(total_len(width.get(), height.get()), 0);
|
||||||
self.canvas.set_width(width);
|
self.canvas.set_width(width.get());
|
||||||
self.canvas.set_height(height);
|
self.canvas.set_height(height.get());
|
||||||
self.width = width;
|
self.size = Some((width, height));
|
||||||
self.height = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -114,6 +106,9 @@ impl WebImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
|
let (width, _height) = self
|
||||||
|
.size
|
||||||
|
.expect("Must set size of surface before calling `present_with_damage()`");
|
||||||
// Create a bitmap from the buffer.
|
// Create a bitmap from the buffer.
|
||||||
let bitmap: Vec<_> = self
|
let bitmap: Vec<_> = self
|
||||||
.buffer
|
.buffer
|
||||||
|
|
@ -140,33 +135,27 @@ impl WebImpl {
|
||||||
let array = Uint8Array::new_with_length(bitmap.len() as u32);
|
let array = Uint8Array::new_with_length(bitmap.len() as u32);
|
||||||
array.copy_from(&bitmap);
|
array.copy_from(&bitmap);
|
||||||
let array = Uint8ClampedArray::new(&array);
|
let array = Uint8ClampedArray::new(&array);
|
||||||
ImageDataExt::new(array, self.width)
|
ImageDataExt::new(array, width.get())
|
||||||
.map(JsValue::from)
|
.map(JsValue::from)
|
||||||
.map(ImageData::unchecked_from_js)
|
.map(ImageData::unchecked_from_js)
|
||||||
};
|
};
|
||||||
#[cfg(not(target_feature = "atomics"))]
|
#[cfg(not(target_feature = "atomics"))]
|
||||||
let result =
|
let result =
|
||||||
ImageData::new_with_u8_clamped_array(wasm_bindgen::Clamped(&bitmap), self.width);
|
ImageData::new_with_u8_clamped_array(wasm_bindgen::Clamped(&bitmap), width.get());
|
||||||
// This should only throw an error if the buffer we pass's size is incorrect.
|
// This should only throw an error if the buffer we pass's size is incorrect.
|
||||||
let image_data = result.unwrap();
|
let image_data = result.unwrap();
|
||||||
|
|
||||||
for Rect {
|
for rect in damage {
|
||||||
x,
|
|
||||||
y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} in damage
|
|
||||||
{
|
|
||||||
// This can only throw an error if `data` is detached, which is impossible.
|
// This can only throw an error if `data` is detached, which is impossible.
|
||||||
self.ctx
|
self.ctx
|
||||||
.put_image_data_with_dirty_x_and_dirty_y_and_dirty_width_and_dirty_height(
|
.put_image_data_with_dirty_x_and_dirty_y_and_dirty_width_and_dirty_height(
|
||||||
&image_data,
|
&image_data,
|
||||||
(*x).into(),
|
rect.x.into(),
|
||||||
(*y).into(),
|
rect.y.into(),
|
||||||
(*x).into(),
|
rect.x.into(),
|
||||||
(*y).into(),
|
rect.y.into(),
|
||||||
(*width).into(),
|
rect.width.get().into(),
|
||||||
(*height).into(),
|
rect.height.get().into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -217,16 +206,10 @@ impl<'a> BufferImpl<'a> {
|
||||||
|
|
||||||
/// Push the buffer to the canvas.
|
/// Push the buffer to the canvas.
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
let (width, height) = (|| {
|
let (width, height) = self
|
||||||
let width = i32::try_from(self.imp.width).ok()?;
|
.imp
|
||||||
let height = i32::try_from(self.imp.height).ok()?;
|
.size
|
||||||
Some((width, height))
|
.expect("Must set size of surface before calling `present()`");
|
||||||
})()
|
|
||||||
.ok_or(SoftBufferError::SizeOutOfRange {
|
|
||||||
width: NonZeroU32::new(self.imp.width).unwrap(),
|
|
||||||
height: NonZeroU32::new(self.imp.height).unwrap(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
self.imp.present_with_damage(&[Rect {
|
self.imp.present_with_damage(&[Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
|
|
||||||
34
src/win32.rs
34
src/win32.rs
|
|
@ -208,24 +208,17 @@ impl Win32Impl {
|
||||||
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
fn present_with_damage(&mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
let buffer = self.buffer.as_mut().unwrap();
|
let buffer = self.buffer.as_mut().unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
for Rect {
|
for rect in damage.iter().copied() {
|
||||||
x,
|
let (x, y, width, height) = (|| {
|
||||||
y,
|
Some((
|
||||||
width,
|
i32::try_from(rect.x).ok()?,
|
||||||
height,
|
i32::try_from(rect.y).ok()?,
|
||||||
} in damage
|
i32::try_from(rect.width.get()).ok()?,
|
||||||
{
|
i32::try_from(rect.height.get()).ok()?,
|
||||||
Gdi::BitBlt(
|
))
|
||||||
self.dc,
|
})()
|
||||||
*x,
|
.ok_or(SoftBufferError::DamageOutOfRange { rect })?;
|
||||||
*y,
|
Gdi::BitBlt(self.dc, x, y, width, height, buffer.dc, x, y, Gdi::SRCCOPY);
|
||||||
*width,
|
|
||||||
*height,
|
|
||||||
buffer.dc,
|
|
||||||
*x,
|
|
||||||
*y,
|
|
||||||
Gdi::SRCCOPY,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the window.
|
// Validate the window.
|
||||||
|
|
@ -263,8 +256,9 @@ impl<'a> BufferImpl<'a> {
|
||||||
imp.present_with_damage(&[Rect {
|
imp.present_with_damage(&[Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: buffer.width.get(),
|
// We know width/height will be non-negative
|
||||||
height: buffer.height.get(),
|
width: buffer.width.try_into().unwrap(),
|
||||||
|
height: buffer.height.try_into().unwrap(),
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
129
src/x11.rs
129
src/x11.rs
|
|
@ -10,7 +10,12 @@ use crate::{Rect, SoftBufferError};
|
||||||
use nix::libc::{shmat, shmctl, shmdt, shmget, IPC_PRIVATE, IPC_RMID};
|
use nix::libc::{shmat, shmctl, shmdt, shmget, IPC_PRIVATE, IPC_RMID};
|
||||||
use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle};
|
use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle};
|
||||||
use std::ptr::{null_mut, NonNull};
|
use std::ptr::{null_mut, NonNull};
|
||||||
use std::{fmt, io, mem, num::NonZeroU32, rc::Rc, slice};
|
use std::{
|
||||||
|
fmt, io, mem,
|
||||||
|
num::{NonZeroU16, NonZeroU32},
|
||||||
|
rc::Rc,
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
use x11_dl::xlib::Display;
|
use x11_dl::xlib::Display;
|
||||||
use x11_dl::xlib_xcb::Xlib_xcb;
|
use x11_dl::xlib_xcb::Xlib_xcb;
|
||||||
|
|
@ -110,11 +115,8 @@ pub struct X11Impl {
|
||||||
/// Buffer has been presented.
|
/// Buffer has been presented.
|
||||||
buffer_presented: bool,
|
buffer_presented: bool,
|
||||||
|
|
||||||
/// The current buffer width.
|
/// The current buffer width/height.
|
||||||
width: u16,
|
size: Option<(NonZeroU16, NonZeroU16)>,
|
||||||
|
|
||||||
/// The current buffer height.
|
|
||||||
height: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The buffer that is being drawn to.
|
/// The buffer that is being drawn to.
|
||||||
|
|
@ -227,8 +229,7 @@ impl X11Impl {
|
||||||
depth: geometry_reply.depth,
|
depth: geometry_reply.depth,
|
||||||
buffer,
|
buffer,
|
||||||
buffer_presented: false,
|
buffer_presented: false,
|
||||||
width: 0,
|
size: None,
|
||||||
height: 0,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,27 +247,22 @@ impl X11Impl {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Width and height should fit in u16.
|
// Width and height should fit in u16.
|
||||||
let width: u16 = width
|
let width: NonZeroU16 = width
|
||||||
.get()
|
|
||||||
.try_into()
|
.try_into()
|
||||||
.or(Err(SoftBufferError::SizeOutOfRange { width, height }))?;
|
.or(Err(SoftBufferError::SizeOutOfRange { width, height }))?;
|
||||||
let height: u16 = height
|
let height: NonZeroU16 = height.try_into().or(Err(SoftBufferError::SizeOutOfRange {
|
||||||
.get()
|
width: width.into(),
|
||||||
.try_into()
|
height,
|
||||||
.or(Err(SoftBufferError::SizeOutOfRange {
|
}))?;
|
||||||
width: NonZeroU32::new(width.into()).unwrap(),
|
|
||||||
height,
|
|
||||||
}))?;
|
|
||||||
|
|
||||||
if width != self.width || height != self.height {
|
if self.size != Some((width, height)) {
|
||||||
self.buffer_presented = false;
|
self.buffer_presented = false;
|
||||||
self.buffer
|
self.buffer
|
||||||
.resize(&self.display.connection, width, height)
|
.resize(&self.display.connection, width.get(), height.get())
|
||||||
.swbuf_err("Failed to resize X11 buffer")?;
|
.swbuf_err("Failed to resize X11 buffer")?;
|
||||||
|
|
||||||
// We successfully resized the buffer.
|
// We successfully resized the buffer.
|
||||||
self.width = width;
|
self.size = Some((width, height));
|
||||||
self.height = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -311,6 +307,10 @@ impl<'a> BufferImpl<'a> {
|
||||||
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
|
||||||
let imp = self.0;
|
let imp = self.0;
|
||||||
|
|
||||||
|
let (surface_width, surface_height) = imp
|
||||||
|
.size
|
||||||
|
.expect("Must set size of surface before calling `present_with_damage()`");
|
||||||
|
|
||||||
log::trace!("present: window={:X}", imp.window);
|
log::trace!("present: window={:X}", imp.window);
|
||||||
|
|
||||||
match imp.buffer {
|
match imp.buffer {
|
||||||
|
|
@ -324,8 +324,8 @@ impl<'a> BufferImpl<'a> {
|
||||||
xproto::ImageFormat::Z_PIXMAP,
|
xproto::ImageFormat::Z_PIXMAP,
|
||||||
imp.window,
|
imp.window,
|
||||||
imp.gc,
|
imp.gc,
|
||||||
imp.width,
|
surface_width.get(),
|
||||||
imp.height,
|
surface_height.get(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
|
@ -334,6 +334,7 @@ impl<'a> BufferImpl<'a> {
|
||||||
)
|
)
|
||||||
.map(|c| c.ignore_error())
|
.map(|c| c.ignore_error())
|
||||||
.push_err()
|
.push_err()
|
||||||
|
.swbuf_err("Failed to draw image to window")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Shm(ref mut shm) => {
|
Buffer::Shm(ref mut shm) => {
|
||||||
|
|
@ -343,46 +344,50 @@ impl<'a> BufferImpl<'a> {
|
||||||
if let Some((_, segment_id)) = shm.seg {
|
if let Some((_, segment_id)) = shm.seg {
|
||||||
damage
|
damage
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(
|
.try_for_each(|rect| {
|
||||||
|Rect {
|
let (src_x, src_y, dst_x, dst_y, width, height) = (|| {
|
||||||
x,
|
Some((
|
||||||
y,
|
u16::try_from(rect.x).ok()?,
|
||||||
width,
|
u16::try_from(rect.y).ok()?,
|
||||||
height,
|
i16::try_from(rect.x).ok()?,
|
||||||
}| {
|
i16::try_from(rect.y).ok()?,
|
||||||
imp.display
|
u16::try_from(rect.width.get()).ok()?,
|
||||||
.connection
|
u16::try_from(rect.height.get()).ok()?,
|
||||||
.shm_put_image(
|
))
|
||||||
imp.window,
|
})(
|
||||||
imp.gc,
|
)
|
||||||
imp.width,
|
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
|
||||||
imp.height,
|
imp.display
|
||||||
*x as u16,
|
.connection
|
||||||
*y as u16,
|
.shm_put_image(
|
||||||
*width as u16,
|
imp.window,
|
||||||
*height as u16,
|
imp.gc,
|
||||||
*x as i16,
|
surface_width.get(),
|
||||||
*y as i16,
|
surface_height.get(),
|
||||||
imp.depth,
|
src_x,
|
||||||
xproto::ImageFormat::Z_PIXMAP.into(),
|
src_y,
|
||||||
false,
|
width,
|
||||||
segment_id,
|
height,
|
||||||
0,
|
dst_x,
|
||||||
)
|
dst_y,
|
||||||
.push_err()
|
imp.depth,
|
||||||
.map(|c| c.ignore_error())
|
xproto::ImageFormat::Z_PIXMAP.into(),
|
||||||
},
|
false,
|
||||||
)
|
segment_id,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.push_err()
|
||||||
|
.map(|c| c.ignore_error())
|
||||||
|
.swbuf_err("Failed to draw image to window")
|
||||||
|
})
|
||||||
.and_then(|()| {
|
.and_then(|()| {
|
||||||
// Send a short request to act as a notification for when the X server is done processing the image.
|
// Send a short request to act as a notification for when the X server is done processing the image.
|
||||||
shm.begin_wait(&imp.display.connection)
|
shm.begin_wait(&imp.display.connection)
|
||||||
})
|
.swbuf_err("Failed to draw image to window")
|
||||||
} else {
|
})?;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.swbuf_err("Failed to draw image to window")?;
|
|
||||||
|
|
||||||
imp.buffer_presented = true;
|
imp.buffer_presented = true;
|
||||||
|
|
||||||
|
|
@ -390,13 +395,15 @@ impl<'a> BufferImpl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn present(self) -> Result<(), SoftBufferError> {
|
pub fn present(self) -> Result<(), SoftBufferError> {
|
||||||
let width = self.0.width.into();
|
let (width, height) = self
|
||||||
let height = self.0.height.into();
|
.0
|
||||||
|
.size
|
||||||
|
.expect("Must set size of surface before calling `present()`");
|
||||||
self.present_with_damage(&[Rect {
|
self.present_with_damage(&[Rect {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width,
|
width: width.into(),
|
||||||
height,
|
height: height.into(),
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue