cairo/
patterns.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{ops::Deref, ptr};
4
5use libc::{c_double, c_int, c_uint};
6
7use crate::{
8    ffi, utils::status_to_result, Error, Extend, Filter, Matrix, MeshCorner, Path, PatternType,
9    Surface,
10};
11
12// See https://cairographics.org/manual/bindings-patterns.html for more info
13#[derive(Debug)]
14pub struct Pattern {
15    pointer: *mut ffi::cairo_pattern_t,
16}
17
18impl Pattern {
19    user_data_methods! {
20        ffi::cairo_pattern_get_user_data,
21        ffi::cairo_pattern_set_user_data,
22    }
23
24    #[inline]
25    pub fn to_raw_none(&self) -> *mut ffi::cairo_pattern_t {
26        self.pointer
27    }
28
29    #[inline]
30    pub unsafe fn from_raw_none(pointer: *mut ffi::cairo_pattern_t) -> Pattern {
31        ffi::cairo_pattern_reference(pointer);
32        Self::from_raw_full(pointer)
33    }
34
35    #[inline]
36    pub unsafe fn from_raw_full(pointer: *mut ffi::cairo_pattern_t) -> Pattern {
37        Self { pointer }
38    }
39
40    #[doc(alias = "cairo_pattern_get_type")]
41    #[doc(alias = "get_type")]
42    pub fn type_(&self) -> PatternType {
43        unsafe { ffi::cairo_pattern_get_type(self.pointer).into() }
44    }
45
46    #[doc(alias = "cairo_pattern_get_reference_count")]
47    #[doc(alias = "get_reference_count")]
48    pub fn reference_count(&self) -> isize {
49        unsafe { ffi::cairo_pattern_get_reference_count(self.pointer) as isize }
50    }
51
52    #[doc(alias = "cairo_pattern_set_extend")]
53    pub fn set_extend(&self, extend: Extend) {
54        unsafe { ffi::cairo_pattern_set_extend(self.pointer, extend.into()) }
55    }
56
57    #[doc(alias = "cairo_pattern_get_extend")]
58    #[doc(alias = "get_extend")]
59    pub fn extend(&self) -> Extend {
60        unsafe { Extend::from(ffi::cairo_pattern_get_extend(self.pointer)) }
61    }
62
63    #[doc(alias = "cairo_pattern_set_filter")]
64    pub fn set_filter(&self, filter: Filter) {
65        unsafe { ffi::cairo_pattern_set_filter(self.pointer, filter.into()) }
66    }
67
68    #[doc(alias = "cairo_pattern_get_filter")]
69    #[doc(alias = "get_filter")]
70    pub fn filter(&self) -> Filter {
71        unsafe { Filter::from(ffi::cairo_pattern_get_filter(self.pointer)) }
72    }
73
74    #[doc(alias = "cairo_pattern_set_matrix")]
75    pub fn set_matrix(&self, matrix: Matrix) {
76        unsafe { ffi::cairo_pattern_set_matrix(self.pointer, matrix.ptr()) }
77    }
78
79    #[doc(alias = "cairo_pattern_get_matrix")]
80    #[doc(alias = "get_matrix")]
81    pub fn matrix(&self) -> Matrix {
82        let mut matrix = Matrix::null();
83        unsafe {
84            ffi::cairo_pattern_get_matrix(self.pointer, matrix.mut_ptr());
85        }
86        matrix
87    }
88
89    #[doc(alias = "cairo_pattern_status")]
90    pub fn status(&self) -> Result<(), Error> {
91        let status = unsafe { ffi::cairo_pattern_status(self.pointer) };
92        status_to_result(status)
93    }
94}
95
96impl Clone for Pattern {
97    #[inline]
98    fn clone(&self) -> Self {
99        Self {
100            pointer: unsafe { ffi::cairo_pattern_reference(self.pointer) },
101        }
102    }
103}
104
105impl Drop for Pattern {
106    #[inline]
107    fn drop(&mut self) {
108        unsafe { ffi::cairo_pattern_destroy(self.pointer) }
109    }
110}
111
112impl AsRef<Pattern> for Pattern {
113    #[inline]
114    fn as_ref(&self) -> &Pattern {
115        self
116    }
117}
118
119macro_rules! convert {
120    ($source: ident => $dest: ident = $( $variant: ident )|+ $( ($intermediate: ident) )*) => {
121        impl TryFrom<$source> for $dest {
122            type Error = $source;
123
124            fn try_from(pattern: $source) -> Result<Self, $source> {
125                if $( pattern.type_() == PatternType::$variant )||+ {
126                    $(
127                        let pattern = $intermediate(pattern);
128                    )*
129                    Ok($dest(pattern))
130                }
131                else {
132                    Err(pattern)
133                }
134            }
135        }
136    };
137}
138
139macro_rules! pattern_type(
140    //Signals without arguments
141    ($pattern_type:ident $( = $variant: ident)*) => (
142
143        #[derive(Debug, Clone)]
144        pub struct $pattern_type(Pattern);
145
146        impl Deref for $pattern_type {
147            type Target = Pattern;
148
149            #[inline]
150            fn deref(&self) -> &Pattern {
151                &self.0
152            }
153        }
154
155        impl AsRef<Pattern> for $pattern_type {
156            #[inline]
157            fn as_ref(&self) -> &Pattern {
158                &self.0
159            }
160        }
161
162        $(
163            convert!(Pattern => $pattern_type = $variant);
164        )*
165    );
166);
167
168pattern_type!(SolidPattern = Solid);
169
170impl SolidPattern {
171    #[doc(alias = "cairo_pattern_create_rgb")]
172    pub fn from_rgb(red: f64, green: f64, blue: f64) -> Self {
173        unsafe {
174            Self(Pattern::from_raw_full(ffi::cairo_pattern_create_rgb(
175                red, green, blue,
176            )))
177        }
178    }
179
180    #[doc(alias = "cairo_pattern_create_rgba")]
181    pub fn from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
182        unsafe {
183            Self(Pattern::from_raw_full(ffi::cairo_pattern_create_rgba(
184                red, green, blue, alpha,
185            )))
186        }
187    }
188
189    #[doc(alias = "cairo_pattern_get_rgba")]
190    #[doc(alias = "get_rgba")]
191    pub fn rgba(&self) -> Result<(f64, f64, f64, f64), Error> {
192        unsafe {
193            let mut red = 0.0;
194            let mut green = 0.0;
195            let mut blue = 0.0;
196            let mut alpha = 0.0;
197
198            let status = ffi::cairo_pattern_get_rgba(
199                self.pointer,
200                &mut red,
201                &mut green,
202                &mut blue,
203                &mut alpha,
204            );
205            status_to_result(status)?;
206
207            Ok((red, green, blue, alpha))
208        }
209    }
210}
211
212pattern_type!(Gradient);
213convert!(Pattern => Gradient = LinearGradient | RadialGradient);
214
215impl Gradient {
216    #[doc(alias = "cairo_pattern_add_color_stop_rgb")]
217    pub fn add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64) {
218        unsafe { ffi::cairo_pattern_add_color_stop_rgb(self.pointer, offset, red, green, blue) }
219    }
220
221    #[doc(alias = "cairo_pattern_add_color_stop_rgba")]
222    pub fn add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64) {
223        unsafe {
224            ffi::cairo_pattern_add_color_stop_rgba(self.pointer, offset, red, green, blue, alpha)
225        }
226    }
227
228    #[doc(alias = "cairo_pattern_get_color_stop_count")]
229    #[doc(alias = "get_color_stop_count")]
230    pub fn color_stop_count(&self) -> Result<isize, Error> {
231        unsafe {
232            let mut count = 0;
233            let status = ffi::cairo_pattern_get_color_stop_count(self.pointer, &mut count);
234
235            status_to_result(status)?;
236            Ok(count as isize)
237        }
238    }
239
240    #[doc(alias = "cairo_pattern_get_color_stop_rgba")]
241    #[doc(alias = "get_color_stop_rgba")]
242    pub fn color_stop_rgba(&self, index: isize) -> Result<(f64, f64, f64, f64, f64), Error> {
243        unsafe {
244            let mut offset = 0.0;
245            let mut red = 0.0;
246            let mut green = 0.0;
247            let mut blue = 0.0;
248            let mut alpha = 0.0;
249
250            let status = ffi::cairo_pattern_get_color_stop_rgba(
251                self.pointer,
252                index as c_int,
253                &mut offset,
254                &mut red,
255                &mut green,
256                &mut blue,
257                &mut alpha,
258            );
259            status_to_result(status)?;
260            Ok((offset, red, green, blue, alpha))
261        }
262    }
263}
264
265macro_rules! gradient_type {
266    ($gradient_type: ident) => {
267        #[derive(Debug, Clone)]
268        pub struct $gradient_type(Gradient);
269
270        impl Deref for $gradient_type {
271            type Target = Gradient;
272
273            #[inline]
274            fn deref(&self) -> &Gradient {
275                &self.0
276            }
277        }
278
279        impl AsRef<Gradient> for $gradient_type {
280            #[inline]
281            fn as_ref(&self) -> &Gradient {
282                &self.0
283            }
284        }
285
286        impl AsRef<Pattern> for $gradient_type {
287            #[inline]
288            fn as_ref(&self) -> &Pattern {
289                &self.0
290            }
291        }
292
293        convert!(Pattern => $gradient_type = $gradient_type (Gradient));
294        convert!(Gradient => $gradient_type = $gradient_type);
295    }
296}
297
298gradient_type!(LinearGradient);
299
300impl LinearGradient {
301    #[doc(alias = "cairo_pattern_create_linear")]
302    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Self {
303        unsafe {
304            Self(Gradient(Pattern::from_raw_full(
305                ffi::cairo_pattern_create_linear(x0, y0, x1, y1),
306            )))
307        }
308    }
309
310    #[doc(alias = "cairo_pattern_get_linear_points")]
311    #[doc(alias = "get_linear_points")]
312    pub fn linear_points(&self) -> Result<(f64, f64, f64, f64), Error> {
313        unsafe {
314            let mut x0 = 0.0;
315            let mut y0 = 0.0;
316            let mut x1 = 0.0;
317            let mut y1 = 0.0;
318
319            let status = ffi::cairo_pattern_get_linear_points(
320                self.pointer,
321                &mut x0,
322                &mut y0,
323                &mut x1,
324                &mut y1,
325            );
326            status_to_result(status)?;
327            Ok((x0, y0, x1, y1))
328        }
329    }
330}
331
332gradient_type!(RadialGradient);
333
334impl RadialGradient {
335    #[doc(alias = "cairo_pattern_create_radial")]
336    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> Self {
337        unsafe {
338            Self(Gradient(Pattern::from_raw_full(
339                ffi::cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1),
340            )))
341        }
342    }
343
344    #[doc(alias = "cairo_pattern_get_radial_circles")]
345    #[doc(alias = "get_radial_circles")]
346    pub fn radial_circles(&self) -> Result<(f64, f64, f64, f64, f64, f64), Error> {
347        unsafe {
348            let mut x0 = 0.0;
349            let mut y0 = 0.0;
350            let mut r0 = 0.0;
351            let mut x1 = 0.0;
352            let mut y1 = 0.0;
353            let mut r1 = 0.0;
354
355            let status = ffi::cairo_pattern_get_radial_circles(
356                self.pointer,
357                &mut x0,
358                &mut y0,
359                &mut r0,
360                &mut x1,
361                &mut y1,
362                &mut r1,
363            );
364            status_to_result(status)?;
365            Ok((x0, y0, r0, x1, y1, r1))
366        }
367    }
368}
369
370pattern_type!(SurfacePattern = Surface);
371
372impl SurfacePattern {
373    #[doc(alias = "cairo_pattern_create_for_surface")]
374    pub fn create(surface: impl AsRef<Surface>) -> Self {
375        unsafe {
376            Self(Pattern::from_raw_full(
377                ffi::cairo_pattern_create_for_surface(surface.as_ref().to_raw_none()),
378            ))
379        }
380    }
381
382    #[doc(alias = "cairo_pattern_get_surface")]
383    #[doc(alias = "get_surface")]
384    pub fn surface(&self) -> Result<Surface, Error> {
385        unsafe {
386            let mut surface_ptr: *mut ffi::cairo_surface_t = ptr::null_mut();
387            let status = ffi::cairo_pattern_get_surface(self.pointer, &mut surface_ptr);
388            status_to_result(status)?;
389            Ok(Surface::from_raw_none(surface_ptr))
390        }
391    }
392}
393
394pattern_type!(Mesh = Mesh);
395
396impl Mesh {
397    #[doc(alias = "cairo_pattern_create_mesh")]
398    pub fn new() -> Self {
399        unsafe { Self(Pattern::from_raw_full(ffi::cairo_pattern_create_mesh())) }
400    }
401
402    #[doc(alias = "cairo_mesh_pattern_begin_patch")]
403    pub fn begin_patch(&self) {
404        unsafe { ffi::cairo_mesh_pattern_begin_patch(self.pointer) }
405    }
406
407    #[doc(alias = "cairo_mesh_pattern_end_patch")]
408    pub fn end_patch(&self) {
409        unsafe { ffi::cairo_mesh_pattern_end_patch(self.pointer) }
410    }
411
412    #[doc(alias = "cairo_mesh_pattern_move_to")]
413    pub fn move_to(&self, x: f64, y: f64) {
414        unsafe { ffi::cairo_mesh_pattern_move_to(self.pointer, x, y) }
415    }
416
417    #[doc(alias = "cairo_mesh_pattern_line_to")]
418    pub fn line_to(&self, x: f64, y: f64) {
419        unsafe { ffi::cairo_mesh_pattern_line_to(self.pointer, x, y) }
420    }
421
422    #[doc(alias = "cairo_mesh_pattern_curve_to")]
423    pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
424        unsafe { ffi::cairo_mesh_pattern_curve_to(self.pointer, x1, y1, x2, y2, x3, y3) }
425    }
426
427    #[doc(alias = "cairo_mesh_pattern_set_control_point")]
428    pub fn set_control_point(&self, corner: MeshCorner, x: f64, y: f64) {
429        unsafe { ffi::cairo_mesh_pattern_set_control_point(self.pointer, corner.into(), x, y) }
430    }
431
432    #[doc(alias = "cairo_mesh_pattern_get_control_point")]
433    #[doc(alias = "get_control_point")]
434    pub fn control_point(&self, patch_num: usize, corner: MeshCorner) -> Result<(f64, f64), Error> {
435        let mut x: c_double = 0.0;
436        let mut y: c_double = 0.0;
437
438        let status = unsafe {
439            ffi::cairo_mesh_pattern_get_control_point(
440                self.pointer,
441                patch_num as c_uint,
442                corner.into(),
443                &mut x,
444                &mut y,
445            )
446        };
447        status_to_result(status)?;
448        Ok((x, y))
449    }
450
451    #[doc(alias = "cairo_mesh_pattern_set_corner_color_rgb")]
452    pub fn set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64) {
453        unsafe {
454            ffi::cairo_mesh_pattern_set_corner_color_rgb(
455                self.pointer,
456                corner.into(),
457                red,
458                green,
459                blue,
460            )
461        }
462    }
463
464    #[doc(alias = "cairo_mesh_pattern_set_corner_color_rgba")]
465    pub fn set_corner_color_rgba(
466        &self,
467        corner: MeshCorner,
468        red: f64,
469        green: f64,
470        blue: f64,
471        alpha: f64,
472    ) {
473        unsafe {
474            ffi::cairo_mesh_pattern_set_corner_color_rgba(
475                self.pointer,
476                corner.into(),
477                red,
478                green,
479                blue,
480                alpha,
481            )
482        }
483    }
484
485    #[doc(alias = "cairo_mesh_pattern_get_corner_color_rgba")]
486    #[doc(alias = "get_corner_color_rgba")]
487    pub fn corner_color_rgba(
488        &self,
489        patch_num: usize,
490        corner: MeshCorner,
491    ) -> Result<(f64, f64, f64, f64), Error> {
492        let mut red: c_double = 0.0;
493        let mut green: c_double = 0.0;
494        let mut blue: c_double = 0.0;
495        let mut alpha: c_double = 0.0;
496
497        let status = unsafe {
498            ffi::cairo_mesh_pattern_get_corner_color_rgba(
499                self.pointer,
500                patch_num as c_uint,
501                corner.into(),
502                &mut red,
503                &mut green,
504                &mut blue,
505                &mut alpha,
506            )
507        };
508        status_to_result(status)?;
509        Ok((red, green, blue, alpha))
510    }
511
512    #[doc(alias = "cairo_mesh_pattern_get_patch_count")]
513    #[doc(alias = "get_patch_count")]
514    pub fn patch_count(&self) -> Result<usize, Error> {
515        let mut count: c_uint = 0;
516        unsafe {
517            let status = ffi::cairo_mesh_pattern_get_patch_count(self.pointer, &mut count);
518            status_to_result(status)?;
519        }
520        Ok(count as usize)
521    }
522
523    #[doc(alias = "cairo_mesh_pattern_get_path")]
524    #[doc(alias = "get_path")]
525    pub fn path(&self, patch_num: usize) -> Result<Path, Error> {
526        let path: Path = unsafe {
527            Path::from_raw_full(ffi::cairo_mesh_pattern_get_path(
528                self.pointer,
529                patch_num as c_uint,
530            ))
531        };
532        let status = unsafe {
533            let ptr: *mut ffi::cairo_path_t = path.as_ptr();
534            (*ptr).status
535        };
536        status_to_result(status)?;
537        Ok(path)
538    }
539}
540
541impl Default for Mesh {
542    fn default() -> Self {
543        Self::new()
544    }
545}
546
547#[test]
548fn try_from() {
549    let linear = LinearGradient::new(0., 0., 1., 1.);
550    let gradient = Gradient::clone(&linear);
551    let pattern = Pattern::clone(&linear);
552    assert!(Gradient::try_from(pattern.clone()).is_ok());
553    assert!(LinearGradient::try_from(gradient).is_ok());
554    assert!(LinearGradient::try_from(pattern).is_ok());
555}