1use 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#[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 ($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}