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