core_graphics/
data_provider.rs

1// Copyright 2013 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
10use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType};
11use core_foundation::data::{CFData, CFDataRef};
12
13use libc::{off_t, size_t};
14use std::mem;
15use std::os::raw::c_void;
16use std::ptr;
17use std::sync::Arc;
18
19use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
20
21pub type CGDataProviderGetBytesCallback =
22    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, size_t) -> size_t>;
23pub type CGDataProviderReleaseInfoCallback = Option<unsafe extern "C" fn(*mut c_void)>;
24pub type CGDataProviderRewindCallback = Option<unsafe extern "C" fn(*mut c_void)>;
25pub type CGDataProviderSkipBytesCallback = Option<unsafe extern "C" fn(*mut c_void, size_t)>;
26pub type CGDataProviderSkipForwardCallback =
27    Option<unsafe extern "C" fn(*mut c_void, off_t) -> off_t>;
28
29pub type CGDataProviderGetBytePointerCallback =
30    Option<unsafe extern "C" fn(*mut c_void) -> *mut c_void>;
31pub type CGDataProviderGetBytesAtOffsetCallback =
32    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, size_t, size_t)>;
33pub type CGDataProviderReleaseBytePointerCallback =
34    Option<unsafe extern "C" fn(*mut c_void, *const c_void)>;
35pub type CGDataProviderReleaseDataCallback =
36    Option<unsafe extern "C" fn(*mut c_void, *const c_void, size_t)>;
37pub type CGDataProviderGetBytesAtPositionCallback =
38    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, off_t, size_t)>;
39
40foreign_type! {
41    #[doc(hidden)]
42    pub unsafe type CGDataProvider {
43        type CType = crate::sys::CGDataProvider;
44        fn drop = |cs| CFRelease(cs as *mut _);
45        fn clone = |p| CFRetain(p as *const _) as *mut _;
46    }
47}
48
49impl CGDataProvider {
50    pub fn type_id() -> CFTypeID {
51        unsafe { CGDataProviderGetTypeID() }
52    }
53
54    /// Creates a data provider from the given reference-counted buffer.
55    ///
56    /// The `CGDataProvider` object takes ownership of the reference. Once the data provider
57    /// is destroyed, the reference count of the buffer is automatically decremented.
58    pub fn from_buffer<T: AsRef<[u8]> + Sync + Send>(buffer: Arc<T>) -> Self {
59        unsafe {
60            let ptr = (*buffer).as_ref().as_ptr() as *const c_void;
61            let len = (*buffer).as_ref().len() as size_t;
62            let info = Arc::into_raw(buffer) as *mut c_void;
63            let result = CGDataProviderCreateWithData(info, ptr, len, Some(release::<T>));
64            return CGDataProvider::from_ptr(result);
65        }
66
67        unsafe extern "C" fn release<T>(info: *mut c_void, _: *const c_void, _: size_t) {
68            drop(Arc::from_raw(info as *mut T))
69        }
70    }
71
72    /// Creates a data prvider from a given slice. The data provider does not own the slice in this
73    /// case, so it's up to the user to ensure the memory safety here.
74    pub unsafe fn from_slice(buffer: &[u8]) -> Self {
75        let ptr = buffer.as_ptr() as *const c_void;
76        let len = buffer.len() as size_t;
77        let result = CGDataProviderCreateWithData(ptr::null_mut(), ptr, len, None);
78        CGDataProvider::from_ptr(result)
79    }
80
81    /// Creates a data provider from the given raw pointer, length, and destructor function.
82    ///
83    /// This is double-boxed because the Core Text API requires that the userdata be a single
84    /// pointer.
85    pub unsafe fn from_custom_data(custom_data: Box<Box<dyn CustomData>>) -> Self {
86        let (ptr, len) = (custom_data.ptr() as *const c_void, custom_data.len());
87        let userdata = mem::transmute::<Box<Box<dyn CustomData>>, &mut c_void>(custom_data);
88        let data_provider = CGDataProviderCreateWithData(userdata, ptr, len, Some(release));
89        return CGDataProvider::from_ptr(data_provider);
90
91        unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) {
92            drop(mem::transmute::<*mut c_void, Box<Box<dyn CustomData>>>(
93                info,
94            ))
95        }
96    }
97}
98
99impl CGDataProviderRef {
100    /// Creates a copy of the data from the underlying `CFDataProviderRef`.
101    pub fn copy_data(&self) -> CFData {
102        unsafe { CFData::wrap_under_create_rule(CGDataProviderCopyData(self.as_ptr())) }
103    }
104}
105
106/// Encapsulates custom data that can be wrapped.
107pub trait CustomData {
108    /// Returns a pointer to the start of the custom data. This pointer *must not change* during
109    /// the lifespan of this `CustomData`.
110    unsafe fn ptr(&self) -> *const u8;
111    /// Returns the length of this custom data. This value must not change during the lifespan of
112    /// this `CustomData`.
113    unsafe fn len(&self) -> usize;
114}
115
116#[test]
117fn test_data_provider() {
118    let l = vec![5];
119    CGDataProvider::from_buffer(Arc::new(l));
120
121    let l = vec![5];
122    CGDataProvider::from_buffer(Arc::new(l.into_boxed_slice()));
123
124    // Make sure the buffer is actually dropped
125    use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
126    struct VecWrapper {
127        inner: Vec<u8>,
128        dropped: Arc<AtomicBool>,
129    }
130
131    impl Drop for VecWrapper {
132        fn drop(&mut self) {
133            self.dropped.store(true, SeqCst)
134        }
135    }
136
137    impl std::convert::AsRef<[u8]> for VecWrapper {
138        fn as_ref(&self) -> &[u8] {
139            &self.inner
140        }
141    }
142
143    let dropped = Arc::new(AtomicBool::default());
144    let l = Arc::new(VecWrapper {
145        inner: vec![5],
146        dropped: dropped.clone(),
147    });
148    let m = l.clone();
149    let dp = CGDataProvider::from_buffer(l);
150    drop(m);
151    assert!(!dropped.load(SeqCst));
152    drop(dp);
153    assert!(dropped.load(SeqCst))
154}
155
156#[cfg_attr(feature = "link", link(name = "CoreGraphics", kind = "framework"))]
157extern "C" {
158    fn CGDataProviderCopyData(provider: crate::sys::CGDataProviderRef) -> CFDataRef;
159    //fn CGDataProviderCreateDirect
160    //fn CGDataProviderCreateSequential
161    //fn CGDataProviderCreateWithCFData
162    fn CGDataProviderCreateWithData(
163        info: *mut c_void,
164        data: *const c_void,
165        size: size_t,
166        releaseData: CGDataProviderReleaseDataCallback,
167    ) -> crate::sys::CGDataProviderRef;
168    //fn CGDataProviderCreateWithFilename(filename: *c_char) -> CGDataProviderRef;
169    //fn CGDataProviderCreateWithURL
170    fn CGDataProviderGetTypeID() -> CFTypeID;
171    //fn CGDataProviderRelease(provider: CGDataProviderRef);
172    //fn CGDataProviderRetain(provider: CGDataProviderRef) -> CGDataProviderRef;
173}