cairo/
context.rs

1// Copyright 2013-2015, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use ffi;
6use font::{FontExtents, FontFace, FontOptions, Glyph, ScaledFont, TextCluster, TextExtents};
7#[cfg(feature = "use_glib")]
8use glib::translate::*;
9use libc::c_int;
10use matrices::Matrix;
11use paths::Path;
12use std::ffi::CString;
13use std::fmt;
14use std::ops;
15use std::slice;
16use Rectangle;
17use {
18    Antialias, Content, FillRule, FontSlant, FontWeight, LineCap, LineJoin, Operator, Status,
19    TextClusterFlags,
20};
21
22use ffi::{cairo_rectangle_list_t, cairo_t};
23use patterns::Pattern;
24use surface::Surface;
25
26pub struct RectangleList {
27    ptr: *mut cairo_rectangle_list_t,
28}
29
30impl ops::Deref for RectangleList {
31    type Target = [Rectangle];
32
33    fn deref(&self) -> &[Rectangle] {
34        unsafe {
35            let ptr = (*self.ptr).rectangles as *mut Rectangle;
36            let len = (*self.ptr).num_rectangles;
37
38            if ptr.is_null() || len == 0 {
39                &[]
40            } else {
41                slice::from_raw_parts(ptr, len as usize)
42            }
43        }
44    }
45}
46
47impl Drop for RectangleList {
48    fn drop(&mut self) {
49        unsafe {
50            ffi::cairo_rectangle_list_destroy(self.ptr);
51        }
52    }
53}
54
55impl fmt::Debug for RectangleList {
56    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57        f.debug_tuple("RectangleList").field(&*self).finish()
58    }
59}
60
61impl fmt::Display for RectangleList {
62    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63        write!(f, "RectangleList")
64    }
65}
66
67#[derive(Debug)]
68pub struct Context(*mut cairo_t, bool);
69
70#[cfg(feature = "use_glib")]
71impl<'a> ToGlibPtr<'a, *mut ffi::cairo_t> for &'a Context {
72    type Storage = &'a Context;
73
74    #[inline]
75    fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_t, &'a Context> {
76        Stash(self.0, *self)
77    }
78
79    #[inline]
80    fn to_glib_full(&self) -> *mut ffi::cairo_t {
81        unsafe { ffi::cairo_reference(self.0) }
82    }
83}
84
85#[cfg(feature = "use_glib")]
86impl FromGlibPtrNone<*mut ffi::cairo_t> for Context {
87    #[inline]
88    unsafe fn from_glib_none(ptr: *mut ffi::cairo_t) -> Context {
89        Self::from_raw_none(ptr)
90    }
91}
92
93#[cfg(feature = "use_glib")]
94impl FromGlibPtrBorrow<*mut ffi::cairo_t> for Context {
95    #[inline]
96    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_t) -> Context {
97        Self::from_raw_borrow(ptr)
98    }
99}
100
101#[cfg(feature = "use_glib")]
102impl FromGlibPtrFull<*mut ffi::cairo_t> for Context {
103    #[inline]
104    unsafe fn from_glib_full(ptr: *mut ffi::cairo_t) -> Context {
105        Self::from_raw_full(ptr)
106    }
107}
108
109#[cfg(feature = "use_glib")]
110gvalue_impl!(
111    Context,
112    cairo_t,
113    ffi::gobject::cairo_gobject_context_get_type
114);
115
116impl Clone for Context {
117    fn clone(&self) -> Context {
118        unsafe { Self::from_raw_none(self.to_raw_none()) }
119    }
120}
121
122impl Drop for Context {
123    fn drop(&mut self) {
124        if !self.1 {
125            unsafe {
126                ffi::cairo_destroy(self.0);
127            }
128        }
129    }
130}
131
132impl Context {
133    #[inline]
134    pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_t) -> Context {
135        assert!(!ptr.is_null());
136        ffi::cairo_reference(ptr);
137        Context(ptr, false)
138    }
139
140    #[inline]
141    pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_t) -> Context {
142        assert!(!ptr.is_null());
143        Context(ptr, true)
144    }
145
146    #[inline]
147    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_t) -> Context {
148        assert!(!ptr.is_null());
149        Context(ptr, false)
150    }
151
152    pub fn to_raw_none(&self) -> *mut ffi::cairo_t {
153        self.0
154    }
155
156    pub fn ensure_status(&self) {
157        self.status().ensure_valid();
158    }
159
160    pub fn new(target: &Surface) -> Context {
161        unsafe { Self::from_raw_full(ffi::cairo_create(target.to_raw_none())) }
162    }
163
164    pub fn status(&self) -> Status {
165        unsafe { Status::from(ffi::cairo_status(self.0)) }
166    }
167
168    pub fn save(&self) {
169        unsafe { ffi::cairo_save(self.0) }
170        self.ensure_status()
171    }
172
173    pub fn restore(&self) {
174        unsafe { ffi::cairo_restore(self.0) }
175        self.ensure_status()
176    }
177
178    pub fn get_target(&self) -> Surface {
179        unsafe { Surface::from_raw_none(ffi::cairo_get_target(self.0)) }
180    }
181
182    pub fn push_group(&self) {
183        unsafe { ffi::cairo_push_group(self.0) }
184    }
185
186    pub fn push_group_with_content(&self, content: Content) {
187        unsafe { ffi::cairo_push_group_with_content(self.0, content.into()) }
188    }
189
190    pub fn pop_group(&self) -> Pattern {
191        unsafe { Pattern::from_raw_full(ffi::cairo_pop_group(self.0)) }
192    }
193
194    pub fn pop_group_to_source(&self) {
195        unsafe { ffi::cairo_pop_group_to_source(self.0) }
196    }
197
198    pub fn get_group_target(&self) -> Surface {
199        unsafe { Surface::from_raw_none(ffi::cairo_get_group_target(self.0)) }
200    }
201
202    pub fn set_source_rgb(&self, red: f64, green: f64, blue: f64) {
203        unsafe { ffi::cairo_set_source_rgb(self.0, red, green, blue) }
204    }
205
206    pub fn set_source_rgba(&self, red: f64, green: f64, blue: f64, alpha: f64) {
207        unsafe { ffi::cairo_set_source_rgba(self.0, red, green, blue, alpha) }
208    }
209
210    pub fn set_source(&self, source: &Pattern) {
211        unsafe {
212            ffi::cairo_set_source(self.0, source.to_raw_none());
213        }
214        self.ensure_status();
215    }
216
217    pub fn get_source(&self) -> Pattern {
218        unsafe { Pattern::from_raw_none(ffi::cairo_get_source(self.0)) }
219    }
220
221    pub fn set_source_surface(&self, surface: &Surface, x: f64, y: f64) {
222        unsafe {
223            ffi::cairo_set_source_surface(self.0, surface.to_raw_none(), x, y);
224        }
225    }
226
227    pub fn set_antialias(&self, antialias: Antialias) {
228        unsafe { ffi::cairo_set_antialias(self.0, antialias.into()) }
229        self.ensure_status()
230    }
231
232    pub fn get_antialias(&self) -> Antialias {
233        unsafe { Antialias::from(ffi::cairo_get_antialias(self.0)) }
234    }
235
236    pub fn set_dash(&self, dashes: &[f64], offset: f64) {
237        unsafe { ffi::cairo_set_dash(self.0, dashes.as_ptr(), dashes.len() as i32, offset) }
238        self.ensure_status(); //Possible invalid dashes value
239    }
240
241    pub fn get_dash_count(&self) -> i32 {
242        unsafe { ffi::cairo_get_dash_count(self.0) }
243    }
244
245    pub fn get_dash(&self) -> (Vec<f64>, f64) {
246        let dash_count = self.get_dash_count() as usize;
247        let mut dashes: Vec<f64> = Vec::with_capacity(dash_count);
248        let mut offset: f64 = 0.0;
249
250        unsafe {
251            ffi::cairo_get_dash(self.0, dashes.as_mut_ptr(), &mut offset);
252            dashes.set_len(dash_count);
253            (dashes, offset)
254        }
255    }
256
257    pub fn get_dash_dashes(&self) -> Vec<f64> {
258        let (dashes, _) = self.get_dash();
259        dashes
260    }
261
262    pub fn get_dash_offset(&self) -> f64 {
263        let (_, offset) = self.get_dash();
264        offset
265    }
266
267    pub fn set_fill_rule(&self, fill_rule: FillRule) {
268        unsafe {
269            ffi::cairo_set_fill_rule(self.0, fill_rule.into());
270        }
271        self.ensure_status();
272    }
273
274    pub fn get_fill_rule(&self) -> FillRule {
275        unsafe { FillRule::from(ffi::cairo_get_fill_rule(self.0)) }
276    }
277
278    pub fn set_line_cap(&self, arg: LineCap) {
279        unsafe { ffi::cairo_set_line_cap(self.0, arg.into()) }
280        self.ensure_status();
281    }
282
283    pub fn get_line_cap(&self) -> LineCap {
284        unsafe { LineCap::from(ffi::cairo_get_line_cap(self.0)) }
285    }
286
287    pub fn set_line_join(&self, arg: LineJoin) {
288        unsafe { ffi::cairo_set_line_join(self.0, arg.into()) }
289        self.ensure_status();
290    }
291
292    pub fn get_line_join(&self) -> LineJoin {
293        unsafe { LineJoin::from(ffi::cairo_get_line_join(self.0)) }
294    }
295
296    pub fn set_line_width(&self, arg: f64) {
297        unsafe { ffi::cairo_set_line_width(self.0, arg) }
298        self.ensure_status();
299    }
300
301    pub fn get_line_width(&self) -> f64 {
302        unsafe { ffi::cairo_get_line_width(self.0) }
303    }
304
305    pub fn set_miter_limit(&self, arg: f64) {
306        unsafe { ffi::cairo_set_miter_limit(self.0, arg) }
307        self.ensure_status();
308    }
309
310    pub fn get_miter_limit(&self) -> f64 {
311        unsafe { ffi::cairo_get_miter_limit(self.0) }
312    }
313
314    pub fn set_operator(&self, op: Operator) {
315        unsafe {
316            ffi::cairo_set_operator(self.0, op.into());
317        }
318    }
319
320    pub fn get_operator(&self) -> Operator {
321        unsafe { Operator::from(ffi::cairo_get_operator(self.0)) }
322    }
323
324    pub fn set_tolerance(&self, arg: f64) {
325        unsafe { ffi::cairo_set_tolerance(self.0, arg) }
326        self.ensure_status();
327    }
328
329    pub fn get_tolerance(&self) -> f64 {
330        unsafe { ffi::cairo_get_tolerance(self.0) }
331    }
332
333    pub fn clip(&self) {
334        unsafe { ffi::cairo_clip(self.0) }
335    }
336
337    pub fn clip_preserve(&self) {
338        unsafe { ffi::cairo_clip_preserve(self.0) }
339    }
340
341    pub fn clip_extents(&self) -> (f64, f64, f64, f64) {
342        let mut x1: f64 = 0.0;
343        let mut y1: f64 = 0.0;
344        let mut x2: f64 = 0.0;
345        let mut y2: f64 = 0.0;
346
347        unsafe {
348            ffi::cairo_clip_extents(self.0, &mut x1, &mut y1, &mut x2, &mut y2);
349        }
350        (x1, y1, x2, y2)
351    }
352
353    pub fn in_clip(&self, x: f64, y: f64) -> bool {
354        unsafe { ffi::cairo_in_clip(self.0, x, y).as_bool() }
355    }
356
357    pub fn reset_clip(&self) {
358        unsafe { ffi::cairo_reset_clip(self.0) }
359        self.ensure_status()
360    }
361
362    pub fn copy_clip_rectangle_list(&self) -> RectangleList {
363        unsafe {
364            let rectangle_list = ffi::cairo_copy_clip_rectangle_list(self.0);
365
366            Status::from((*rectangle_list).status).ensure_valid();
367
368            RectangleList {
369                ptr: rectangle_list,
370            }
371        }
372    }
373
374    pub fn fill(&self) {
375        unsafe { ffi::cairo_fill(self.0) }
376    }
377
378    pub fn fill_preserve(&self) {
379        unsafe { ffi::cairo_fill_preserve(self.0) }
380    }
381
382    pub fn fill_extents(&self) -> (f64, f64, f64, f64) {
383        let mut x1: f64 = 0.0;
384        let mut y1: f64 = 0.0;
385        let mut x2: f64 = 0.0;
386        let mut y2: f64 = 0.0;
387
388        unsafe {
389            ffi::cairo_fill_extents(self.0, &mut x1, &mut y1, &mut x2, &mut y2);
390        }
391        (x1, y1, x2, y2)
392    }
393
394    pub fn in_fill(&self, x: f64, y: f64) -> bool {
395        unsafe { ffi::cairo_in_fill(self.0, x, y).as_bool() }
396    }
397
398    pub fn mask(&self, pattern: &Pattern) {
399        unsafe { ffi::cairo_mask(self.0, pattern.to_raw_none()) }
400    }
401
402    pub fn mask_surface(&self, surface: &Surface, x: f64, y: f64) {
403        unsafe {
404            ffi::cairo_mask_surface(self.0, surface.to_raw_none(), x, y);
405        }
406    }
407
408    pub fn paint(&self) {
409        unsafe { ffi::cairo_paint(self.0) }
410    }
411
412    pub fn paint_with_alpha(&self, alpha: f64) {
413        unsafe { ffi::cairo_paint_with_alpha(self.0, alpha) }
414    }
415
416    pub fn stroke(&self) {
417        unsafe { ffi::cairo_stroke(self.0) }
418    }
419
420    pub fn stroke_preserve(&self) {
421        unsafe { ffi::cairo_stroke_preserve(self.0) }
422    }
423
424    pub fn stroke_extents(&self) -> (f64, f64, f64, f64) {
425        let mut x1: f64 = 0.0;
426        let mut y1: f64 = 0.0;
427        let mut x2: f64 = 0.0;
428        let mut y2: f64 = 0.0;
429
430        unsafe {
431            ffi::cairo_stroke_extents(self.0, &mut x1, &mut y1, &mut x2, &mut y2);
432        }
433        (x1, y1, x2, y2)
434    }
435
436    pub fn in_stroke(&self, x: f64, y: f64) -> bool {
437        unsafe { ffi::cairo_in_stroke(self.0, x, y).as_bool() }
438    }
439
440    pub fn copy_page(&self) {
441        unsafe { ffi::cairo_copy_page(self.0) }
442    }
443
444    pub fn show_page(&self) {
445        unsafe { ffi::cairo_show_page(self.0) }
446    }
447
448    pub fn get_reference_count(&self) -> u32 {
449        unsafe { ffi::cairo_get_reference_count(self.0) }
450    }
451
452    // transformations stuff
453
454    pub fn translate(&self, tx: f64, ty: f64) {
455        unsafe { ffi::cairo_translate(self.0, tx, ty) }
456    }
457
458    pub fn scale(&self, sx: f64, sy: f64) {
459        unsafe { ffi::cairo_scale(self.0, sx, sy) }
460    }
461
462    pub fn rotate(&self, angle: f64) {
463        unsafe { ffi::cairo_rotate(self.0, angle) }
464    }
465
466    pub fn transform(&self, matrix: Matrix) {
467        unsafe {
468            ffi::cairo_transform(self.0, matrix.ptr());
469        }
470    }
471
472    pub fn set_matrix(&self, matrix: Matrix) {
473        unsafe {
474            ffi::cairo_set_matrix(self.0, matrix.ptr());
475        }
476    }
477
478    pub fn get_matrix(&self) -> Matrix {
479        let mut matrix = Matrix::null();
480        unsafe {
481            ffi::cairo_get_matrix(self.0, matrix.mut_ptr());
482        }
483        matrix
484    }
485
486    pub fn identity_matrix(&self) {
487        unsafe { ffi::cairo_identity_matrix(self.0) }
488    }
489
490    pub fn user_to_device(&self, mut x: f64, mut y: f64) -> (f64, f64) {
491        unsafe {
492            ffi::cairo_user_to_device(self.0, &mut x, &mut y);
493            (x, y)
494        }
495    }
496
497    pub fn user_to_device_distance(&self, mut dx: f64, mut dy: f64) -> (f64, f64) {
498        unsafe {
499            ffi::cairo_user_to_device_distance(self.0, &mut dx, &mut dy);
500            (dx, dy)
501        }
502    }
503
504    pub fn device_to_user(&self, mut x: f64, mut y: f64) -> (f64, f64) {
505        unsafe {
506            ffi::cairo_device_to_user(self.0, &mut x, &mut y);
507            (x, y)
508        }
509    }
510
511    pub fn device_to_user_distance(&self, mut dx: f64, mut dy: f64) -> (f64, f64) {
512        unsafe {
513            ffi::cairo_device_to_user_distance(self.0, &mut dx, &mut dy);
514            (dx, dy)
515        }
516    }
517
518    // font stuff
519
520    pub fn select_font_face(&self, family: &str, slant: FontSlant, weight: FontWeight) {
521        unsafe {
522            let family = CString::new(family).unwrap();
523            ffi::cairo_select_font_face(self.0, family.as_ptr(), slant.into(), weight.into())
524        }
525    }
526
527    pub fn set_font_size(&self, size: f64) {
528        unsafe { ffi::cairo_set_font_size(self.0, size) }
529    }
530
531    // FIXME probably needs a heap allocation
532    pub fn set_font_matrix(&self, matrix: Matrix) {
533        unsafe { ffi::cairo_set_font_matrix(self.0, matrix.ptr()) }
534    }
535
536    pub fn get_font_matrix(&self) -> Matrix {
537        let mut matrix = Matrix::null();
538        unsafe {
539            ffi::cairo_get_font_matrix(self.0, matrix.mut_ptr());
540        }
541        matrix
542    }
543
544    pub fn set_font_options(&self, options: &FontOptions) {
545        unsafe { ffi::cairo_set_font_options(self.0, options.to_raw_none()) }
546    }
547
548    pub fn get_font_options(&self) -> FontOptions {
549        let out = FontOptions::new();
550        unsafe {
551            ffi::cairo_get_font_options(self.0, out.to_raw_none());
552        }
553        out
554    }
555
556    pub fn set_font_face(&self, font_face: &FontFace) {
557        unsafe { ffi::cairo_set_font_face(self.0, font_face.to_raw_none()) }
558    }
559
560    pub fn get_font_face(&self) -> FontFace {
561        unsafe { FontFace::from_raw_none(ffi::cairo_get_font_face(self.0)) }
562    }
563
564    pub fn set_scaled_font(&self, scaled_font: &ScaledFont) {
565        unsafe { ffi::cairo_set_scaled_font(self.0, scaled_font.to_raw_none()) }
566    }
567
568    pub fn get_scaled_font(&self) -> ScaledFont {
569        unsafe { ScaledFont::from_raw_none(ffi::cairo_get_scaled_font(self.0)) }
570    }
571
572    pub fn show_text(&self, text: &str) {
573        unsafe {
574            let text = CString::new(text).unwrap();
575            ffi::cairo_show_text(self.0, text.as_ptr())
576        }
577    }
578
579    pub fn show_glyphs(&self, glyphs: &[Glyph]) {
580        unsafe { ffi::cairo_show_glyphs(self.0, glyphs.as_ptr(), glyphs.len() as c_int) }
581    }
582
583    pub fn show_text_glyphs(
584        &self,
585        text: &str,
586        glyphs: &[Glyph],
587        clusters: &[TextCluster],
588        cluster_flags: TextClusterFlags,
589    ) {
590        unsafe {
591            let text = CString::new(text).unwrap();
592            ffi::cairo_show_text_glyphs(
593                self.0,
594                text.as_ptr(),
595                -1 as c_int, //NULL terminated
596                glyphs.as_ptr(),
597                glyphs.len() as c_int,
598                clusters.as_ptr(),
599                clusters.len() as c_int,
600                cluster_flags.into(),
601            )
602        }
603    }
604
605    pub fn font_extents(&self) -> FontExtents {
606        let mut extents = FontExtents {
607            ascent: 0.0,
608            descent: 0.0,
609            height: 0.0,
610            max_x_advance: 0.0,
611            max_y_advance: 0.0,
612        };
613
614        unsafe {
615            ffi::cairo_font_extents(self.0, &mut extents);
616        }
617
618        extents
619    }
620
621    pub fn text_extents(&self, text: &str) -> TextExtents {
622        let mut extents = TextExtents {
623            x_bearing: 0.0,
624            y_bearing: 0.0,
625            width: 0.0,
626            height: 0.0,
627            x_advance: 0.0,
628            y_advance: 0.0,
629        };
630
631        unsafe {
632            let text = CString::new(text).unwrap();
633            ffi::cairo_text_extents(self.0, text.as_ptr(), &mut extents);
634        }
635        extents
636    }
637
638    pub fn glyph_extents(&self, glyphs: &[Glyph]) -> TextExtents {
639        let mut extents = TextExtents {
640            x_bearing: 0.0,
641            y_bearing: 0.0,
642            width: 0.0,
643            height: 0.0,
644            x_advance: 0.0,
645            y_advance: 0.0,
646        };
647
648        unsafe {
649            ffi::cairo_glyph_extents(self.0, glyphs.as_ptr(), glyphs.len() as c_int, &mut extents);
650        }
651
652        extents
653    }
654
655    // paths stuff
656
657    pub fn copy_path(&self) -> Path {
658        unsafe { Path::from_raw_full(ffi::cairo_copy_path(self.0)) }
659    }
660
661    pub fn copy_path_flat(&self) -> Path {
662        unsafe { Path::from_raw_full(ffi::cairo_copy_path_flat(self.0)) }
663    }
664
665    pub fn append_path(&self, path: &Path) {
666        unsafe { ffi::cairo_append_path(self.0, path.as_ptr()) }
667    }
668
669    pub fn has_current_point(&self) -> bool {
670        unsafe { ffi::cairo_has_current_point(self.0).as_bool() }
671    }
672
673    pub fn get_current_point(&self) -> (f64, f64) {
674        unsafe {
675            let mut x = 0.0;
676            let mut y = 0.0;
677            ffi::cairo_get_current_point(self.0, &mut x, &mut y);
678            (x, y)
679        }
680    }
681
682    pub fn new_path(&self) {
683        unsafe { ffi::cairo_new_path(self.0) }
684    }
685
686    pub fn new_sub_path(&self) {
687        unsafe { ffi::cairo_new_sub_path(self.0) }
688    }
689
690    pub fn close_path(&self) {
691        unsafe { ffi::cairo_close_path(self.0) }
692    }
693
694    pub fn arc(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) {
695        unsafe { ffi::cairo_arc(self.0, xc, yc, radius, angle1, angle2) }
696    }
697
698    pub fn arc_negative(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) {
699        unsafe { ffi::cairo_arc_negative(self.0, xc, yc, radius, angle1, angle2) }
700    }
701
702    pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
703        unsafe { ffi::cairo_curve_to(self.0, x1, y1, x2, y2, x3, y3) }
704    }
705
706    pub fn line_to(&self, x: f64, y: f64) {
707        unsafe { ffi::cairo_line_to(self.0, x, y) }
708    }
709
710    pub fn move_to(&self, x: f64, y: f64) {
711        unsafe { ffi::cairo_move_to(self.0, x, y) }
712    }
713
714    pub fn rectangle(&self, x: f64, y: f64, width: f64, height: f64) {
715        unsafe { ffi::cairo_rectangle(self.0, x, y, width, height) }
716    }
717
718    pub fn text_path(&self, str_: &str) {
719        unsafe {
720            let str_ = CString::new(str_).unwrap();
721            ffi::cairo_text_path(self.0, str_.as_ptr())
722        }
723    }
724
725    pub fn glyph_path(&self, glyphs: &[Glyph]) {
726        unsafe { ffi::cairo_glyph_path(self.0, glyphs.as_ptr(), glyphs.len() as i32) }
727    }
728
729    pub fn rel_curve_to(&self, dx1: f64, dy1: f64, dx2: f64, dy2: f64, dx3: f64, dy3: f64) {
730        unsafe { ffi::cairo_rel_curve_to(self.0, dx1, dy1, dx2, dy2, dx3, dy3) }
731    }
732
733    pub fn rel_line_to(&self, dx: f64, dy: f64) {
734        unsafe { ffi::cairo_rel_line_to(self.0, dx, dy) }
735    }
736
737    pub fn rel_move_to(&self, dx: f64, dy: f64) {
738        unsafe { ffi::cairo_rel_move_to(self.0, dx, dy) }
739    }
740
741    pub fn path_extents(&self) -> (f64, f64, f64, f64) {
742        let mut x1: f64 = 0.0;
743        let mut y1: f64 = 0.0;
744        let mut x2: f64 = 0.0;
745        let mut y2: f64 = 0.0;
746
747        unsafe {
748            ffi::cairo_path_extents(self.0, &mut x1, &mut y1, &mut x2, &mut y2);
749        }
750        (x1, y1, x2, y2)
751    }
752
753    #[cfg(any(feature = "v1_16", feature = "dox"))]
754    pub fn tag_begin(&self, tag_name: &str, attributes: &str) {
755        unsafe {
756            let tag_name = CString::new(tag_name).unwrap();
757            let attributes = CString::new(attributes).unwrap();
758            ffi::cairo_tag_begin(self.0, tag_name.as_ptr(), attributes.as_ptr())
759        }
760    }
761
762    #[cfg(any(feature = "v1_16", feature = "dox"))]
763    pub fn tag_end(&self, tag_name: &str) {
764        unsafe {
765            let tag_name = CString::new(tag_name).unwrap();
766            ffi::cairo_tag_end(self.0, tag_name.as_ptr())
767        }
768    }
769}
770
771impl fmt::Display for Context {
772    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
773        write!(f, "Context")
774    }
775}
776
777#[cfg(test)]
778mod tests {
779    use super::*;
780    use enums::Format;
781    use image_surface::ImageSurface;
782    use patterns::LinearGradient;
783
784    fn create_ctx() -> Context {
785        let surface = ImageSurface::create(Format::ARgb32, 10, 10).unwrap();
786        Context::new(&surface)
787    }
788
789    #[test]
790    fn drop_non_reference_pattern_from_ctx() {
791        let ctx = create_ctx();
792        ctx.get_source();
793    }
794
795    #[test]
796    fn drop_non_reference_pattern() {
797        let ctx = create_ctx();
798        let pattern = LinearGradient::new(1.0f64, 2.0f64, 3.0f64, 4.0f64);
799        ctx.set_source(&pattern);
800    }
801}