pixman/image/
mod.rs

1use std::os::raw::c_int;
2
3use pixman_sys as ffi;
4use thiserror::Error;
5
6use crate::{
7    repeat::Repeat, Dither, Filter, Fixed, OperationFailed, Region16, Region32, Transform,
8};
9
10mod bits;
11mod conical_gradient;
12mod linear_gradient;
13mod radial_gradient;
14mod solid;
15
16pub use bits::*;
17pub use conical_gradient::ConicalGradient;
18pub use linear_gradient::LinearGradient;
19pub use radial_gradient::RadialGradient;
20pub use solid::Solid;
21
22/// Resource creation failed
23#[derive(Debug, Error)]
24#[error("Resource creation failed")]
25pub struct CreateFailed;
26
27/// A reference to a raw image
28#[derive(Debug)]
29pub struct ImageRef(*mut ffi::pixman_image_t);
30
31// SAFETY: See `Image`.
32#[cfg(feature = "sync")]
33unsafe impl Send for ImageRef {}
34#[cfg(feature = "sync")]
35unsafe impl Sync for ImageRef {}
36
37impl ImageRef {
38    /// Set the repeat operation for this image
39    pub fn set_repeat(&mut self, repeat: Repeat) {
40        unsafe {
41            ffi::pixman_image_set_repeat(self.0, repeat.into());
42        }
43    }
44
45    /// Apply the specified transform during sampling from this image
46    pub fn set_transform(
47        &mut self,
48        transform: impl Into<Transform>,
49    ) -> Result<(), OperationFailed> {
50        let transform = transform.into();
51        let res = unsafe { ffi::pixman_image_set_transform(self.0, transform.as_ptr()) };
52        if res == 1 {
53            Ok(())
54        } else {
55            Err(OperationFailed)
56        }
57    }
58
59    /// Clear a previously applied transform
60    pub fn clear_transform(&mut self) -> Result<(), OperationFailed> {
61        let res = unsafe { ffi::pixman_image_set_transform(self.0, std::ptr::null()) };
62        if res == 1 {
63            Ok(())
64        } else {
65            Err(OperationFailed)
66        }
67    }
68
69    /// Apply a clip region used during composition
70    pub fn set_clip_region(&mut self, region: Option<&Region16>) -> Result<(), OperationFailed> {
71        let region = if let Some(region) = region {
72            region.as_ptr()
73        } else {
74            std::ptr::null()
75        };
76        let res = unsafe { ffi::pixman_image_set_clip_region(self.0, region) };
77        if res == 1 {
78            Ok(())
79        } else {
80            Err(OperationFailed)
81        }
82    }
83
84    /// Apply a clip region used during composition
85    pub fn set_clip_region32(&mut self, region: Option<&Region32>) -> Result<(), OperationFailed> {
86        let region = if let Some(region) = region {
87            region.as_ptr()
88        } else {
89            std::ptr::null()
90        };
91        let res = unsafe { ffi::pixman_image_set_clip_region32(self.0, region) };
92        if res == 1 {
93            Ok(())
94        } else {
95            Err(OperationFailed)
96        }
97    }
98
99    /// Set the dither operation used during composition
100    pub fn set_dither(&mut self, dither: Dither) {
101        unsafe {
102            ffi::pixman_image_set_dither(self.0, dither.into());
103        }
104    }
105
106    /// Set the dither offset
107    pub fn set_dither_offset(&mut self, offset_x: c_int, offset_y: c_int) {
108        unsafe { ffi::pixman_image_set_dither_offset(self.0, offset_x, offset_y) }
109    }
110
111    /// Set the filter operation used during composition
112    pub fn set_filter(
113        &mut self,
114        filter: Filter,
115        filter_params: &[Fixed],
116    ) -> Result<(), OperationFailed> {
117        let res = unsafe {
118            ffi::pixman_image_set_filter(
119                self.0,
120                filter.into(),
121                filter_params.as_ptr() as *const _,
122                filter_params.len() as i32,
123            )
124        };
125        if res == 1 {
126            Ok(())
127        } else {
128            Err(OperationFailed)
129        }
130    }
131
132    /// Set whether the source clip was set by a client
133    pub fn set_has_client_clip(&mut self, client_clip: bool) {
134        let client_clip = if client_clip { 1 } else { 0 };
135        unsafe {
136            ffi::pixman_image_set_has_client_clip(self.0, client_clip);
137        }
138    }
139
140    // TODO: pixman_image_set_indexed
141    //pub fn set_indexed(&mut self)
142
143    /// Set whether the clip applies when the image is used as a source
144    pub fn set_source_clipping(&mut self, source_clipping: bool) {
145        let source_clipping = if source_clipping { 1 } else { 0 };
146        unsafe {
147            ffi::pixman_image_set_source_clipping(self.0, source_clipping);
148        }
149    }
150
151    /// Whether the image has component alpha or unified alpha
152    pub fn component_alpha(&self) -> bool {
153        unsafe { ffi::pixman_image_get_component_alpha(self.0) == 1 }
154    }
155
156    /// Set whether the image has component alpha or unified alpha
157    pub fn set_component_alpha(&mut self, component_alpha: bool) {
158        let component_alpha = if component_alpha { 1 } else { 0 };
159        unsafe { ffi::pixman_image_set_component_alpha(self.0, component_alpha) }
160    }
161}
162
163impl ImageRef {
164    /// Create a reference to a raw image
165    ///
166    /// # Safety
167    ///
168    /// The pointer is expected to be valid and have a ref-count of at least one.
169    /// Ownership of the pointer is transferred and unref will be called on drop.
170    pub unsafe fn from_ptr(ptr: *mut ffi::pixman_image_t) -> Self {
171        assert!(!ptr.is_null());
172        ImageRef(ptr)
173    }
174
175    /// Access the raw image pointer
176    pub fn as_ptr(&self) -> *mut ffi::pixman_image_t {
177        self.0
178    }
179}
180
181impl Drop for ImageRef {
182    fn drop(&mut self) {
183        #[cfg(feature = "sync")]
184        let _lock = crate::REF_COUNT_LOCK.lock().unwrap();
185        unsafe {
186            ffi::pixman_image_unref(self.0);
187        }
188    }
189}
190
191macro_rules! image_type {
192    ($(#[$attr:meta])* $name:ident) => {
193        $(#[$attr])*
194        pub struct $name<'alpha> {
195            image: $crate::ImageRef,
196            _phantom: std::marker::PhantomData<&'alpha ()>,
197        }
198
199        impl<'a> $name<'a> {
200            /// Set an alpha map that will be used when this image is
201            /// used as a src in a blit operation
202            pub fn set_alpha_map<'alpha: 'a>(
203                self,
204                alpha_map: &'alpha crate::Image<'_, 'static>,
205                x: i16,
206                y: i16,
207            ) -> $name<'alpha> {
208                #[cfg(feature = "sync")]
209                let _lock = $crate::REF_COUNT_LOCK.lock().unwrap();
210                unsafe {
211                    $crate::ffi::pixman_image_set_alpha_map(
212                        self.as_ptr(),
213                        alpha_map.as_ptr(),
214                        x,
215                        y,
216                    );
217                }
218                $name {
219                    image: self.image,
220                    _phantom: std::marker::PhantomData,
221                }
222            }
223
224            /// Clear a previously set alpha map
225            pub fn clear_alpha_map(self) -> $name<'static> {
226                #[cfg(feature = "sync")]
227                let _lock = $crate::REF_COUNT_LOCK.lock().unwrap();
228                unsafe {
229                    $crate::ffi::pixman_image_set_alpha_map(
230                        self.as_ptr(),
231                        std::ptr::null_mut(),
232                        0,
233                        0,
234                    );
235                }
236                $name {
237                    image: self.image,
238                    _phantom: std::marker::PhantomData,
239                }
240            }
241        }
242
243        impl<'alpha> $name<'alpha> {
244            /// Initialize the image from a raw pointer
245            ///
246            /// # Safety
247            ///
248            /// The pointer is expected to be valid and have a ref-count of at least one.
249            /// Ownership of the pointer is transferred and unref will be called on drop.
250            pub unsafe fn from_ptr(ptr: *mut ffi::pixman_image_t) -> Self {
251                Self {
252                    image: $crate::ImageRef::from_ptr(ptr),
253                    _phantom: std::marker::PhantomData,
254                }
255            }
256        }
257
258        impl<'alpha> std::ops::Deref for $name<'alpha> {
259            type Target = $crate::ImageRef;
260
261            fn deref(&self) -> &Self::Target {
262                &self.image
263            }
264        }
265
266        impl<'alpha> std::ops::DerefMut for $name<'alpha> {
267            fn deref_mut(&mut self) -> &mut Self::Target {
268                &mut self.image
269            }
270        }
271    };
272}
273
274pub(crate) use image_type;