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 {
15 fn overlay_view_for_page(
17 &mut self,
18 _view: PdfView,
19 _page: PdfPage,
20 ) -> Option<PdfPageOverlayView> {
21 None
22 }
23
24 fn will_display_overlay_view(
26 &mut self,
27 _view: PdfView,
28 _overlay_view: PdfPageOverlayView,
29 _page: PdfPage,
30 ) {
31 }
32
33 fn will_end_displaying_overlay_view(
35 &mut self,
36 _view: PdfView,
37 _overlay_view: PdfPageOverlayView,
38 _page: PdfPage,
39 ) {
40 }
41}
42
43struct ProviderState {
44 provider: Box<dyn PdfPageOverlayViewProvider>,
45}
46
47pub struct PdfPageOverlayViewProviderHandle {
49 handle: ObjectHandle,
50 _state: Box<ProviderState>,
51}
52
53impl PdfPageOverlayViewProviderHandle {
54 pub fn new(provider: impl PdfPageOverlayViewProvider) -> Result<Self> {
56 let mut state = Box::new(ProviderState {
57 provider: Box::new(provider),
58 });
59 let context = ptr::addr_of_mut!(*state).cast::<c_void>();
60 let mut out_provider = ptr::null_mut();
61 let mut out_error = ptr::null_mut();
62 let status = unsafe {
63 ffi::pdf_page_overlay_view_provider_new(
64 context,
65 Some(pdf_page_overlay_view_provider_overlay_trampoline),
66 Some(pdf_page_overlay_view_provider_will_display_trampoline),
67 Some(pdf_page_overlay_view_provider_will_end_displaying_trampoline),
68 &mut out_provider,
69 &mut out_error,
70 )
71 };
72 crate::util::status_result(status, out_error)?;
73 Ok(Self {
74 handle: crate::util::required_handle(out_provider, "PDFPageOverlayViewProvider")?,
75 _state: state,
76 })
77 }
78
79 pub(crate) fn as_handle_ptr(&self) -> *mut c_void {
80 self.handle.as_ptr()
81 }
82}
83
84impl fmt::Debug for PdfPageOverlayViewProviderHandle {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.debug_struct("PdfPageOverlayViewProviderHandle")
87 .finish_non_exhaustive()
88 }
89}
90
91unsafe fn provider_state(context: *mut c_void) -> Option<&'static mut ProviderState> {
95 context.cast::<ProviderState>().as_mut()
96}
97
98unsafe fn retained_view(handle: *mut c_void) -> Option<PdfView> {
103 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfView::from_handle)
105}
106
107unsafe fn retained_page(handle: *mut c_void) -> Option<PdfPage> {
112 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfPage::from_handle)
114}
115
116unsafe fn retained_overlay_view(handle: *mut c_void) -> Option<PdfPageOverlayView> {
121 unsafe { ObjectHandle::from_retained_ptr(handle) }.map(PdfPageOverlayView::from_handle)
123}
124
125unsafe extern "C" fn pdf_page_overlay_view_provider_overlay_trampoline(
132 context: *mut c_void,
133 view_handle: *mut c_void,
134 page_handle: *mut c_void,
135) -> *mut c_void {
136 catch_unwind(AssertUnwindSafe(|| {
137 let Some(state) = (unsafe { provider_state(context) }) else {
139 return ptr::null_mut();
140 };
141 let Some(view) = (unsafe { retained_view(view_handle) }) else {
142 return ptr::null_mut();
143 };
144 let Some(page) = (unsafe { retained_page(page_handle) }) else {
145 return ptr::null_mut();
146 };
147 state
148 .provider
149 .overlay_view_for_page(view, page)
150 .map_or(ptr::null_mut(), PdfPageOverlayView::into_handle_ptr)
151 }))
152 .unwrap_or(ptr::null_mut())
153}
154
155unsafe extern "C" fn pdf_page_overlay_view_provider_will_display_trampoline(
162 context: *mut c_void,
163 view_handle: *mut c_void,
164 overlay_view_handle: *mut c_void,
165 page_handle: *mut c_void,
166) {
167 let _ = catch_unwind(AssertUnwindSafe(|| {
168 let Some(state) = (unsafe { provider_state(context) }) else {
170 return;
171 };
172 let Some(view) = (unsafe { retained_view(view_handle) }) else {
173 return;
174 };
175 let Some(overlay_view) = (unsafe { retained_overlay_view(overlay_view_handle) }) else {
176 return;
177 };
178 let Some(page) = (unsafe { retained_page(page_handle) }) else {
179 return;
180 };
181 state
182 .provider
183 .will_display_overlay_view(view, overlay_view, page);
184 }));
185}
186
187unsafe extern "C" fn pdf_page_overlay_view_provider_will_end_displaying_trampoline(
194 context: *mut c_void,
195 view_handle: *mut c_void,
196 overlay_view_handle: *mut c_void,
197 page_handle: *mut c_void,
198) {
199 let _ = catch_unwind(AssertUnwindSafe(|| {
200 let Some(state) = (unsafe { provider_state(context) }) else {
202 return;
203 };
204 let Some(view) = (unsafe { retained_view(view_handle) }) else {
205 return;
206 };
207 let Some(overlay_view) = (unsafe { retained_overlay_view(overlay_view_handle) }) else {
208 return;
209 };
210 let Some(page) = (unsafe { retained_page(page_handle) }) else {
211 return;
212 };
213 state
214 .provider
215 .will_end_displaying_overlay_view(view, overlay_view, page);
216 }));
217}