pdfkit/
page_overlay_view_provider.rs1use std::fmt;
2use std::os::raw::c_void;
3use std::panic::{catch_unwind, AssertUnwindSafe};
4use std::ptr;
5
6use crate::error::Result;
7use crate::ffi;
8use crate::handle::ObjectHandle;
9use crate::page::PdfPage;
10use crate::page_overlay_view::PdfPageOverlayView;
11use crate::view::PdfView;
12
13pub trait PdfPageOverlayViewProvider: 'static {
14 fn overlay_view_for_page(
15 &mut self,
16 _view: PdfView,
17 _page: PdfPage,
18 ) -> Option<PdfPageOverlayView> {
19 None
20 }
21
22 fn will_display_overlay_view(
23 &mut self,
24 _view: PdfView,
25 _overlay_view: PdfPageOverlayView,
26 _page: PdfPage,
27 ) {
28 }
29
30 fn will_end_displaying_overlay_view(
31 &mut self,
32 _view: PdfView,
33 _overlay_view: PdfPageOverlayView,
34 _page: PdfPage,
35 ) {
36 }
37}
38
39struct ProviderState {
40 provider: Box<dyn PdfPageOverlayViewProvider>,
41}
42
43pub struct PdfPageOverlayViewProviderHandle {
44 handle: ObjectHandle,
45 _state: Box<ProviderState>,
46}
47
48impl PdfPageOverlayViewProviderHandle {
49 pub fn new(provider: impl PdfPageOverlayViewProvider) -> Result<Self> {
50 let mut state = Box::new(ProviderState {
51 provider: Box::new(provider),
52 });
53 let context = ptr::addr_of_mut!(*state).cast::<c_void>();
54 let mut out_provider = ptr::null_mut();
55 let mut out_error = ptr::null_mut();
56 let status = unsafe {
57 ffi::pdf_page_overlay_view_provider_new(
58 context,
59 Some(pdf_page_overlay_view_provider_overlay_trampoline),
60 Some(pdf_page_overlay_view_provider_will_display_trampoline),
61 Some(pdf_page_overlay_view_provider_will_end_displaying_trampoline),
62 &mut out_provider,
63 &mut out_error,
64 )
65 };
66 crate::util::status_result(status, out_error)?;
67 Ok(Self {
68 handle: crate::util::required_handle(out_provider, "PDFPageOverlayViewProvider")?,
69 _state: state,
70 })
71 }
72
73 pub(crate) fn as_handle_ptr(&self) -> *mut c_void {
74 self.handle.as_ptr()
75 }
76}
77
78impl fmt::Debug for PdfPageOverlayViewProviderHandle {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 f.debug_struct("PdfPageOverlayViewProviderHandle")
81 .finish_non_exhaustive()
82 }
83}
84
85unsafe fn provider_state(context: *mut c_void) -> Option<&'static mut ProviderState> {
89 context.cast::<ProviderState>().as_mut()
90}
91
92unsafe fn retained_view(handle: *mut c_void) -> Option<PdfView> {
97 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfView::from_handle)
99}
100
101unsafe fn retained_page(handle: *mut c_void) -> Option<PdfPage> {
106 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfPage::from_handle)
108}
109
110unsafe fn retained_overlay_view(handle: *mut c_void) -> Option<PdfPageOverlayView> {
115 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfPageOverlayView::from_handle)
117}
118
119unsafe extern "C" fn pdf_page_overlay_view_provider_overlay_trampoline(
126 context: *mut c_void,
127 view_handle: *mut c_void,
128 page_handle: *mut c_void,
129) -> *mut c_void {
130 catch_unwind(AssertUnwindSafe(|| {
131 let Some(state) = (unsafe { provider_state(context) }) else {
133 return ptr::null_mut();
134 };
135 let Some(view) = (unsafe { retained_view(view_handle) }) else {
136 return ptr::null_mut();
137 };
138 let Some(page) = (unsafe { retained_page(page_handle) }) else {
139 return ptr::null_mut();
140 };
141 state
142 .provider
143 .overlay_view_for_page(view, page)
144 .map_or(ptr::null_mut(), PdfPageOverlayView::into_handle_ptr)
145 }))
146 .unwrap_or(ptr::null_mut())
147}
148
149unsafe extern "C" fn pdf_page_overlay_view_provider_will_display_trampoline(
156 context: *mut c_void,
157 view_handle: *mut c_void,
158 overlay_view_handle: *mut c_void,
159 page_handle: *mut c_void,
160) {
161 let _ = catch_unwind(AssertUnwindSafe(|| {
162 let Some(state) = (unsafe { provider_state(context) }) else {
164 return;
165 };
166 let Some(view) = (unsafe { retained_view(view_handle) }) else {
167 return;
168 };
169 let Some(overlay_view) = (unsafe { retained_overlay_view(overlay_view_handle) }) else {
170 return;
171 };
172 let Some(page) = (unsafe { retained_page(page_handle) }) else {
173 return;
174 };
175 state
176 .provider
177 .will_display_overlay_view(view, overlay_view, page);
178 }));
179}
180
181unsafe extern "C" fn pdf_page_overlay_view_provider_will_end_displaying_trampoline(
188 context: *mut c_void,
189 view_handle: *mut c_void,
190 overlay_view_handle: *mut c_void,
191 page_handle: *mut c_void,
192) {
193 let _ = catch_unwind(AssertUnwindSafe(|| {
194 let Some(state) = (unsafe { provider_state(context) }) else {
196 return;
197 };
198 let Some(view) = (unsafe { retained_view(view_handle) }) else {
199 return;
200 };
201 let Some(overlay_view) = (unsafe { retained_overlay_view(overlay_view_handle) }) else {
202 return;
203 };
204 let Some(page) = (unsafe { retained_page(page_handle) }) else {
205 return;
206 };
207 state
208 .provider
209 .will_end_displaying_overlay_view(view, overlay_view, page);
210 }));
211}