diff --git a/src/lib.rs b/src/lib.rs index 0c0d9f7..01854e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,4 +32,5 @@ pub mod geometry; #[cfg(target_os = "macos")] pub mod private; pub mod image; +pub mod path; mod sys; diff --git a/src/path.rs b/src/path.rs new file mode 100644 index 0000000..4e60c59 --- /dev/null +++ b/src/path.rs @@ -0,0 +1,115 @@ +// Copyright 2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use foreign_types::ForeignType; +use geometry::CGPoint; +use libc::c_void; +use std::fmt::{self, Debug, Formatter}; +use std::marker::PhantomData; +use std::ops::Deref; +use std::slice; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGPath; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGPath; + pub struct CGPathRef; +} + +impl CGPath { + pub fn type_id() -> CFTypeID { + unsafe { + CGPathGetTypeID() + } + } + + pub fn apply<'a, F>(&'a self, mut closure: &'a F) where F: FnMut(CGPathElementRef<'a>) { + unsafe { + CGPathApply(self.as_ptr(), &mut closure as *mut _ as *mut c_void, do_apply::); + } + + unsafe extern "C" fn do_apply<'a, F>(info: *mut c_void, element: *const CGPathElement) + where F: FnMut(CGPathElementRef<'a>) { + let closure = info as *mut *mut F; + (**closure)(CGPathElementRef::new(element)) + } + } +} + +#[repr(i32)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CGPathElementType { + MoveToPoint = 0, + AddLineToPoint = 1, + AddQuadCurveToPoint = 2, + AddCurveToPoint = 3, + CloseSubpath = 4, +} + +pub struct CGPathElementRef<'a> { + element: *const CGPathElement, + phantom: PhantomData<&'a CGPathElement>, +} + +impl<'a> CGPathElementRef<'a> { + fn new<'b>(element: *const CGPathElement) -> CGPathElementRef<'b> { + CGPathElementRef { + element: element, + phantom: PhantomData, + } + } +} + +impl<'a> Deref for CGPathElementRef<'a> { + type Target = CGPathElement; + fn deref(&self) -> &CGPathElement { + unsafe { + &*self.element + } + } +} + +#[repr(C)] +pub struct CGPathElement { + pub element_type: CGPathElementType, + points: *mut CGPoint, +} + +impl Debug for CGPathElement { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{:?}: {:?}", self.element_type, self.points()) + } +} + +impl CGPathElement { + pub fn points(&self) -> &[CGPoint] { + unsafe { + match self.element_type { + CGPathElementType::CloseSubpath => &[], + CGPathElementType::MoveToPoint | CGPathElementType::AddLineToPoint => { + slice::from_raw_parts(self.points, 1) + } + CGPathElementType::AddQuadCurveToPoint => slice::from_raw_parts(self.points, 2), + CGPathElementType::AddCurveToPoint => slice::from_raw_parts(self.points, 3), + } + } + } +} + +type CGPathApplierFunction = unsafe extern "C" fn(info: *mut c_void, + element: *const CGPathElement); + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGPathApply(path: ::sys::CGPathRef, info: *mut c_void, function: CGPathApplierFunction); + fn CGPathGetTypeID() -> CFTypeID; +} diff --git a/src/sys.rs b/src/sys.rs index 317dd07..1048e04 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -4,6 +4,9 @@ pub type CGImageRef = *mut CGImage; pub enum CGColorSpace {} pub type CGColorSpaceRef = *mut CGColorSpace; +pub enum CGPath {} +pub type CGPathRef = *mut CGPath; + pub enum CGDataProvider {} pub type CGDataProviderRef = *mut CGDataProvider;