core_graphics/
path.rs

1// Copyright 2017 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10pub use crate::sys::CGPathRef as SysCGPathRef;
11
12use crate::geometry::{CGAffineTransform, CGPoint, CGRect};
13use core_foundation::base::{CFRelease, CFRetain, CFTypeID};
14use foreign_types::{foreign_type, ForeignType};
15use libc::c_void;
16use std::fmt::{self, Debug, Formatter};
17use std::marker::PhantomData;
18use std::ops::Deref;
19use std::ptr;
20use std::slice;
21
22foreign_type! {
23    #[doc(hidden)]
24    pub unsafe type CGPath {
25        type CType = crate::sys::CGPath;
26        fn drop = |p| CFRelease(p as *mut _);
27        fn clone = |p| CFRetain(p as *const _) as *mut _;
28    }
29}
30
31impl CGPath {
32    pub fn from_rect(rect: CGRect, transform: Option<&CGAffineTransform>) -> CGPath {
33        unsafe {
34            let transform = match transform {
35                None => ptr::null(),
36                Some(transform) => transform as *const CGAffineTransform,
37            };
38            CGPath::from_ptr(CGPathCreateWithRect(rect, transform))
39        }
40    }
41
42    pub fn type_id() -> CFTypeID {
43        unsafe { CGPathGetTypeID() }
44    }
45
46    pub fn apply<'a, F>(&'a self, mut closure: &'a F)
47    where
48        F: FnMut(CGPathElementRef<'a>),
49    {
50        unsafe {
51            CGPathApply(
52                self.as_ptr(),
53                &mut closure as *mut _ as *mut c_void,
54                do_apply::<F>,
55            );
56        }
57
58        unsafe extern "C" fn do_apply<'a, F>(info: *mut c_void, element: *const CGPathElement)
59        where
60            F: FnMut(CGPathElementRef<'a>),
61        {
62            let closure = info as *mut *mut F;
63            (**closure)(CGPathElementRef::new(element))
64        }
65    }
66}
67
68#[repr(i32)]
69#[derive(Clone, Copy, Debug, PartialEq)]
70pub enum CGPathElementType {
71    MoveToPoint = 0,
72    AddLineToPoint = 1,
73    AddQuadCurveToPoint = 2,
74    AddCurveToPoint = 3,
75    CloseSubpath = 4,
76}
77
78pub struct CGPathElementRef<'a> {
79    element: *const CGPathElement,
80    phantom: PhantomData<&'a CGPathElement>,
81}
82
83impl<'a> CGPathElementRef<'a> {
84    fn new<'b>(element: *const CGPathElement) -> CGPathElementRef<'b> {
85        CGPathElementRef {
86            element,
87            phantom: PhantomData,
88        }
89    }
90}
91
92impl<'a> Deref for CGPathElementRef<'a> {
93    type Target = CGPathElement;
94    fn deref(&self) -> &CGPathElement {
95        unsafe { &*self.element }
96    }
97}
98
99#[repr(C)]
100pub struct CGPathElement {
101    pub element_type: CGPathElementType,
102    points: *mut CGPoint,
103}
104
105impl Debug for CGPathElement {
106    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
107        write!(formatter, "{:?}: {:?}", self.element_type, self.points())
108    }
109}
110
111impl CGPathElement {
112    pub fn points(&self) -> &[CGPoint] {
113        unsafe {
114            match self.element_type {
115                CGPathElementType::CloseSubpath => &[],
116                CGPathElementType::MoveToPoint | CGPathElementType::AddLineToPoint => {
117                    slice::from_raw_parts(self.points, 1)
118                }
119                CGPathElementType::AddQuadCurveToPoint => slice::from_raw_parts(self.points, 2),
120                CGPathElementType::AddCurveToPoint => slice::from_raw_parts(self.points, 3),
121            }
122        }
123    }
124}
125
126type CGPathApplierFunction = unsafe extern "C" fn(info: *mut c_void, element: *const CGPathElement);
127
128#[cfg_attr(feature = "link", link(name = "CoreGraphics", kind = "framework"))]
129extern "C" {
130    fn CGPathCreateWithRect(
131        rect: CGRect,
132        transform: *const CGAffineTransform,
133    ) -> crate::sys::CGPathRef;
134    fn CGPathApply(path: crate::sys::CGPathRef, info: *mut c_void, function: CGPathApplierFunction);
135    fn CGPathGetTypeID() -> CFTypeID;
136}