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