1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::enums::MeshCorner;
4 use crate::enums::{Extend, Filter, PatternType};
5 use crate::error::Error;
6 use crate::ffi::{cairo_pattern_t, cairo_surface_t};
7 use crate::utils::status_to_result;
8 use crate::{Matrix, Path, Surface};
9 use libc::{c_double, c_int, c_uint};
10 use std::convert::TryFrom;
11 use std::fmt;
12 use std::ops::Deref;
13 use std::ptr;
14 
15 // See https://cairographics.org/manual/bindings-patterns.html for more info
16 #[derive(Debug)]
17 pub struct Pattern {
18     pointer: *mut cairo_pattern_t,
19 }
20 
21 impl fmt::Display for Pattern {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result22     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23         write!(f, "Pattern")
24     }
25 }
26 
27 impl Pattern {
28     user_data_methods! {
29         ffi::cairo_pattern_get_user_data,
30         ffi::cairo_pattern_set_user_data,
31     }
32 
to_raw_none(&self) -> *mut cairo_pattern_t33     pub fn to_raw_none(&self) -> *mut cairo_pattern_t {
34         self.pointer
35     }
36 
from_raw_none(pointer: *mut cairo_pattern_t) -> Pattern37     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 
from_raw_full(pointer: *mut cairo_pattern_t) -> Pattern42     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")]
type_(&self) -> PatternType48     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")]
reference_count(&self) -> isize54     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")]
set_extend(&self, extend: 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")]
extend(&self) -> Extend65     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")]
set_filter(&self, filter: 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")]
filter(&self) -> Filter76     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")]
set_matrix(&self, matrix: 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")]
matrix(&self) -> Matrix87     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")]
status(&self) -> Result<(), Error>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 
102 impl Clone for Pattern {
clone(&self) -> Self103     fn clone(&self) -> Self {
104         Self {
105             pointer: unsafe { ffi::cairo_pattern_reference(self.pointer) },
106         }
107     }
108 }
109 
110 impl Drop for Pattern {
drop(&mut self)111     fn drop(&mut self) {
112         unsafe { ffi::cairo_pattern_destroy(self.pointer) }
113     }
114 }
115 
116 macro_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 
136 macro_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 
163 pattern_type!(SolidPattern = Solid);
164 
165 impl SolidPattern {
166     #[doc(alias = "cairo_pattern_create_rgb")]
from_rgb(red: f64, green: f64, blue: f64) -> Self167     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")]
from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> Self176     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")]
rgba(&self) -> Result<(f64, f64, f64, f64), Error>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 
207 pattern_type!(Gradient);
208 convert!(Pattern => Gradient = LinearGradient | RadialGradient);
209 
210 impl Gradient {
211     #[doc(alias = "cairo_pattern_add_color_stop_rgb")]
add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64)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")]
add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64)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")]
color_stop_count(&self) -> Result<isize, Error>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")]
color_stop_rgba(&self, index: isize) -> Result<(f64, f64, f64, f64, f64), Error>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 
260 macro_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 
284 gradient_type!(LinearGradient);
285 
286 impl LinearGradient {
287     #[doc(alias = "cairo_pattern_create_linear")]
new(x0: f64, y0: f64, x1: f64, y1: f64) -> Self288     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")]
linear_points(&self) -> Result<(f64, f64, f64, f64), Error>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 
318 gradient_type!(RadialGradient);
319 
320 impl RadialGradient {
321     #[doc(alias = "cairo_pattern_create_radial")]
new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> Self322     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")]
radial_circles(&self) -> Result<(f64, f64, f64, f64, f64, f64), Error>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 
356 pattern_type!(SurfacePattern = Surface);
357 
358 impl SurfacePattern {
359     #[doc(alias = "cairo_pattern_create_for_surface")]
create(surface: &Surface) -> Self360     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")]
surface(&self) -> Result<Surface, Error>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 
380 pattern_type!(Mesh = Mesh);
381 
382 impl Mesh {
383     #[doc(alias = "cairo_pattern_create_mesh")]
new() -> Self384     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")]
begin_patch(&self)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")]
end_patch(&self)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")]
move_to(&self, x: f64, y: f64)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")]
line_to(&self, x: f64, y: f64)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")]
curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64)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")]
set_control_point(&self, corner: MeshCorner, x: f64, y: f64)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")]
control_point(&self, patch_num: usize, corner: MeshCorner) -> Result<(f64, f64), Error>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")]
set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64)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")]
set_corner_color_rgba( &self, corner: MeshCorner, red: f64, green: f64, blue: f64, alpha: f64, )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")]
corner_color_rgba( &self, patch_num: usize, corner: MeshCorner, ) -> Result<(f64, f64, f64, f64), Error>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")]
patch_count(&self) -> Result<usize, Error>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")]
path(&self, patch_num: usize) -> Result<Path, Error>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 
527 impl Default for Mesh {
default() -> Self528     fn default() -> Self {
529         Self::new()
530     }
531 }
532 
533 #[test]
try_from()534 fn 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 }
542