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