diff --git a/pixman/examples/alpha.rs b/pixman/examples/alpha.rs index 5910f60..11dbdf0 100644 --- a/pixman/examples/alpha.rs +++ b/pixman/examples/alpha.rs @@ -1,4 +1,6 @@ -use pixman::{Fixed, FormatCode, GradientStop, Image, Operation, Point, Repeat, Transform}; +use pixman::{ + Fixed, FormatCode, GradientStop, Image, LinearGradient, Operation, Point, Repeat, Transform, +}; const WIDTH: usize = 400; const HEIGHT: usize = 200; @@ -19,7 +21,7 @@ pub fn main() { ]); let mut alpha = [0x4f00004fu32; WIDTH * HEIGHT]; /* pale blue */ - let mut alpha_img = Image::from_bits( + let alpha_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -30,7 +32,7 @@ pub fn main() { .unwrap(); let mut dest = [0xffffff00u32; WIDTH * HEIGHT]; /* yellow */ - let mut dest_img = Image::from_bits( + let dest_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -41,17 +43,10 @@ pub fn main() { .unwrap(); let mut src = [0xffff0000; WIDTH * HEIGHT]; - let mut src_img = Image::from_bits( - FormatCode::A8R8G8B8, - WIDTH, - HEIGHT, - &mut src, - WIDTH * 4, - false, - ) - .unwrap(); + let src_img = + Image::from_slice(FormatCode::A8R8G8B8, WIDTH, HEIGHT, &mut src, WIDTH * 4).unwrap(); - let mut grad_img = Image::linear_gradient(p1, p2, &stops).unwrap(); + let grad_img = LinearGradient::new(p1, p2, &stops).unwrap(); grad_img.set_transform(transform).unwrap(); grad_img.set_repeat(Repeat::Pad); @@ -69,7 +64,7 @@ pub fn main() { HEIGHT as u16, ); - src_img.set_alpha_map(Some(&alpha_img), 10, 10); + let src_img = src_img.set_alpha_map(&alpha_img, 10, 10); dest_img.composite( Operation::Over, @@ -85,7 +80,7 @@ pub fn main() { HEIGHT as u16, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dest_img.width(), dest_img.height(), diff --git a/pixman/examples/checkerboard.rs b/pixman/examples/checkerboard.rs index 4480cb3..384c9ce 100644 --- a/pixman/examples/checkerboard.rs +++ b/pixman/examples/checkerboard.rs @@ -1,12 +1,12 @@ -use pixman::{Color, Filter, FormatCode, Image, Operation, Repeat}; +use pixman::{Color, Filter, FormatCode, Image, Operation, Repeat, Solid}; const WIDTH: usize = 400; const HEIGHT: usize = 400; const TILE_SIZE: usize = 25; pub fn main() { - let mut checkerboard = Image::new(FormatCode::A8R8G8B8, WIDTH, HEIGHT, false).unwrap(); - let mut destination = Image::new(FormatCode::A8R8G8B8, WIDTH, HEIGHT, false).unwrap(); + let checkerboard = Image::new(FormatCode::A8R8G8B8, WIDTH, HEIGHT, false).unwrap(); + let destination = Image::new(FormatCode::A8R8G8B8, WIDTH, HEIGHT, false).unwrap(); // let transform = Transform::new([ // [-1.96830, -1.82250, 512.12250], @@ -28,7 +28,7 @@ pub fn main() { let c = if (j & 1) != (i & 1) { black } else { white }; - let fill = Image::solid_fill(c).unwrap(); + let fill = Solid::new(c).unwrap(); checkerboard.composite( Operation::Src, @@ -65,7 +65,7 @@ pub fn main() { HEIGHT as u16, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, destination.width(), destination.height(), diff --git a/pixman/examples/clip.rs b/pixman/examples/clip.rs index f94f54e..0ebc224 100644 --- a/pixman/examples/clip.rs +++ b/pixman/examples/clip.rs @@ -1,5 +1,6 @@ use pixman::{ - Fixed, FormatCode, GradientStop, Image, Operation, Point, Region32, Repeat, Transform, + Fixed, FormatCode, GradientStop, Image, Operation, Point, RadialGradient, Region32, Repeat, + Transform, }; const WIDTH: usize = 200; @@ -19,7 +20,7 @@ pub fn main() { let r_outer = Fixed::from(100.0); let mut src = [0xff0000ffu32; WIDTH * HEIGHT]; - let mut src_img = Image::from_bits( + let src_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -29,7 +30,7 @@ pub fn main() { ) .unwrap(); - let gradient_img = Image::radial_gradient(c_inner, c_outer, r_inner, r_outer, &stops).unwrap(); + let gradient_img = RadialGradient::new(c_inner, c_outer, r_inner, r_outer, &stops).unwrap(); src_img.composite( Operation::Over, @@ -53,7 +54,7 @@ pub fn main() { src_img.set_repeat(Repeat::Normal); let mut dst = [0xffff0000u32; WIDTH * HEIGHT]; - let mut dst_img = Image::from_bits( + let dst_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -77,7 +78,7 @@ pub fn main() { HEIGHT as u16, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dst_img.width(), dst_img.height(), diff --git a/pixman/examples/conical.rs b/pixman/examples/conical.rs index 594837f..8dbd947 100644 --- a/pixman/examples/conical.rs +++ b/pixman/examples/conical.rs @@ -1,4 +1,6 @@ -use pixman::{FormatCode, GradientStop, Image, Operation, Repeat, Transform}; +use pixman::{ + ConicalGradient, FormatCode, GradientStop, Image, Operation, Repeat, Solid, Transform, +}; const SIZE: usize = 128; const GRADIENTS_PER_ROW: usize = 7; @@ -24,7 +26,7 @@ pub fn main() { let column = i % GRADIENTS_PER_ROW; let row = i / GRADIENTS_PER_ROW; - let mut src_img = create_conical(i); + let src_img = create_conical(i); src_img.set_repeat(Repeat::Normal); src_img.set_transform(transform).unwrap(); @@ -43,7 +45,7 @@ pub fn main() { ); } - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dest_img.width(), dest_img.height(), @@ -76,9 +78,9 @@ pub fn main() { .unwrap(); } -fn create_conical(index: usize) -> Image<'static> { +fn create_conical(index: usize) -> ConicalGradient<'static> { let angle = (0.5 / NUM_GRADIENTS as f64 + index as f64 / NUM_GRADIENTS as f64) * 720.0 - 180.0; - Image::conical_gradient( + ConicalGradient::new( (0.0, 0.0), angle, &[ @@ -91,9 +93,9 @@ fn create_conical(index: usize) -> Image<'static> { .unwrap() } -fn draw_checkerboard(image: &mut Image, check_size: usize, color1: u32, color2: u32) { - let c1 = Image::solid_fill(color1).unwrap(); - let c2 = Image::solid_fill(color2).unwrap(); +fn draw_checkerboard(image: &Image<'_, '_, true>, check_size: usize, color1: u32, color2: u32) { + let c1 = Solid::new(color1).unwrap(); + let c2 = Solid::new(color2).unwrap(); let n_checks_x = (image.width() + check_size - 1) / check_size; let n_checks_y = (image.height() + check_size - 1) / check_size; diff --git a/pixman/examples/gradient.rs b/pixman/examples/gradient.rs index b2db501..8473719 100644 --- a/pixman/examples/gradient.rs +++ b/pixman/examples/gradient.rs @@ -1,4 +1,6 @@ -use pixman::{Fixed, FormatCode, GradientStop, Image, Operation, Point, Repeat, Transform}; +use pixman::{ + Fixed, FormatCode, GradientStop, Image, LinearGradient, Operation, Point, Repeat, Transform, +}; const WIDTH: usize = 400; const HEIGHT: usize = 200; @@ -19,7 +21,7 @@ pub fn main() { ]); let mut dest = [0xff00ff00u32; WIDTH * HEIGHT]; - let mut dest_img = Image::from_bits( + let dest_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -29,7 +31,7 @@ pub fn main() { ) .unwrap(); - let mut src_img = Image::linear_gradient(p1, p2, &stops).unwrap(); + let src_img = LinearGradient::new(p1, p2, &stops).unwrap(); src_img.set_transform(transform).unwrap(); src_img.set_repeat(Repeat::None); @@ -48,7 +50,7 @@ pub fn main() { HEIGHT as u16, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dest_img.width(), dest_img.height(), diff --git a/pixman/examples/solid_fill.rs b/pixman/examples/solid_fill.rs index 754a3ef..c280aae 100644 --- a/pixman/examples/solid_fill.rs +++ b/pixman/examples/solid_fill.rs @@ -1,12 +1,12 @@ -use pixman::{FormatCode, Image, Operation, Repeat}; +use pixman::{FormatCode, Image, Operation, Repeat, Solid}; pub fn main() { - let mut dst = Image::new(FormatCode::A8R8G8B8, 800, 600, true).unwrap(); - let mut solid = Image::solid_fill([0xffff, 0xffff, 0xffff, 0xffff]).unwrap(); + let dst = Image::new(FormatCode::A8R8G8B8, 800, 600, true).unwrap(); + let solid = Solid::new([0xffff, 0xffff, 0xffff, 0xffff]).unwrap(); solid.set_repeat(Repeat::Normal); dst.composite(Operation::Over, &solid, None, 0, 0, 0, 0, 50, 0, 50, 50); - let mut out_img = Image::new(FormatCode::A8B8G8R8, dst.width(), dst.height(), false).unwrap(); + let out_img = Image::new(FormatCode::A8B8G8R8, dst.width(), dst.height(), false).unwrap(); out_img.composite( Operation::Src, &dst, diff --git a/pixman/examples/trap.rs b/pixman/examples/trap.rs index e2c7d5d..4432c0d 100644 --- a/pixman/examples/trap.rs +++ b/pixman/examples/trap.rs @@ -1,4 +1,4 @@ -use pixman::{Color, Fixed, FormatCode, Image, Operation, Span, Trap}; +use pixman::{Color, Fixed, FormatCode, Image, Operation, Solid, Span, Trap}; const WIDTH: usize = 200; const HEIGHT: usize = 200; @@ -24,11 +24,11 @@ pub fn main() { ), ); - let mut mask_img = - Image::from_bits(FormatCode::A8, WIDTH, HEIGHT, &mut mbits, WIDTH, false).unwrap(); - let src_img = Image::solid_fill(white).unwrap(); - let mut dest_img = - Image::from_bits(FormatCode::A8R8G8B8, WIDTH, HEIGHT, bits, WIDTH * 4, false).unwrap(); + let mask_img = + Image::from_slice_mut(FormatCode::A8, WIDTH, HEIGHT, &mut mbits, WIDTH, false).unwrap(); + let src_img = Solid::new(white).unwrap(); + let dest_img = + Image::from_slice_mut(FormatCode::A8R8G8B8, WIDTH, HEIGHT, bits, WIDTH * 4, false).unwrap(); mask_img.add_traps(0, 0, &[trap]); @@ -46,7 +46,7 @@ pub fn main() { HEIGHT as u16, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dest_img.width(), dest_img.height(), diff --git a/pixman/examples/tri.rs b/pixman/examples/tri.rs index 4751989..9b22ea1 100644 --- a/pixman/examples/tri.rs +++ b/pixman/examples/tri.rs @@ -1,4 +1,4 @@ -use pixman::{Color, FormatCode, Image, Operation, Triangle}; +use pixman::{Color, FormatCode, Image, Operation, Solid, Triangle}; const WIDTH: usize = 200; const HEIGHT: usize = 200; @@ -18,8 +18,8 @@ pub fn main() { bits[i] = ((i / HEIGHT) as u32) * 0x01010000; } - let src_img = Image::solid_fill(color).unwrap(); - let mut dest_img = Image::from_bits( + let src_img = Solid::new(color).unwrap(); + let dest_img = Image::from_slice_mut( FormatCode::A8R8G8B8, WIDTH, HEIGHT, @@ -40,7 +40,7 @@ pub fn main() { &tris, ); - let mut out_img = Image::new( + let out_img = Image::new( FormatCode::A8B8G8R8, dest_img.width(), dest_img.height(), diff --git a/pixman/src/image.rs b/pixman/src/image.rs deleted file mode 100644 index f27e603..0000000 --- a/pixman/src/image.rs +++ /dev/null @@ -1,688 +0,0 @@ -use std::{marker::PhantomData, mem::MaybeUninit, os::raw::c_int}; - -use pixman_sys as ffi; - -use crate::{ - format::FormatCode, operation::Operation, repeat::Repeat, Box32, Color, Dither, Edge, Filter, - Fixed, GradientStop, OperationFailed, Point, Rectangle16, Region16, Region32, Transform, Trap, - Trapezoid, Triangle, -}; - -pub struct Image<'bits> { - ptr: *mut ffi::pixman_image_t, - _phantom: PhantomData<&'bits ()>, -} - -#[derive(Debug)] -pub struct CreateFailed; - -impl Image<'static> { - pub fn new( - format: FormatCode, - width: usize, - height: usize, - clear: bool, - ) -> Result { - let ptr = if clear { - unsafe { - ffi::pixman_image_create_bits( - format.into(), - width as c_int, - height as c_int, - std::ptr::null_mut(), - 0, - ) - } - } else { - unsafe { - ffi::pixman_image_create_bits_no_clear( - format.into(), - width as c_int, - height as c_int, - std::ptr::null_mut(), - 0, - ) - } - }; - - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } - - pub fn solid_fill(color: impl Into) -> Result { - let color = color.into(); - let ptr = unsafe { ffi::pixman_image_create_solid_fill(color.as_ptr()) }; - - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } - - pub fn linear_gradient( - p1: impl Into, - p2: impl Into, - stops: &[GradientStop], - ) -> Result { - let p1: Point = p1.into(); - let p2: Point = p2.into(); - let ptr = unsafe { - ffi::pixman_image_create_linear_gradient( - p1.as_ptr(), - p2.as_ptr(), - stops.as_ptr() as *const _, - stops.len() as c_int, - ) - }; - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } - - pub fn conical_gradient( - center: impl Into, - angle: impl Into, - stops: &[GradientStop], - ) -> Result { - let center = center.into(); - let angle = angle.into(); - let ptr = unsafe { - ffi::pixman_image_create_conical_gradient( - center.as_ptr(), - angle.into_raw(), - stops.as_ptr() as *const _, - stops.len() as c_int, - ) - }; - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } - - pub fn radial_gradient( - inner: impl Into, - outer: impl Into, - inner_radius: impl Into, - outer_radius: impl Into, - stops: &[GradientStop], - ) -> Result { - let inner = inner.into(); - let outer = outer.into(); - let inner_radius = inner_radius.into(); - let other_radius = outer_radius.into(); - let ptr = unsafe { - ffi::pixman_image_create_radial_gradient( - inner.as_ptr(), - outer.as_ptr(), - inner_radius.into_raw(), - other_radius.into_raw(), - stops.as_ptr() as *const _, - stops.len() as c_int, - ) - }; - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } -} - -impl<'bits> Image<'bits> { - pub fn from_bits( - format: FormatCode, - width: usize, - height: usize, - bits: &'bits mut [u32], - rowstride_bytes: usize, - clear: bool, - ) -> Result { - let ptr = if clear { - unsafe { - ffi::pixman_image_create_bits( - format.into(), - width as c_int, - height as c_int, - bits.as_mut_ptr(), - rowstride_bytes as c_int, - ) - } - } else { - unsafe { - ffi::pixman_image_create_bits_no_clear( - format.into(), - width as c_int, - height as c_int, - bits.as_mut_ptr(), - rowstride_bytes as c_int, - ) - } - }; - - if ptr.is_null() { - Err(CreateFailed) - } else { - Ok(Self { - ptr, - _phantom: PhantomData, - }) - } - } - - pub fn width(&self) -> usize { - unsafe { ffi::pixman_image_get_width(self.ptr) as usize } - } - - pub fn height(&self) -> usize { - unsafe { ffi::pixman_image_get_height(self.ptr) as usize } - } - - pub fn stride(&self) -> usize { - unsafe { ffi::pixman_image_get_stride(self.ptr) as usize } - } - - pub fn depth(&self) -> usize { - unsafe { ffi::pixman_image_get_depth(self.ptr) as usize } - } - - pub fn format(&self) -> Option { - let format = unsafe { ffi::pixman_image_get_format(self.ptr) }; - FormatCode::try_from(format).ok() - } - - pub fn component_alpha(&self) -> bool { - unsafe { ffi::pixman_image_get_component_alpha(self.ptr) == 1 } - } - - pub fn set_repeat(&mut self, repeat: Repeat) { - unsafe { - ffi::pixman_image_set_repeat(self.ptr, repeat.into()); - } - } - - pub fn set_transform( - &mut self, - transform: impl Into, - ) -> Result<(), OperationFailed> { - let transform = transform.into(); - let res = unsafe { ffi::pixman_image_set_transform(self.ptr, transform.as_ptr()) }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - pub fn set_alpha_map<'alpha: 'bits>( - &mut self, - alpha_map: Option<&Image<'alpha>>, - x: i16, - y: i16, - ) { - let alpha_map = if let Some(alpha_map) = alpha_map { - alpha_map.ptr - } else { - std::ptr::null_mut() - }; - unsafe { - ffi::pixman_image_set_alpha_map(self.ptr, alpha_map, x, y); - } - } - - pub fn set_clip_region(&mut self, region: Option) -> Result<(), OperationFailed> { - let region = if let Some(region) = region { - region.as_ptr() - } else { - std::ptr::null() - }; - let res = unsafe { - // FIXME: pixman_image_set_clip_region takes a *const region, but bindgen generates *mut region - ffi::pixman_image_set_clip_region(self.ptr, region as *mut _) - }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - pub fn set_clip_region32(&mut self, region: Option) -> Result<(), OperationFailed> { - let region = if let Some(region) = region { - region.as_ptr() - } else { - std::ptr::null() - }; - let res = unsafe { - // FIXME: pixman_image_set_clip_region32 takes a *const region, but bindgen generates *mut region - ffi::pixman_image_set_clip_region32(self.ptr, region as *mut _) - }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - pub fn set_component_alpha(&mut self, component_alpha: bool) { - let component_alpha = if component_alpha { 1 } else { 0 }; - unsafe { ffi::pixman_image_set_component_alpha(self.ptr, component_alpha) } - } - - pub fn set_dither(&mut self, dither: Dither) { - unsafe { - ffi::pixman_image_set_dither(self.ptr, dither.into()); - } - } - - pub fn set_dither_offset(&mut self, offset_x: c_int, offset_y: c_int) { - unsafe { ffi::pixman_image_set_dither_offset(self.ptr, offset_x, offset_y) } - } - - pub fn set_filter( - &mut self, - filter: Filter, - filter_params: &[Fixed], - ) -> Result<(), OperationFailed> { - let res = unsafe { - ffi::pixman_image_set_filter( - self.ptr, - filter.into(), - filter_params.as_ptr() as *const _, - filter_params.len() as i32, - ) - }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - pub fn set_has_client_clip(&mut self, client_clip: bool) { - let client_clip = if client_clip { 1 } else { 0 }; - unsafe { - ffi::pixman_image_set_has_client_clip(self.ptr, client_clip); - } - } - - // TODO: pixman_image_set_indexed - //pub fn set_indexd(&mut self) - - pub fn set_source_clipping(&mut self, source_clipping: bool) { - let source_clipping = if source_clipping { 1 } else { 0 }; - unsafe { - ffi::pixman_image_set_source_clipping(self.ptr, source_clipping); - } - } - - pub fn fill_boxes( - &mut self, - op: Operation, - color: impl Into, - boxes: &[Box32], - ) -> Result<(), OperationFailed> { - let color = color.into(); - let res = unsafe { - ffi::pixman_image_fill_boxes( - op.into(), - self.ptr, - color.as_ptr(), - boxes.len() as c_int, - boxes.as_ptr(), - ) - }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - pub fn fill_rectangles( - &mut self, - op: Operation, - color: impl Into, - rects: &[Rectangle16], - ) -> Result<(), OperationFailed> { - let color = color.into(); - let res = unsafe { - ffi::pixman_image_fill_rectangles( - op.into(), - self.ptr, - color.as_ptr(), - rects.len() as c_int, - rects.as_ptr(), - ) - }; - if res == 1 { - Ok(()) - } else { - Err(OperationFailed) - } - } - - #[allow(clippy::too_many_arguments)] - pub fn composite( - &mut self, - operation: Operation, - src: &Image<'_>, - mask: Option<&Image<'_>>, - src_x: i16, - src_y: i16, - mask_x: i16, - mask_y: i16, - dest_x: i16, - dest_y: i16, - width: u16, - height: u16, - ) { - let mask_ptr = if let Some(mask) = mask { - mask.ptr - } else { - std::ptr::null_mut() - }; - unsafe { - ffi::pixman_image_composite( - operation.into(), - src.ptr, - mask_ptr, - self.ptr, - src_x, - src_y, - mask_x, - mask_y, - dest_x, - dest_y, - width, - height, - ) - } - } - - #[allow(clippy::too_many_arguments)] - pub fn composite32( - &mut self, - operation: Operation, - src: &Image<'_>, - mask: Option<&Image<'_>>, - src_x: i32, - src_y: i32, - mask_x: i32, - mask_y: i32, - dest_x: i32, - dest_y: i32, - width: i32, - height: i32, - ) { - let mask_ptr = if let Some(mask) = mask { - mask.ptr - } else { - std::ptr::null_mut() - }; - unsafe { - ffi::pixman_image_composite32( - operation.into(), - src.ptr, - mask_ptr, - self.ptr, - src_x, - src_y, - mask_x, - mask_y, - dest_x, - dest_y, - width, - height, - ) - } - } - - #[allow(clippy::too_many_arguments)] - pub fn composite_triangles( - &mut self, - operation: Operation, - src: &Image<'_>, - mask_format: FormatCode, - x_src: isize, - y_src: isize, - x_dst: isize, - y_dst: isize, - tris: &[Triangle], - ) { - unsafe { - ffi::pixman_composite_triangles( - operation.into(), - src.ptr, - self.ptr, - mask_format.into(), - x_src as i32, - y_src as i32, - x_dst as i32, - y_dst as i32, - tris.len() as i32, - tris.as_ptr() as *const _, - ); - } - } - - #[allow(clippy::too_many_arguments)] - pub fn composite_trapezoids( - &mut self, - operation: Operation, - src: &Image<'_>, - mask_format: FormatCode, - x_src: isize, - y_src: isize, - x_dst: isize, - y_dst: isize, - traps: &[Trapezoid], - ) { - unsafe { - ffi::pixman_composite_trapezoids( - operation.into(), - src.ptr, - self.ptr, - mask_format.into(), - x_src as i32, - y_src as i32, - x_dst as i32, - y_dst as i32, - traps.len() as i32, - traps.as_ptr() as *const _, - ); - } - } - - pub fn add_traps(&mut self, x_off: i16, y_off: i16, traps: &[Trap]) { - unsafe { - ffi::pixman_add_traps( - self.ptr, - x_off, - y_off, - traps.len() as i32, - traps.as_ptr() as *const _, - ); - } - } - - pub fn add_trapezoids(&mut self, x_off: i16, y_off: i32, traps: &[Trapezoid]) { - unsafe { - ffi::pixman_add_trapezoids( - self.ptr, - x_off, - y_off, - traps.len() as i32, - traps.as_ptr() as *const _, - ); - } - } - - pub fn add_triangles(&mut self, x_off: i32, y_off: i32, tris: &[Triangle]) { - unsafe { - ffi::pixman_add_triangles( - self.ptr, - x_off, - y_off, - tris.len() as i32, - tris.as_ptr() as *const _, - ); - } - } - - #[allow(clippy::too_many_arguments)] - pub fn compute_composite_region( - &self, - src: &Image<'_>, - mask: Option<&Image<'_>>, - src_x: i16, - src_y: i16, - mask_x: i16, - mask_y: i16, - dest_x: i16, - dest_y: i16, - width: u16, - height: u16, - ) -> Option { - let mask_ptr = if let Some(mask) = mask { - mask.ptr - } else { - std::ptr::null_mut() - }; - - let mut region = MaybeUninit::uninit(); - let res = unsafe { - ffi::pixman_compute_composite_region( - region.as_mut_ptr(), - src.ptr, - mask_ptr, - self.ptr, - src_x, - src_y, - mask_x, - mask_y, - dest_x, - dest_y, - width, - height, - ) - }; - if res == 1 { - Some(Region16::from(unsafe { region.assume_init() })) - } else { - None - } - } - - pub fn rasterize_edges(&mut self, l: Edge, r: Edge, t: impl Into, b: impl Into) { - unsafe { - ffi::pixman_rasterize_edges( - self.ptr, - l.as_ptr() as *mut _, - r.as_ptr() as *mut _, - t.into().into_raw(), - b.into().into_raw(), - ) - } - } - - pub fn rasterize_trapezoid(&mut self, trap: Trapezoid, x_off: i32, y_off: i32) { - unsafe { ffi::pixman_rasterize_trapezoid(self.ptr, trap.as_ptr(), x_off, y_off) } - } - - // TODO: pixman_composite_glyphs - //pub fn composite_glyphs() - - // TODO: pixman_composite_glyphs - //pub fn composite_glyphs_no_mask() - - /// Access the underlying pixel data - /// - /// Returns `None` in case the image has no underlying pixel data, e.g. solid/gradient/... - pub fn data(&self) -> Option<&[u8]> { - let height = self.height(); - let stride = self.stride(); - let ptr = unsafe { ffi::pixman_image_get_data(self.ptr) }; - - if ptr.is_null() { - None - } else { - unsafe { - Some(std::slice::from_raw_parts( - ptr as *const u8, - stride * height, - )) - } - } - } - - #[inline] - pub fn as_ptr(&self) -> *const ffi::pixman_image_t { - self.ptr - } - - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut ffi::pixman_image_t { - self.ptr - } -} - -impl<'bits> Drop for Image<'bits> { - fn drop(&mut self) { - unsafe { - ffi::pixman_image_unref(self.ptr); - } - } -} - -#[cfg(test)] -mod tests { - use crate::{FormatCode, Image, Operation, Repeat}; - - #[test] - fn create() { - let _ = Image::new(FormatCode::A8R8G8B8, 800, 600, false).unwrap(); - } - - #[test] - fn from_bits() { - let mut bits: Vec = Vec::new(); - let _ = Image::from_bits(FormatCode::A8R8G8B8, 800, 600, &mut bits, 0, true).unwrap(); - } - - #[test] - fn solid() { - let _ = Image::solid_fill([0xffff, 0xffff, 0xffff, 0xffff]).unwrap(); - } - - #[test] - fn composite() { - let mut dst = Image::new(FormatCode::A8R8G8B8, 800, 600, true).unwrap(); - let mut solid = Image::solid_fill([0xffff, 0xffff, 0xffff, 0xffff]).unwrap(); - solid.set_repeat(Repeat::Normal); - dst.composite(Operation::Over, &solid, None, 0, 0, 0, 0, 0, 0, 50, 50); - let _ = dst.data().unwrap(); - } -} diff --git a/pixman/src/image/bits.rs b/pixman/src/image/bits.rs new file mode 100644 index 0000000..96cf1af --- /dev/null +++ b/pixman/src/image/bits.rs @@ -0,0 +1,530 @@ +use std::{ffi::c_int, marker::PhantomData, mem::MaybeUninit}; + +use crate::{ + ffi, Box32, Color, CreateFailed, Edge, Fixed, FormatCode, ImageRef, Operation, OperationFailed, + Rectangle16, Region16, Trap, Trapezoid, Triangle, +}; + +pub struct Image<'bits, 'alpha, const WRITABLE: bool> { + image: ImageRef, + _bits: PhantomData<&'bits ()>, + _alpha: PhantomData<&'alpha ()>, +} + +impl<'bits, 'alpha, const WRITABLE: bool> Image<'bits, 'alpha, WRITABLE> { + pub unsafe fn from_ptr(ptr: *mut ffi::pixman_image_t) -> Self { + Self { + image: unsafe { ImageRef::from_ptr(ptr) }, + _bits: PhantomData, + _alpha: PhantomData, + } + } +} + +impl<'bits, 'alpha, const WRITABLE: bool> std::ops::Deref for Image<'bits, 'alpha, WRITABLE> { + type Target = ImageRef; + + fn deref(&self) -> &Self::Target { + &self.image + } +} + +impl<'bits, 'alpha, const WRITABLE: bool> Image<'bits, 'alpha, WRITABLE> { + pub fn width(&self) -> usize { + unsafe { ffi::pixman_image_get_width(self.as_ptr()) as usize } + } + + pub fn height(&self) -> usize { + unsafe { ffi::pixman_image_get_height(self.as_ptr()) as usize } + } + + pub fn stride(&self) -> usize { + unsafe { ffi::pixman_image_get_stride(self.as_ptr()) as usize } + } + + pub fn depth(&self) -> usize { + unsafe { ffi::pixman_image_get_depth(self.as_ptr()) as usize } + } + + pub fn format(&self) -> Option { + let format = unsafe { ffi::pixman_image_get_format(self.as_ptr()) }; + FormatCode::try_from(format).ok() + } + + /// Access the underlying pixel data + /// + /// Returns `None` in case the image has no underlying pixel data, e.g. solid/gradient/... + pub fn data(&self) -> Option<&[u8]> { + let height = self.height(); + let stride = self.stride(); + let ptr = unsafe { ffi::pixman_image_get_data(self.as_ptr()) }; + + if ptr.is_null() { + None + } else { + unsafe { + Some(std::slice::from_raw_parts( + ptr as *const u8, + stride * height, + )) + } + } + } +} + +impl<'bits, 'a, const W: bool> Image<'bits, 'a, W> { + pub fn set_alpha_map<'alpha: 'a, const WRITABLE: bool>( + self, + alpha_map: &'alpha Image<'_, 'static, WRITABLE>, + x: i16, + y: i16, + ) -> Image<'bits, 'alpha, W> { + unsafe { + ffi::pixman_image_set_alpha_map(self.as_ptr(), alpha_map.as_ptr(), x, y); + } + Image { + image: self.image, + _bits: self._bits, + _alpha: PhantomData, + } + } + + pub fn clear_alpha_map(self) -> Image<'bits, 'static, W> { + unsafe { + ffi::pixman_image_set_alpha_map(self.as_ptr(), std::ptr::null_mut(), 0, 0); + } + Image { + image: self.image, + _bits: self._bits, + _alpha: PhantomData, + } + } +} + +impl<'bits> Image<'bits, 'static, false> { + pub fn from_slice( + format: FormatCode, + width: usize, + height: usize, + bits: &'bits [u32], + rowstride_bytes: usize, + ) -> Result { + unsafe { Self::from_raw(format, width, height, bits.as_ptr(), rowstride_bytes) } + } + + pub unsafe fn from_raw( + format: FormatCode, + width: usize, + height: usize, + bits: *const u32, + rowstride_bytes: usize, + ) -> Result { + let ptr = unsafe { + ffi::pixman_image_create_bits_no_clear( + format.into(), + width as c_int, + height as c_int, + bits as *mut _, + rowstride_bytes as c_int, + ) + }; + + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} + +impl Image<'static, 'static, true> { + pub fn new( + format: FormatCode, + width: usize, + height: usize, + clear: bool, + ) -> Result { + let ptr = if clear { + unsafe { + ffi::pixman_image_create_bits( + format.into(), + width as c_int, + height as c_int, + std::ptr::null_mut(), + 0, + ) + } + } else { + unsafe { + ffi::pixman_image_create_bits_no_clear( + format.into(), + width as c_int, + height as c_int, + std::ptr::null_mut(), + 0, + ) + } + }; + + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} + +impl<'bits> Image<'bits, 'static, true> { + pub fn from_slice_mut( + format: FormatCode, + width: usize, + height: usize, + bits: &'bits mut [u32], + rowstride_bytes: usize, + clear: bool, + ) -> Result { + unsafe { + Self::from_raw_mut( + format, + width, + height, + bits.as_mut_ptr(), + rowstride_bytes, + clear, + ) + } + } + + pub unsafe fn from_raw_mut( + format: FormatCode, + width: usize, + height: usize, + bits: *mut u32, + rowstride_bytes: usize, + clear: bool, + ) -> Result { + let ptr = if clear { + unsafe { + ffi::pixman_image_create_bits( + format.into(), + width as c_int, + height as c_int, + bits, + rowstride_bytes as c_int, + ) + } + } else { + unsafe { + ffi::pixman_image_create_bits_no_clear( + format.into(), + width as c_int, + height as c_int, + bits, + rowstride_bytes as c_int, + ) + } + }; + + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} + +impl<'bits, 'alpha> Image<'bits, 'alpha, true> { + pub fn fill_boxes( + &self, + op: Operation, + color: impl Into, + boxes: &[Box32], + ) -> Result<(), OperationFailed> { + let color = color.into(); + let res = unsafe { + ffi::pixman_image_fill_boxes( + op.into(), + self.as_ptr(), + color.as_ptr(), + boxes.len() as c_int, + boxes.as_ptr(), + ) + }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + pub fn fill_rectangles( + &self, + op: Operation, + color: impl Into, + rects: &[Rectangle16], + ) -> Result<(), OperationFailed> { + let color = color.into(); + let res = unsafe { + ffi::pixman_image_fill_rectangles( + op.into(), + self.as_ptr(), + color.as_ptr(), + rects.len() as c_int, + rects.as_ptr(), + ) + }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + #[allow(clippy::too_many_arguments)] + pub fn composite( + &self, + operation: Operation, + src: &ImageRef, + mask: Option<&ImageRef>, + src_x: i16, + src_y: i16, + mask_x: i16, + mask_y: i16, + dest_x: i16, + dest_y: i16, + width: u16, + height: u16, + ) { + let mask_ptr = if let Some(mask) = mask { + mask.as_ptr() + } else { + std::ptr::null_mut() + }; + unsafe { + ffi::pixman_image_composite( + operation.into(), + src.as_ptr(), + mask_ptr, + self.as_ptr(), + src_x, + src_y, + mask_x, + mask_y, + dest_x, + dest_y, + width, + height, + ) + } + } + + #[allow(clippy::too_many_arguments)] + pub fn composite32( + &self, + operation: Operation, + src: &ImageRef, + mask: Option<&ImageRef>, + src_x: i32, + src_y: i32, + mask_x: i32, + mask_y: i32, + dest_x: i32, + dest_y: i32, + width: i32, + height: i32, + ) { + let mask_ptr = if let Some(mask) = mask { + mask.as_ptr() + } else { + std::ptr::null_mut() + }; + unsafe { + ffi::pixman_image_composite32( + operation.into(), + src.as_ptr(), + mask_ptr, + self.as_ptr(), + src_x, + src_y, + mask_x, + mask_y, + dest_x, + dest_y, + width, + height, + ) + } + } + + #[allow(clippy::too_many_arguments)] + pub fn composite_triangles( + &self, + operation: Operation, + src: &ImageRef, + mask_format: FormatCode, + x_src: isize, + y_src: isize, + x_dst: isize, + y_dst: isize, + tris: &[Triangle], + ) { + unsafe { + ffi::pixman_composite_triangles( + operation.into(), + src.as_ptr(), + self.as_ptr(), + mask_format.into(), + x_src as i32, + y_src as i32, + x_dst as i32, + y_dst as i32, + tris.len() as i32, + tris.as_ptr() as *const _, + ); + } + } + + #[allow(clippy::too_many_arguments)] + pub fn composite_trapezoids( + &self, + operation: Operation, + src: &ImageRef, + mask_format: FormatCode, + x_src: isize, + y_src: isize, + x_dst: isize, + y_dst: isize, + traps: &[Trapezoid], + ) { + unsafe { + ffi::pixman_composite_trapezoids( + operation.into(), + src.as_ptr(), + self.as_ptr(), + mask_format.into(), + x_src as i32, + y_src as i32, + x_dst as i32, + y_dst as i32, + traps.len() as i32, + traps.as_ptr() as *const _, + ); + } + } + + pub fn add_traps(&self, x_off: i16, y_off: i16, traps: &[Trap]) { + unsafe { + ffi::pixman_add_traps( + self.as_ptr(), + x_off, + y_off, + traps.len() as i32, + traps.as_ptr() as *const _, + ); + } + } + + pub fn add_trapezoids(&self, x_off: i16, y_off: i32, traps: &[Trapezoid]) { + unsafe { + ffi::pixman_add_trapezoids( + self.as_ptr(), + x_off, + y_off, + traps.len() as i32, + traps.as_ptr() as *const _, + ); + } + } + + pub fn add_triangles(&self, x_off: i32, y_off: i32, tris: &[Triangle]) { + unsafe { + ffi::pixman_add_triangles( + self.as_ptr(), + x_off, + y_off, + tris.len() as i32, + tris.as_ptr() as *const _, + ); + } + } + + #[allow(clippy::too_many_arguments)] + pub fn compute_composite_region( + &self, + src: &ImageRef, + mask: Option<&ImageRef>, + src_x: i16, + src_y: i16, + mask_x: i16, + mask_y: i16, + dest_x: i16, + dest_y: i16, + width: u16, + height: u16, + ) -> Option { + let mask_ptr = if let Some(mask) = mask { + mask.as_ptr() + } else { + std::ptr::null_mut() + }; + + let mut region = MaybeUninit::uninit(); + let res = unsafe { + ffi::pixman_compute_composite_region( + region.as_mut_ptr(), + src.as_ptr(), + mask_ptr, + self.as_ptr(), + src_x, + src_y, + mask_x, + mask_y, + dest_x, + dest_y, + width, + height, + ) + }; + if res == 1 { + Some(Region16::from(unsafe { region.assume_init() })) + } else { + None + } + } + + pub fn rasterize_edges(&self, l: Edge, r: Edge, t: impl Into, b: impl Into) { + unsafe { + ffi::pixman_rasterize_edges( + self.as_ptr(), + l.as_ptr() as *mut _, + r.as_ptr() as *mut _, + t.into().into_raw(), + b.into().into_raw(), + ) + } + } + + pub fn rasterize_trapezoid(&self, trap: Trapezoid, x_off: i32, y_off: i32) { + unsafe { ffi::pixman_rasterize_trapezoid(self.as_ptr(), trap.as_ptr(), x_off, y_off) } + } + + /// Access the underlying pixel data + /// + /// Returns `None` in case the image has no underlying pixel data, e.g. solid/gradient/... + pub fn data_mut(&self) -> Option<&mut [u8]> { + let height = self.height(); + let stride = self.stride(); + let ptr = unsafe { ffi::pixman_image_get_data(self.as_ptr()) }; + + if ptr.is_null() { + None + } else { + unsafe { + Some(std::slice::from_raw_parts_mut( + ptr as *mut u8, + stride * height, + )) + } + } + } +} diff --git a/pixman/src/image/conical_gradient.rs b/pixman/src/image/conical_gradient.rs new file mode 100644 index 0000000..4523623 --- /dev/null +++ b/pixman/src/image/conical_gradient.rs @@ -0,0 +1,29 @@ +use std::ffi::c_int; + +use crate::{ffi, image_type, CreateFailed, Fixed, GradientStop, Point}; + +image_type!(ConicalGradient); + +impl ConicalGradient<'static> { + pub fn new( + center: impl Into, + angle: impl Into, + stops: &[GradientStop], + ) -> Result { + let center = center.into(); + let angle = angle.into(); + let ptr = unsafe { + ffi::pixman_image_create_conical_gradient( + center.as_ptr(), + angle.into_raw(), + stops.as_ptr() as *const _, + stops.len() as c_int, + ) + }; + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} diff --git a/pixman/src/image/linear_gradient.rs b/pixman/src/image/linear_gradient.rs new file mode 100644 index 0000000..811c475 --- /dev/null +++ b/pixman/src/image/linear_gradient.rs @@ -0,0 +1,29 @@ +use std::ffi::c_int; + +use crate::{ffi, image_type, CreateFailed, GradientStop, Point}; + +image_type!(LinearGradient); + +impl LinearGradient<'static> { + pub fn new( + p1: impl Into, + p2: impl Into, + stops: &[GradientStop], + ) -> Result { + let p1: Point = p1.into(); + let p2: Point = p2.into(); + let ptr = unsafe { + ffi::pixman_image_create_linear_gradient( + p1.as_ptr(), + p2.as_ptr(), + stops.as_ptr() as *const _, + stops.len() as c_int, + ) + }; + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} diff --git a/pixman/src/image/mod.rs b/pixman/src/image/mod.rs new file mode 100644 index 0000000..c6abef3 --- /dev/null +++ b/pixman/src/image/mod.rs @@ -0,0 +1,216 @@ +use std::os::raw::c_int; + +use pixman_sys as ffi; + +use crate::{ + repeat::Repeat, Dither, Filter, Fixed, OperationFailed, Region16, Region32, Transform, +}; + +mod bits; +mod conical_gradient; +mod linear_gradient; +mod radial_gradient; +mod solid; + +pub use bits::*; +pub use conical_gradient::ConicalGradient; +pub use linear_gradient::LinearGradient; +pub use radial_gradient::RadialGradient; +pub use solid::Solid; + +pub struct ImageRef(*mut ffi::pixman_image_t); + +impl ImageRef { + pub fn set_repeat(&self, repeat: Repeat) { + unsafe { + ffi::pixman_image_set_repeat(self.0, repeat.into()); + } + } + + pub fn set_transform(&self, transform: impl Into) -> Result<(), OperationFailed> { + let transform = transform.into(); + let res = unsafe { ffi::pixman_image_set_transform(self.0, transform.as_ptr()) }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + pub fn set_clip_region(&self, region: Option) -> Result<(), OperationFailed> { + let region = if let Some(region) = region { + region.as_ptr() + } else { + std::ptr::null() + }; + let res = unsafe { + // FIXME: pixman_image_set_clip_region takes a *const region, but bindgen generates *mut region + ffi::pixman_image_set_clip_region(self.0, region as *mut _) + }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + pub fn set_clip_region32(&self, region: Option) -> Result<(), OperationFailed> { + let region = if let Some(region) = region { + region.as_ptr() + } else { + std::ptr::null() + }; + let res = unsafe { + // FIXME: pixman_image_set_clip_region32 takes a *const region, but bindgen generates *mut region + ffi::pixman_image_set_clip_region32(self.0, region as *mut _) + }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + pub fn set_dither(&self, dither: Dither) { + unsafe { + ffi::pixman_image_set_dither(self.0, dither.into()); + } + } + + pub fn set_dither_offset(&self, offset_x: c_int, offset_y: c_int) { + unsafe { ffi::pixman_image_set_dither_offset(self.0, offset_x, offset_y) } + } + + pub fn set_filter( + &self, + filter: Filter, + filter_params: &[Fixed], + ) -> Result<(), OperationFailed> { + let res = unsafe { + ffi::pixman_image_set_filter( + self.0, + filter.into(), + filter_params.as_ptr() as *const _, + filter_params.len() as i32, + ) + }; + if res == 1 { + Ok(()) + } else { + Err(OperationFailed) + } + } + + pub fn set_has_client_clip(&self, client_clip: bool) { + let client_clip = if client_clip { 1 } else { 0 }; + unsafe { + ffi::pixman_image_set_has_client_clip(self.0, client_clip); + } + } + + // TODO: pixman_image_set_indexed + //pub fn set_indexed(&mut self) + + pub fn set_source_clipping(&self, source_clipping: bool) { + let source_clipping = if source_clipping { 1 } else { 0 }; + unsafe { + ffi::pixman_image_set_source_clipping(self.0, source_clipping); + } + } + + pub fn component_alpha(&self) -> bool { + unsafe { ffi::pixman_image_get_component_alpha(self.0) == 1 } + } + + pub fn set_component_alpha(&self, component_alpha: bool) { + let component_alpha = if component_alpha { 1 } else { 0 }; + unsafe { ffi::pixman_image_set_component_alpha(self.0, component_alpha) } + } +} + +impl ImageRef { + pub unsafe fn from_ptr(ptr: *mut ffi::pixman_image_t) -> Self { + assert!(!ptr.is_null()); + ImageRef(ptr) + } + + pub fn as_ptr(&self) -> *mut ffi::pixman_image_t { + self.0 + } +} + +impl Drop for ImageRef { + fn drop(&mut self) { + unsafe { + ffi::pixman_image_unref(self.0); + } + } +} + +macro_rules! image_type { + ($name:ident) => { + pub struct $name<'alpha> { + image: $crate::ImageRef, + _phantom: std::marker::PhantomData<&'alpha ()>, + } + + impl<'a> $name<'a> { + pub fn set_alpha_map<'alpha: 'a, const WRITABLE: bool>( + self, + alpha_map: &'alpha crate::Image<'_, 'static, WRITABLE>, + x: i16, + y: i16, + ) -> $name<'alpha> { + unsafe { + $crate::ffi::pixman_image_set_alpha_map( + self.as_ptr(), + alpha_map.as_ptr(), + x, + y, + ); + } + $name { + image: self.image, + _phantom: std::marker::PhantomData, + } + } + + pub fn clear_alpha_map(self) -> $name<'static> { + unsafe { + $crate::ffi::pixman_image_set_alpha_map( + self.as_ptr(), + std::ptr::null_mut(), + 0, + 0, + ); + } + $name { + image: self.image, + _phantom: std::marker::PhantomData, + } + } + } + + impl<'alpha> $name<'alpha> { + pub unsafe fn from_ptr(ptr: *mut ffi::pixman_image_t) -> Self { + Self { + image: $crate::ImageRef::from_ptr(ptr), + _phantom: std::marker::PhantomData, + } + } + } + + impl<'alpha> std::ops::Deref for $name<'alpha> { + type Target = $crate::ImageRef; + + fn deref(&self) -> &Self::Target { + &self.image + } + } + }; +} + +pub(crate) use image_type; + +#[derive(Debug)] +pub struct CreateFailed; diff --git a/pixman/src/image/radial_gradient.rs b/pixman/src/image/radial_gradient.rs new file mode 100644 index 0000000..29a5a67 --- /dev/null +++ b/pixman/src/image/radial_gradient.rs @@ -0,0 +1,35 @@ +use std::ffi::c_int; + +use crate::{ffi, image_type, CreateFailed, Fixed, GradientStop, Point}; + +image_type!(RadialGradient); + +impl RadialGradient<'static> { + pub fn new( + inner: impl Into, + outer: impl Into, + inner_radius: impl Into, + outer_radius: impl Into, + stops: &[GradientStop], + ) -> Result { + let inner = inner.into(); + let outer = outer.into(); + let inner_radius = inner_radius.into(); + let other_radius = outer_radius.into(); + let ptr = unsafe { + ffi::pixman_image_create_radial_gradient( + inner.as_ptr(), + outer.as_ptr(), + inner_radius.into_raw(), + other_radius.into_raw(), + stops.as_ptr() as *const _, + stops.len() as c_int, + ) + }; + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +} diff --git a/pixman/src/image/solid.rs b/pixman/src/image/solid.rs new file mode 100644 index 0000000..997ad7b --- /dev/null +++ b/pixman/src/image/solid.rs @@ -0,0 +1,16 @@ +use crate::{ffi, image_type, Color, CreateFailed}; + +image_type!(Solid); + +impl Solid<'static> { + pub fn new(color: impl Into) -> Result { + let color = color.into(); + let ptr = unsafe { ffi::pixman_image_create_solid_fill(color.as_ptr()) }; + + if ptr.is_null() { + Err(CreateFailed) + } else { + Ok(unsafe { Self::from_ptr(ptr) }) + } + } +}