Skip to main content

cairo/
patterns.rs

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