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