1#[cfg(feature = "use_glib")]
4use std::marker::PhantomData;
5use std::{ffi::CString, fmt, mem::MaybeUninit, ops, ptr, slice};
6
7#[cfg(feature = "use_glib")]
8use glib::translate::*;
9
10use crate::{
11 Antialias, Content, Error, FillRule, FontExtents, FontFace, FontOptions, FontSlant, FontWeight,
12 Glyph, LineCap, LineJoin, Matrix, Operator, Path, Pattern, Rectangle, ScaledFont, Surface,
13 TextCluster, TextClusterFlags, TextExtents, ffi, utils::status_to_result,
14};
15
16pub struct RectangleList {
17 ptr: *mut ffi::cairo_rectangle_list_t,
18}
19
20impl ops::Deref for RectangleList {
21 type Target = [Rectangle];
22
23 #[inline]
24 fn deref(&self) -> &[Rectangle] {
25 unsafe {
26 let ptr = (*self.ptr).rectangles as *mut Rectangle;
27 let len = (*self.ptr).num_rectangles;
28
29 if ptr.is_null() || len == 0 {
30 &[]
31 } else {
32 slice::from_raw_parts(ptr, len as usize)
33 }
34 }
35 }
36}
37
38impl Drop for RectangleList {
39 #[inline]
40 fn drop(&mut self) {
41 unsafe {
42 ffi::cairo_rectangle_list_destroy(self.ptr);
43 }
44 }
45}
46
47impl fmt::Debug for RectangleList {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 use std::ops::Deref;
50 f.debug_tuple("RectangleList").field(&self.deref()).finish()
51 }
52}
53
54#[derive(Debug)]
55#[repr(transparent)]
56#[doc(alias = "cairo_t")]
57pub struct Context(ptr::NonNull<ffi::cairo_t>);
58
59#[cfg(feature = "use_glib")]
60#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
61impl IntoGlibPtr<*mut ffi::cairo_t> for Context {
62 #[inline]
63 fn into_glib_ptr(self) -> *mut ffi::cairo_t {
64 (&*std::mem::ManuallyDrop::new(self)).to_glib_none().0
65 }
66}
67
68#[cfg(feature = "use_glib")]
69#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
70impl<'a> ToGlibPtr<'a, *mut ffi::cairo_t> for &'a Context {
71 type Storage = PhantomData<&'a Context>;
72
73 #[inline]
74 fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_t, &'a Context> {
75 Stash(self.0.as_ptr(), PhantomData)
76 }
77
78 #[inline]
79 fn to_glib_full(&self) -> *mut ffi::cairo_t {
80 unsafe { ffi::cairo_reference(self.0.as_ptr()) }
81 }
82}
83
84#[cfg(feature = "use_glib")]
85#[cfg_attr(docsrs, doc(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 unsafe { Self::from_raw_none(ptr) }
90 }
91}
92
93#[cfg(feature = "use_glib")]
94#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
95impl FromGlibPtrBorrow<*mut ffi::cairo_t> for Context {
96 #[inline]
97 unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_t) -> crate::Borrowed<Context> {
98 unsafe { Self::from_raw_borrow(ptr) }
99 }
100}
101
102#[cfg(feature = "use_glib")]
103#[cfg_attr(docsrs, doc(cfg(feature = "use_glib")))]
104impl FromGlibPtrFull<*mut ffi::cairo_t> for Context {
105 #[inline]
106 unsafe fn from_glib_full(ptr: *mut ffi::cairo_t) -> Context {
107 unsafe { Self::from_raw_full(ptr) }
108 }
109}
110
111#[cfg(feature = "use_glib")]
112gvalue_impl!(
113 Context,
114 ffi::cairo_t,
115 ffi::gobject::cairo_gobject_context_get_type
116);
117
118impl Clone for Context {
119 #[inline]
120 fn clone(&self) -> Context {
121 unsafe { Self::from_raw_none(self.to_raw_none()) }
122 }
123}
124
125impl Drop for Context {
126 #[inline]
127 fn drop(&mut self) {
128 unsafe {
129 ffi::cairo_destroy(self.0.as_ptr());
130 }
131 }
132}
133
134impl Context {
135 #[inline]
136 pub unsafe fn from_raw_none(ptr: *mut ffi::cairo_t) -> Context {
137 unsafe {
138 debug_assert!(!ptr.is_null());
139 ffi::cairo_reference(ptr);
140 Context(ptr::NonNull::new_unchecked(ptr))
141 }
142 }
143
144 #[inline]
145 pub unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_t) -> crate::Borrowed<Context> {
146 unsafe {
147 debug_assert!(!ptr.is_null());
148 crate::Borrowed::new(Context(ptr::NonNull::new_unchecked(ptr)))
149 }
150 }
151
152 #[inline]
153 pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_t) -> Context {
154 unsafe {
155 debug_assert!(!ptr.is_null());
156 Context(ptr::NonNull::new_unchecked(ptr))
157 }
158 }
159
160 #[inline]
161 pub fn to_raw_none(&self) -> *mut ffi::cairo_t {
162 self.0.as_ptr()
163 }
164
165 #[doc(alias = "cairo_status")]
166 #[inline]
167 pub fn status(&self) -> Result<(), Error> {
168 let status = unsafe { ffi::cairo_status(self.0.as_ptr()) };
169 status_to_result(status)
170 }
171
172 pub fn new(target: impl AsRef<Surface>) -> Result<Context, Error> {
173 let ctx = unsafe { Self::from_raw_full(ffi::cairo_create(target.as_ref().to_raw_none())) };
174 ctx.status().map(|_| ctx)
175 }
176
177 #[doc(alias = "cairo_save")]
178 pub fn save(&self) -> Result<(), Error> {
179 unsafe { ffi::cairo_save(self.0.as_ptr()) }
180 self.status()
181 }
182
183 #[doc(alias = "cairo_restore")]
184 pub fn restore(&self) -> Result<(), Error> {
185 unsafe { ffi::cairo_restore(self.0.as_ptr()) }
186 self.status()
187 }
188
189 #[doc(alias = "get_target")]
190 #[doc(alias = "cairo_get_target")]
191 pub fn target(&self) -> Surface {
192 unsafe { Surface::from_raw_none(ffi::cairo_get_target(self.0.as_ptr())) }
193 }
194
195 #[doc(alias = "cairo_push_group")]
196 pub fn push_group(&self) {
197 unsafe { ffi::cairo_push_group(self.0.as_ptr()) }
198 }
199
200 #[doc(alias = "cairo_push_group_with_content")]
201 pub fn push_group_with_content(&self, content: Content) {
202 unsafe { ffi::cairo_push_group_with_content(self.0.as_ptr(), content.into()) }
203 }
204
205 #[doc(alias = "cairo_pop_group")]
206 pub fn pop_group(&self) -> Result<Pattern, Error> {
207 let pattern = unsafe { Pattern::from_raw_full(ffi::cairo_pop_group(self.0.as_ptr())) };
208 self.status().map(|_| pattern)
209 }
210
211 #[doc(alias = "cairo_pop_group_to_source")]
212 pub fn pop_group_to_source(&self) -> Result<(), Error> {
213 unsafe { ffi::cairo_pop_group_to_source(self.0.as_ptr()) };
214 self.status()
215 }
216
217 #[doc(alias = "get_group_target")]
218 #[doc(alias = "cairo_get_group_target")]
219 pub fn group_target(&self) -> Surface {
220 unsafe { Surface::from_raw_none(ffi::cairo_get_group_target(self.0.as_ptr())) }
221 }
222
223 #[doc(alias = "cairo_set_source_rgb")]
224 pub fn set_source_rgb(&self, red: f64, green: f64, blue: f64) {
225 unsafe { ffi::cairo_set_source_rgb(self.0.as_ptr(), red, green, blue) }
226 }
227
228 #[doc(alias = "cairo_set_source_rgba")]
229 pub fn set_source_rgba(&self, red: f64, green: f64, blue: f64, alpha: f64) {
230 unsafe { ffi::cairo_set_source_rgba(self.0.as_ptr(), red, green, blue, alpha) }
231 }
232
233 #[doc(alias = "cairo_set_source")]
234 pub fn set_source(&self, source: impl AsRef<Pattern>) -> Result<(), Error> {
235 let source = source.as_ref();
236 source.status()?;
237 unsafe {
238 ffi::cairo_set_source(self.0.as_ptr(), source.to_raw_none());
239 }
240 self.status()
241 }
242
243 #[doc(alias = "get_source")]
244 #[doc(alias = "cairo_get_source")]
245 pub fn source(&self) -> Pattern {
246 unsafe { Pattern::from_raw_none(ffi::cairo_get_source(self.0.as_ptr())) }
247 }
248
249 #[doc(alias = "cairo_set_source_surface")]
250 pub fn set_source_surface(
251 &self,
252 surface: impl AsRef<Surface>,
253 x: f64,
254 y: f64,
255 ) -> Result<(), Error> {
256 let surface = surface.as_ref();
257 surface.status()?;
258 unsafe {
259 ffi::cairo_set_source_surface(self.0.as_ptr(), surface.to_raw_none(), x, y);
260 }
261 self.status()
262 }
263
264 #[doc(alias = "cairo_set_antialias")]
265 pub fn set_antialias(&self, antialias: Antialias) {
266 unsafe { ffi::cairo_set_antialias(self.0.as_ptr(), antialias.into()) }
267 }
268
269 #[doc(alias = "get_antialias")]
270 #[doc(alias = "cairo_get_antialias")]
271 pub fn antialias(&self) -> Antialias {
272 unsafe { Antialias::from(ffi::cairo_get_antialias(self.0.as_ptr())) }
273 }
274
275 #[doc(alias = "cairo_set_dash")]
276 pub fn set_dash(&self, dashes: &[f64], offset: f64) {
277 unsafe {
278 ffi::cairo_set_dash(
279 self.0.as_ptr(),
280 dashes.as_ptr(),
281 dashes.len() as i32,
282 offset,
283 )
284 }
285 }
286
287 #[doc(alias = "get_dash_count")]
288 #[doc(alias = "cairo_get_dash_count")]
289 pub fn dash_count(&self) -> i32 {
290 unsafe { ffi::cairo_get_dash_count(self.0.as_ptr()) }
291 }
292
293 #[doc(alias = "get_dash")]
294 #[doc(alias = "cairo_get_dash")]
295 pub fn dash(&self) -> (Vec<f64>, f64) {
296 let dash_count = self.dash_count() as usize;
297 let mut dashes: Vec<f64> = Vec::with_capacity(dash_count);
298 let mut offset: f64 = 0.0;
299
300 unsafe {
301 ffi::cairo_get_dash(self.0.as_ptr(), dashes.as_mut_ptr(), &mut offset);
302 dashes.set_len(dash_count);
303 (dashes, offset)
304 }
305 }
306
307 #[doc(alias = "get_dash_dashes")]
308 pub fn dash_dashes(&self) -> Vec<f64> {
309 let (dashes, _) = self.dash();
310 dashes
311 }
312
313 #[doc(alias = "get_dash_offset")]
314 pub fn dash_offset(&self) -> f64 {
315 let (_, offset) = self.dash();
316 offset
317 }
318
319 #[doc(alias = "cairo_set_fill_rule")]
320 pub fn set_fill_rule(&self, fill_rule: FillRule) {
321 unsafe {
322 ffi::cairo_set_fill_rule(self.0.as_ptr(), fill_rule.into());
323 }
324 }
325
326 #[doc(alias = "get_fill_rule")]
327 #[doc(alias = "cairo_get_fill_rule")]
328 pub fn fill_rule(&self) -> FillRule {
329 unsafe { FillRule::from(ffi::cairo_get_fill_rule(self.0.as_ptr())) }
330 }
331
332 #[doc(alias = "cairo_set_line_cap")]
333 pub fn set_line_cap(&self, arg: LineCap) {
334 unsafe { ffi::cairo_set_line_cap(self.0.as_ptr(), arg.into()) }
335 }
336
337 #[doc(alias = "get_line_cap")]
338 #[doc(alias = "cairo_get_line_cap")]
339 pub fn line_cap(&self) -> LineCap {
340 unsafe { LineCap::from(ffi::cairo_get_line_cap(self.0.as_ptr())) }
341 }
342
343 #[doc(alias = "cairo_set_line_join")]
344 pub fn set_line_join(&self, arg: LineJoin) {
345 unsafe { ffi::cairo_set_line_join(self.0.as_ptr(), arg.into()) }
346 }
347
348 #[doc(alias = "get_line_join")]
349 #[doc(alias = "cairo_get_line_join")]
350 pub fn line_join(&self) -> LineJoin {
351 unsafe { LineJoin::from(ffi::cairo_get_line_join(self.0.as_ptr())) }
352 }
353
354 #[doc(alias = "cairo_set_line_width")]
355 pub fn set_line_width(&self, arg: f64) {
356 unsafe { ffi::cairo_set_line_width(self.0.as_ptr(), arg) }
357 }
358
359 #[doc(alias = "get_line_width")]
360 #[doc(alias = "cairo_get_line_width")]
361 pub fn line_width(&self) -> f64 {
362 unsafe { ffi::cairo_get_line_width(self.0.as_ptr()) }
363 }
364
365 #[cfg(feature = "v1_18")]
366 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
367 #[doc(alias = "cairo_set_hairline")]
368 pub fn set_hairline(&self, set_hairline: bool) {
369 unsafe { ffi::cairo_set_hairline(self.0.as_ptr(), set_hairline.into()) }
370 }
371
372 #[cfg(feature = "v1_18")]
373 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
374 #[doc(alias = "get_hairline")]
375 #[doc(alias = "cairo_get_hairline")]
376 pub fn hairline(&self) -> bool {
377 unsafe { ffi::cairo_get_hairline(self.0.as_ptr()) }.as_bool()
378 }
379
380 #[doc(alias = "cairo_set_miter_limit")]
381 pub fn set_miter_limit(&self, arg: f64) {
382 unsafe { ffi::cairo_set_miter_limit(self.0.as_ptr(), arg) }
383 }
384
385 #[doc(alias = "get_miter_limit")]
386 #[doc(alias = "cairo_get_miter_limit")]
387 pub fn miter_limit(&self) -> f64 {
388 unsafe { ffi::cairo_get_miter_limit(self.0.as_ptr()) }
389 }
390
391 #[doc(alias = "cairo_set_operator")]
392 pub fn set_operator(&self, op: Operator) {
393 unsafe {
394 ffi::cairo_set_operator(self.0.as_ptr(), op.into());
395 }
396 }
397
398 #[doc(alias = "get_operator")]
399 #[doc(alias = "cairo_get_operator")]
400 pub fn operator(&self) -> Operator {
401 unsafe { Operator::from(ffi::cairo_get_operator(self.0.as_ptr())) }
402 }
403
404 #[doc(alias = "cairo_set_tolerance")]
405 pub fn set_tolerance(&self, arg: f64) {
406 unsafe { ffi::cairo_set_tolerance(self.0.as_ptr(), arg) }
407 }
408
409 #[doc(alias = "get_tolerance")]
410 #[doc(alias = "cairo_get_tolerance")]
411 pub fn tolerance(&self) -> f64 {
412 unsafe { ffi::cairo_get_tolerance(self.0.as_ptr()) }
413 }
414
415 #[doc(alias = "cairo_clip")]
416 pub fn clip(&self) {
417 unsafe { ffi::cairo_clip(self.0.as_ptr()) }
418 }
419
420 #[doc(alias = "cairo_clip_preserve")]
421 pub fn clip_preserve(&self) {
422 unsafe { ffi::cairo_clip_preserve(self.0.as_ptr()) }
423 }
424
425 #[doc(alias = "cairo_clip_extents")]
426 pub fn clip_extents(&self) -> Result<(f64, f64, f64, f64), Error> {
427 let mut x1: f64 = 0.0;
428 let mut y1: f64 = 0.0;
429 let mut x2: f64 = 0.0;
430 let mut y2: f64 = 0.0;
431
432 unsafe {
433 ffi::cairo_clip_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2);
434 }
435 self.status().map(|_| (x1, y1, x2, y2))
436 }
437
438 #[doc(alias = "cairo_in_clip")]
439 pub fn in_clip(&self, x: f64, y: f64) -> Result<bool, Error> {
440 let in_clip = unsafe { ffi::cairo_in_clip(self.0.as_ptr(), x, y).as_bool() };
441 self.status().map(|_| in_clip)
442 }
443
444 #[doc(alias = "cairo_reset_clip")]
445 pub fn reset_clip(&self) {
446 unsafe { ffi::cairo_reset_clip(self.0.as_ptr()) }
447 }
448
449 #[doc(alias = "cairo_copy_clip_rectangle_list")]
450 pub fn copy_clip_rectangle_list(&self) -> Result<RectangleList, Error> {
451 unsafe {
452 let rectangle_list = ffi::cairo_copy_clip_rectangle_list(self.0.as_ptr());
453
454 status_to_result((*rectangle_list).status)?;
455
456 Ok(RectangleList {
457 ptr: rectangle_list,
458 })
459 }
460 }
461
462 #[doc(alias = "cairo_fill")]
463 pub fn fill(&self) -> Result<(), Error> {
464 unsafe { ffi::cairo_fill(self.0.as_ptr()) };
465 self.status()
466 }
467
468 #[doc(alias = "cairo_fill_preserve")]
469 pub fn fill_preserve(&self) -> Result<(), Error> {
470 unsafe { ffi::cairo_fill_preserve(self.0.as_ptr()) };
471 self.status()
472 }
473
474 #[doc(alias = "cairo_fill_extents")]
475 pub fn fill_extents(&self) -> Result<(f64, f64, f64, f64), Error> {
476 let mut x1: f64 = 0.0;
477 let mut y1: f64 = 0.0;
478 let mut x2: f64 = 0.0;
479 let mut y2: f64 = 0.0;
480
481 unsafe {
482 ffi::cairo_fill_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2);
483 }
484 self.status().map(|_| (x1, y1, x2, y2))
485 }
486
487 #[doc(alias = "cairo_in_fill")]
488 pub fn in_fill(&self, x: f64, y: f64) -> Result<bool, Error> {
489 let in_fill = unsafe { ffi::cairo_in_fill(self.0.as_ptr(), x, y).as_bool() };
490 self.status().map(|_| in_fill)
491 }
492
493 #[doc(alias = "cairo_mask")]
494 pub fn mask(&self, pattern: impl AsRef<Pattern>) -> Result<(), Error> {
495 let pattern = pattern.as_ref();
496 pattern.status()?;
497 unsafe { ffi::cairo_mask(self.0.as_ptr(), pattern.to_raw_none()) };
498 self.status()
499 }
500
501 #[doc(alias = "cairo_mask_surface")]
502 pub fn mask_surface(&self, surface: impl AsRef<Surface>, x: f64, y: f64) -> Result<(), Error> {
503 let surface = surface.as_ref();
504 surface.status()?;
505 unsafe {
506 ffi::cairo_mask_surface(self.0.as_ptr(), surface.to_raw_none(), x, y);
507 };
508 self.status()
509 }
510
511 #[doc(alias = "cairo_paint")]
512 pub fn paint(&self) -> Result<(), Error> {
513 unsafe { ffi::cairo_paint(self.0.as_ptr()) };
514 self.status()
515 }
516
517 #[doc(alias = "cairo_paint_with_alpha")]
518 pub fn paint_with_alpha(&self, alpha: f64) -> Result<(), Error> {
519 unsafe { ffi::cairo_paint_with_alpha(self.0.as_ptr(), alpha) };
520 self.status()
521 }
522
523 #[doc(alias = "cairo_stroke")]
524 pub fn stroke(&self) -> Result<(), Error> {
525 unsafe { ffi::cairo_stroke(self.0.as_ptr()) };
526 self.status()
527 }
528
529 #[doc(alias = "cairo_stroke_preserve")]
530 pub fn stroke_preserve(&self) -> Result<(), Error> {
531 unsafe { ffi::cairo_stroke_preserve(self.0.as_ptr()) };
532 self.status()
533 }
534
535 #[doc(alias = "cairo_stroke_extents")]
536 pub fn stroke_extents(&self) -> Result<(f64, f64, f64, f64), Error> {
537 let mut x1: f64 = 0.0;
538 let mut y1: f64 = 0.0;
539 let mut x2: f64 = 0.0;
540 let mut y2: f64 = 0.0;
541
542 unsafe {
543 ffi::cairo_stroke_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2);
544 }
545 self.status().map(|_| (x1, y1, x2, y2))
546 }
547
548 #[doc(alias = "cairo_in_stroke")]
549 pub fn in_stroke(&self, x: f64, y: f64) -> Result<bool, Error> {
550 let in_stroke = unsafe { ffi::cairo_in_stroke(self.0.as_ptr(), x, y).as_bool() };
551 self.status().map(|_| in_stroke)
552 }
553
554 #[doc(alias = "cairo_copy_page")]
555 pub fn copy_page(&self) -> Result<(), Error> {
556 unsafe { ffi::cairo_copy_page(self.0.as_ptr()) };
557 self.status()
558 }
559
560 #[doc(alias = "cairo_show_page")]
561 pub fn show_page(&self) -> Result<(), Error> {
562 unsafe { ffi::cairo_show_page(self.0.as_ptr()) };
563 self.status()
564 }
565
566 #[doc(alias = "get_reference_count")]
567 pub fn reference_count(&self) -> u32 {
568 unsafe { ffi::cairo_get_reference_count(self.0.as_ptr()) }
569 }
570
571 #[doc(alias = "cairo_translate")]
574 pub fn translate(&self, tx: f64, ty: f64) {
575 unsafe { ffi::cairo_translate(self.0.as_ptr(), tx, ty) }
576 }
577
578 #[doc(alias = "cairo_scale")]
579 pub fn scale(&self, sx: f64, sy: f64) {
580 unsafe { ffi::cairo_scale(self.0.as_ptr(), sx, sy) }
581 }
582
583 #[doc(alias = "cairo_rotate")]
584 pub fn rotate(&self, angle: f64) {
585 unsafe { ffi::cairo_rotate(self.0.as_ptr(), angle) }
586 }
587
588 #[doc(alias = "cairo_transform")]
589 pub fn transform(&self, matrix: Matrix) {
590 unsafe {
591 ffi::cairo_transform(self.0.as_ptr(), matrix.ptr());
592 }
593 }
594
595 #[doc(alias = "cairo_set_matrix")]
596 pub fn set_matrix(&self, matrix: Matrix) {
597 unsafe {
598 ffi::cairo_set_matrix(self.0.as_ptr(), matrix.ptr());
599 }
600 }
601
602 #[doc(alias = "get_matrix")]
603 #[doc(alias = "cairo_get_matrix")]
604 pub fn matrix(&self) -> Matrix {
605 let mut matrix = Matrix::null();
606 unsafe {
607 ffi::cairo_get_matrix(self.0.as_ptr(), matrix.mut_ptr());
608 }
609 matrix
610 }
611
612 #[doc(alias = "cairo_identity_matrix")]
613 pub fn identity_matrix(&self) {
614 unsafe { ffi::cairo_identity_matrix(self.0.as_ptr()) }
615 }
616
617 #[doc(alias = "cairo_user_to_device")]
618 pub fn user_to_device(&self, mut x: f64, mut y: f64) -> (f64, f64) {
619 unsafe {
620 ffi::cairo_user_to_device(self.0.as_ptr(), &mut x, &mut y);
621 (x, y)
622 }
623 }
624
625 #[doc(alias = "cairo_user_to_device_distance")]
626 pub fn user_to_device_distance(&self, mut dx: f64, mut dy: f64) -> Result<(f64, f64), Error> {
627 unsafe {
628 ffi::cairo_user_to_device_distance(self.0.as_ptr(), &mut dx, &mut dy);
629 };
630 self.status().map(|_| (dx, dy))
631 }
632
633 #[doc(alias = "cairo_device_to_user")]
634 pub fn device_to_user(&self, mut x: f64, mut y: f64) -> Result<(f64, f64), Error> {
635 unsafe {
636 ffi::cairo_device_to_user(self.0.as_ptr(), &mut x, &mut y);
637 }
638 self.status().map(|_| (x, y))
639 }
640
641 #[doc(alias = "cairo_device_to_user_distance")]
642 pub fn device_to_user_distance(&self, mut dx: f64, mut dy: f64) -> Result<(f64, f64), Error> {
643 unsafe {
644 ffi::cairo_device_to_user_distance(self.0.as_ptr(), &mut dx, &mut dy);
645 }
646 self.status().map(|_| (dx, dy))
647 }
648
649 #[doc(alias = "cairo_select_font_face")]
652 pub fn select_font_face(&self, family: &str, slant: FontSlant, weight: FontWeight) {
653 unsafe {
654 let family = CString::new(family).unwrap();
655 ffi::cairo_select_font_face(
656 self.0.as_ptr(),
657 family.as_ptr(),
658 slant.into(),
659 weight.into(),
660 )
661 }
662 }
663
664 #[doc(alias = "cairo_set_font_size")]
665 pub fn set_font_size(&self, size: f64) {
666 unsafe { ffi::cairo_set_font_size(self.0.as_ptr(), size) }
667 }
668
669 #[doc(alias = "cairo_set_font_matrix")]
671 pub fn set_font_matrix(&self, matrix: Matrix) {
672 unsafe { ffi::cairo_set_font_matrix(self.0.as_ptr(), matrix.ptr()) }
673 }
674
675 #[doc(alias = "get_font_matrix")]
676 #[doc(alias = "cairo_get_font_matrix")]
677 pub fn font_matrix(&self) -> Matrix {
678 let mut matrix = Matrix::null();
679 unsafe {
680 ffi::cairo_get_font_matrix(self.0.as_ptr(), matrix.mut_ptr());
681 }
682 matrix
683 }
684
685 #[doc(alias = "cairo_set_font_options")]
686 pub fn set_font_options(&self, options: &FontOptions) {
687 unsafe { ffi::cairo_set_font_options(self.0.as_ptr(), options.to_raw_none()) }
688 }
689
690 #[doc(alias = "get_font_options")]
691 #[doc(alias = "cairo_get_font_options")]
692 pub fn font_options(&self) -> Result<FontOptions, Error> {
693 let out = FontOptions::new()?;
694 unsafe {
695 ffi::cairo_get_font_options(self.0.as_ptr(), out.to_raw_none());
696 }
697 Ok(out)
698 }
699
700 #[doc(alias = "cairo_set_font_face")]
701 pub fn set_font_face(&self, font_face: &FontFace) {
702 unsafe { ffi::cairo_set_font_face(self.0.as_ptr(), font_face.to_raw_none()) }
703 }
704
705 #[doc(alias = "get_font_face")]
706 #[doc(alias = "cairo_get_font_face")]
707 pub fn font_face(&self) -> FontFace {
708 unsafe { FontFace::from_raw_none(ffi::cairo_get_font_face(self.0.as_ptr())) }
709 }
710
711 #[doc(alias = "cairo_set_scaled_font")]
712 pub fn set_scaled_font(&self, scaled_font: &ScaledFont) {
713 unsafe { ffi::cairo_set_scaled_font(self.0.as_ptr(), scaled_font.to_raw_none()) }
714 }
715
716 #[doc(alias = "get_scaled_font")]
717 #[doc(alias = "cairo_get_scaled_font")]
718 pub fn scaled_font(&self) -> ScaledFont {
719 unsafe { ScaledFont::from_raw_none(ffi::cairo_get_scaled_font(self.0.as_ptr())) }
720 }
721
722 #[doc(alias = "cairo_show_text")]
723 pub fn show_text(&self, text: &str) -> Result<(), Error> {
724 unsafe {
725 let text = CString::new(text).unwrap();
726 ffi::cairo_show_text(self.0.as_ptr(), text.as_ptr())
727 };
728 self.status()
729 }
730
731 #[doc(alias = "cairo_show_glyphs")]
732 pub fn show_glyphs(&self, glyphs: &[Glyph]) -> Result<(), Error> {
733 unsafe {
734 ffi::cairo_show_glyphs(
735 self.0.as_ptr(),
736 glyphs.as_ptr() as *const _,
737 glyphs.len() as _,
738 )
739 };
740 self.status()
741 }
742
743 #[doc(alias = "cairo_show_text_glyphs")]
744 pub fn show_text_glyphs(
745 &self,
746 text: &str,
747 glyphs: &[Glyph],
748 clusters: &[TextCluster],
749 cluster_flags: TextClusterFlags,
750 ) -> Result<(), Error> {
751 unsafe {
752 let text = CString::new(text).unwrap();
753 ffi::cairo_show_text_glyphs(
754 self.0.as_ptr(),
755 text.as_ptr(),
756 -1_i32, glyphs.as_ptr() as *const _,
758 glyphs.len() as _,
759 clusters.as_ptr() as *const _,
760 clusters.len() as _,
761 cluster_flags.into(),
762 )
763 };
764 self.status()
765 }
766
767 #[doc(alias = "cairo_font_extents")]
768 pub fn font_extents(&self) -> Result<FontExtents, Error> {
769 let mut extents = MaybeUninit::<FontExtents>::uninit();
770
771 unsafe {
772 ffi::cairo_font_extents(self.0.as_ptr(), extents.as_mut_ptr() as *mut _);
773 self.status().map(|_| extents.assume_init() as _)
774 }
775 }
776
777 #[doc(alias = "cairo_text_extents")]
778 pub fn text_extents(&self, text: &str) -> Result<TextExtents, Error> {
779 let mut extents = MaybeUninit::<TextExtents>::uninit();
780
781 unsafe {
782 let text = CString::new(text).unwrap();
783 ffi::cairo_text_extents(
784 self.0.as_ptr(),
785 text.as_ptr(),
786 extents.as_mut_ptr() as *mut _,
787 );
788 self.status().map(|_| extents.assume_init())
789 }
790 }
791
792 #[doc(alias = "cairo_glyph_extents")]
793 pub fn glyph_extents(&self, glyphs: &[Glyph]) -> Result<TextExtents, Error> {
794 let mut extents = MaybeUninit::<TextExtents>::uninit();
795
796 unsafe {
797 ffi::cairo_glyph_extents(
798 self.0.as_ptr(),
799 glyphs.as_ptr() as *const _,
800 glyphs.len() as _,
801 extents.as_mut_ptr() as *mut _,
802 );
803 self.status().map(|_| extents.assume_init())
804 }
805 }
806
807 #[doc(alias = "cairo_copy_path")]
810 pub fn copy_path(&self) -> Result<Path, Error> {
811 let path = unsafe { Path::from_raw_full(ffi::cairo_copy_path(self.0.as_ptr())) };
812 self.status().map(|_| path)
813 }
814
815 #[doc(alias = "cairo_copy_path_flat")]
816 pub fn copy_path_flat(&self) -> Result<Path, Error> {
817 let path = unsafe { Path::from_raw_full(ffi::cairo_copy_path_flat(self.0.as_ptr())) };
818 self.status().map(|_| path)
819 }
820
821 #[doc(alias = "cairo_append_path")]
822 pub fn append_path(&self, path: &Path) {
823 unsafe { ffi::cairo_append_path(self.0.as_ptr(), path.as_ptr()) }
824 }
825
826 #[doc(alias = "cairo_has_current_point")]
827 pub fn has_current_point(&self) -> Result<bool, Error> {
828 let has_current_point = unsafe { ffi::cairo_has_current_point(self.0.as_ptr()).as_bool() };
829 self.status().map(|_| has_current_point)
830 }
831
832 #[doc(alias = "get_current_point")]
833 #[doc(alias = "cairo_get_current_point")]
834 pub fn current_point(&self) -> Result<(f64, f64), Error> {
835 unsafe {
836 let mut x = 0.0;
837 let mut y = 0.0;
838 ffi::cairo_get_current_point(self.0.as_ptr(), &mut x, &mut y);
839 self.status().map(|_| (x, y))
840 }
841 }
842
843 #[doc(alias = "cairo_new_path")]
844 pub fn new_path(&self) {
845 unsafe { ffi::cairo_new_path(self.0.as_ptr()) }
846 }
847
848 #[doc(alias = "cairo_new_sub_path")]
849 pub fn new_sub_path(&self) {
850 unsafe { ffi::cairo_new_sub_path(self.0.as_ptr()) }
851 }
852
853 #[doc(alias = "cairo_close_path")]
854 pub fn close_path(&self) {
855 unsafe { ffi::cairo_close_path(self.0.as_ptr()) }
856 }
857
858 #[doc(alias = "cairo_arc")]
859 pub fn arc(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) {
860 unsafe { ffi::cairo_arc(self.0.as_ptr(), xc, yc, radius, angle1, angle2) }
861 }
862
863 #[doc(alias = "cairo_arc_negative")]
864 pub fn arc_negative(&self, xc: f64, yc: f64, radius: f64, angle1: f64, angle2: f64) {
865 unsafe { ffi::cairo_arc_negative(self.0.as_ptr(), xc, yc, radius, angle1, angle2) }
866 }
867
868 #[doc(alias = "cairo_curve_to")]
869 pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
870 unsafe { ffi::cairo_curve_to(self.0.as_ptr(), x1, y1, x2, y2, x3, y3) }
871 }
872
873 #[doc(alias = "cairo_line_to")]
874 pub fn line_to(&self, x: f64, y: f64) {
875 unsafe { ffi::cairo_line_to(self.0.as_ptr(), x, y) }
876 }
877
878 #[doc(alias = "cairo_move_to")]
879 pub fn move_to(&self, x: f64, y: f64) {
880 unsafe { ffi::cairo_move_to(self.0.as_ptr(), x, y) }
881 }
882
883 #[doc(alias = "cairo_rectangle")]
884 pub fn rectangle(&self, x: f64, y: f64, width: f64, height: f64) {
885 unsafe { ffi::cairo_rectangle(self.0.as_ptr(), x, y, width, height) }
886 }
887
888 #[doc(alias = "cairo_text_path")]
889 pub fn text_path(&self, str_: &str) {
890 unsafe {
891 let str_ = CString::new(str_).unwrap();
892 ffi::cairo_text_path(self.0.as_ptr(), str_.as_ptr())
893 }
894 }
895
896 #[doc(alias = "cairo_glyph_path")]
897 pub fn glyph_path(&self, glyphs: &[Glyph]) {
898 unsafe {
899 ffi::cairo_glyph_path(
900 self.0.as_ptr(),
901 glyphs.as_ptr() as *const _,
902 glyphs.len() as _,
903 )
904 }
905 }
906
907 #[doc(alias = "cairo_rel_curve_to")]
908 pub fn rel_curve_to(&self, dx1: f64, dy1: f64, dx2: f64, dy2: f64, dx3: f64, dy3: f64) {
909 unsafe { ffi::cairo_rel_curve_to(self.0.as_ptr(), dx1, dy1, dx2, dy2, dx3, dy3) }
910 }
911
912 #[doc(alias = "cairo_rel_line_to")]
913 pub fn rel_line_to(&self, dx: f64, dy: f64) {
914 unsafe { ffi::cairo_rel_line_to(self.0.as_ptr(), dx, dy) }
915 }
916
917 #[doc(alias = "cairo_rel_move_to")]
918 pub fn rel_move_to(&self, dx: f64, dy: f64) {
919 unsafe { ffi::cairo_rel_move_to(self.0.as_ptr(), dx, dy) }
920 }
921
922 #[doc(alias = "cairo_path_extents")]
923 pub fn path_extents(&self) -> Result<(f64, f64, f64, f64), Error> {
924 let mut x1: f64 = 0.0;
925 let mut y1: f64 = 0.0;
926 let mut x2: f64 = 0.0;
927 let mut y2: f64 = 0.0;
928
929 unsafe {
930 ffi::cairo_path_extents(self.0.as_ptr(), &mut x1, &mut y1, &mut x2, &mut y2);
931 }
932 self.status().map(|_| (x1, y1, x2, y2))
933 }
934
935 #[cfg(feature = "v1_16")]
936 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
937 #[doc(alias = "cairo_tag_begin")]
938 pub fn tag_begin(&self, tag_name: &str, attributes: &str) {
939 unsafe {
940 let tag_name = CString::new(tag_name).unwrap();
941 let attributes = CString::new(attributes).unwrap();
942 ffi::cairo_tag_begin(self.0.as_ptr(), tag_name.as_ptr(), attributes.as_ptr())
943 }
944 }
945
946 #[cfg(feature = "v1_16")]
947 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
948 #[doc(alias = "cairo_tag_end")]
949 pub fn tag_end(&self, tag_name: &str) {
950 unsafe {
951 let tag_name = CString::new(tag_name).unwrap();
952 ffi::cairo_tag_end(self.0.as_ptr(), tag_name.as_ptr())
953 }
954 }
955}
956
957#[cfg(test)]
958mod tests {
959 use float_eq::float_eq;
960
961 use super::*;
962 use crate::{enums::Format, image_surface::ImageSurface, patterns::LinearGradient};
963
964 fn create_ctx() -> Context {
965 let surface = ImageSurface::create(Format::ARgb32, 10, 10).unwrap();
966 Context::new(&surface).expect("Can't create a Cairo context")
967 }
968
969 #[test]
970 fn invalid_surface_cant_create_context() {
971 unsafe {
972 let image_surf =
974 ffi::cairo_image_surface_create(Format::ARgb32.into(), 100_000, 100_000);
975
976 let wrapped = Surface::from_raw_none(image_surf);
979
980 assert!(Context::new(&wrapped).is_err());
981
982 ffi::cairo_surface_destroy(image_surf);
983 }
984 }
985
986 #[test]
987 fn drop_non_reference_pattern_from_ctx() {
988 let ctx = create_ctx();
989 ctx.source();
990 }
991
992 #[test]
993 fn drop_non_reference_pattern() {
994 let ctx = create_ctx();
995 let pattern = LinearGradient::new(1.0f64, 2.0f64, 3.0f64, 4.0f64);
996 ctx.set_source(&pattern).expect("Invalid surface state");
997 }
998
999 #[test]
1000 fn clip_rectangle() {
1001 let ctx = create_ctx();
1002 let rect = ctx
1003 .copy_clip_rectangle_list()
1004 .expect("Failed to copy rectangle list");
1005 let first_rect = rect[0];
1006 assert!(float_eq!(first_rect.x(), 0.0, abs <= 0.000_1));
1007 assert!(float_eq!(first_rect.y(), 0.0, abs <= 0.000_1));
1008 assert!(float_eq!(first_rect.width(), 10.0, abs <= 0.000_1));
1009 assert!(float_eq!(first_rect.height(), 10.0, abs <= 0.000_1));
1010 }
1011}