Skip to main content

pdfium_render/pdf/
action.rs

1//! Defines the [PdfAction] struct, exposing functionality related to a single action
2//! associated with a clickable link or document bookmark.
3
4pub mod embedded_destination;
5pub mod launch;
6pub mod local_destination;
7pub(crate) mod private; // Keep private so that the PdfActionPrivate trait is not exposed.
8pub mod remote_destination;
9pub mod unsupported;
10pub mod uri;
11
12use crate::bindgen::{
13    FPDF_ACTION, FPDF_DOCUMENT, PDFACTION_EMBEDDEDGOTO, PDFACTION_GOTO, PDFACTION_LAUNCH,
14    PDFACTION_REMOTEGOTO, PDFACTION_UNSUPPORTED, PDFACTION_URI,
15};
16use crate::bindings::PdfiumLibraryBindings;
17use crate::error::PdfiumError;
18use crate::pdf::action::embedded_destination::PdfActionEmbeddedDestination;
19use crate::pdf::action::launch::PdfActionLaunch;
20use crate::pdf::action::local_destination::PdfActionLocalDestination;
21use crate::pdf::action::private::internal::PdfActionPrivate;
22use crate::pdf::action::remote_destination::PdfActionRemoteDestination;
23use crate::pdf::action::unsupported::PdfActionUnsupported;
24use crate::pdf::action::uri::PdfActionUri;
25use crate::pdfium::PdfiumLibraryBindingsAccessor;
26
27/// The type of action associated with a clickable link or document bookmark.
28#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
29pub enum PdfActionType {
30    GoToDestinationInSameDocument = PDFACTION_GOTO as isize,
31    GoToDestinationInRemoteDocument = PDFACTION_REMOTEGOTO as isize,
32    GoToDestinationInEmbeddedDocument = PDFACTION_EMBEDDEDGOTO as isize,
33    Launch = PDFACTION_LAUNCH as isize,
34    Uri = PDFACTION_URI as isize,
35    Unsupported = PDFACTION_UNSUPPORTED as isize,
36}
37
38impl PdfActionType {
39    pub(crate) fn from_pdfium(action_type: u32) -> Result<PdfActionType, PdfiumError> {
40        match action_type {
41            PDFACTION_GOTO => Ok(PdfActionType::GoToDestinationInSameDocument),
42            PDFACTION_REMOTEGOTO => Ok(PdfActionType::GoToDestinationInRemoteDocument),
43            PDFACTION_EMBEDDEDGOTO => Ok(PdfActionType::GoToDestinationInEmbeddedDocument),
44            PDFACTION_LAUNCH => Ok(PdfActionType::Launch),
45            PDFACTION_URI => Ok(PdfActionType::Uri),
46            PDFACTION_UNSUPPORTED => Ok(PdfActionType::Unsupported),
47            _ => Err(PdfiumError::UnknownActionType),
48        }
49    }
50}
51
52/// The action associated with a clickable link or document bookmark.
53pub enum PdfAction<'a> {
54    LocalDestination(PdfActionLocalDestination<'a>),
55    RemoteDestination(PdfActionRemoteDestination<'a>),
56    EmbeddedDestination(PdfActionEmbeddedDestination<'a>),
57    Launch(PdfActionLaunch<'a>),
58    Uri(PdfActionUri<'a>),
59    Unsupported(PdfActionUnsupported<'a>),
60}
61
62impl<'a> PdfAction<'a> {
63    pub(crate) fn from_pdfium(
64        handle: FPDF_ACTION,
65        document: FPDF_DOCUMENT,
66        bindings: &'a dyn PdfiumLibraryBindings,
67    ) -> Self {
68        match PdfActionType::from_pdfium(unsafe { bindings.FPDFAction_GetType(handle) } as u32)
69            .unwrap_or(PdfActionType::Unsupported)
70        {
71            PdfActionType::Unsupported => {
72                PdfAction::Unsupported(PdfActionUnsupported::from_pdfium(handle))
73            }
74            PdfActionType::GoToDestinationInSameDocument => PdfAction::LocalDestination(
75                PdfActionLocalDestination::from_pdfium(handle, document),
76            ),
77            PdfActionType::GoToDestinationInRemoteDocument => {
78                PdfAction::RemoteDestination(PdfActionRemoteDestination::from_pdfium(handle))
79            }
80            PdfActionType::GoToDestinationInEmbeddedDocument => {
81                PdfAction::EmbeddedDestination(PdfActionEmbeddedDestination::from_pdfium(handle))
82            }
83            PdfActionType::Launch => PdfAction::Launch(PdfActionLaunch::from_pdfium(handle)),
84            PdfActionType::Uri => PdfAction::Uri(PdfActionUri::from_pdfium(handle, document)),
85        }
86    }
87
88    #[inline]
89    #[allow(dead_code)] // AJRC - 18/2/23 - We expect this function to be used in future.
90    pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfActionPrivate<'a> {
91        match self {
92            PdfAction::LocalDestination(action) => action,
93            PdfAction::RemoteDestination(action) => action,
94            PdfAction::EmbeddedDestination(action) => action,
95            PdfAction::Launch(action) => action,
96            PdfAction::Uri(action) => action,
97            PdfAction::Unsupported(action) => action,
98        }
99    }
100
101    #[inline]
102    #[allow(dead_code)] // AJRC - 18/2/23 - We expect this function to be used in future.
103    pub(crate) fn unwrap_as_trait_mut(&mut self) -> &mut dyn PdfActionPrivate<'a> {
104        match self {
105            PdfAction::LocalDestination(action) => action,
106            PdfAction::RemoteDestination(action) => action,
107            PdfAction::EmbeddedDestination(action) => action,
108            PdfAction::Launch(action) => action,
109            PdfAction::Uri(action) => action,
110            PdfAction::Unsupported(action) => action,
111        }
112    }
113
114    /// Returns the [PdfActionType] for this [PdfAction].
115    ///
116    /// Note that Pdfium does not support or recognize all PDF action types. For instance,
117    /// Pdfium does not currently support or recognize the interactive Javascript action type
118    /// supported by Adobe Acrobat or Foxit's commercial PDF SDK. In these cases,
119    /// Pdfium will return [PdfActionType::Unsupported].
120    #[inline]
121    pub fn action_type(&self) -> PdfActionType {
122        match self {
123            PdfAction::LocalDestination(_) => PdfActionType::GoToDestinationInSameDocument,
124            PdfAction::RemoteDestination(_) => PdfActionType::GoToDestinationInRemoteDocument,
125            PdfAction::EmbeddedDestination(_) => PdfActionType::GoToDestinationInEmbeddedDocument,
126            PdfAction::Launch(_) => PdfActionType::Launch,
127            PdfAction::Uri(_) => PdfActionType::Uri,
128            PdfAction::Unsupported(_) => PdfActionType::Unsupported,
129        }
130    }
131
132    /// Returns `true` if this [PdfAction] has an action type other than [PdfActionType::Unsupported].
133    ///
134    /// The [PdfAction::as_local_destination_action()], [PdfAction::as_remote_destination_action()],
135    /// [PdfAction::as_embedded_destination_action()], [PdfAction::as_launch_action()],
136    /// and [PdfAction::as_uri_action()] functions can be used to access properties and functions
137    /// pertaining to a specific action type.
138    #[inline]
139    pub fn is_supported(&self) -> bool {
140        !self.is_unsupported()
141    }
142
143    /// Returns `true` if this [PdfAction] has an action type of [PdfActionType::Unsupported].
144    ///
145    /// Common properties shared by all [PdfAction] types can still be accessed for
146    /// actions not recognized by Pdfium, but action-specific functionality will be unavailable.
147    #[inline]
148    pub fn is_unsupported(&self) -> bool {
149        self.action_type() == PdfActionType::Unsupported
150    }
151
152    /// Returns an immutable reference to the underlying [PdfActionLocalDestination] for this [PdfAction],
153    /// if this action has an action type of [PdfActionType::GoToDestinationInSameDocument].
154    #[inline]
155    pub fn as_local_destination_action(&self) -> Option<&PdfActionLocalDestination<'_>> {
156        match self {
157            PdfAction::LocalDestination(action) => Some(action),
158            _ => None,
159        }
160    }
161
162    /// Returns a mutable reference to the underlying [PdfActionLocalDestination] for this [PdfAction],
163    /// if this action has an action type of [PdfActionType::GoToDestinationInSameDocument].
164    #[inline]
165    pub fn as_local_destination_action_mut(
166        &mut self,
167    ) -> Option<&mut PdfActionLocalDestination<'a>> {
168        match self {
169            PdfAction::LocalDestination(action) => Some(action),
170            _ => None,
171        }
172    }
173
174    /// Returns an immutable reference to the underlying [PdfActionRemoteDestination] for this [PdfAction],
175    /// if this action has an action type of [PdfActionType::GoToDestinationInRemoteDocument].
176    #[inline]
177    pub fn as_remote_destination_action(&self) -> Option<&PdfActionRemoteDestination<'_>> {
178        match self {
179            PdfAction::RemoteDestination(action) => Some(action),
180            _ => None,
181        }
182    }
183
184    /// Returns a mutable reference to the underlying [PdfActionRemoteDestination] for this [PdfAction],
185    /// if this action has an action type of [PdfActionType::GoToDestinationInRemoteDocument].
186    #[inline]
187    pub fn as_remote_destination_action_mut(
188        &mut self,
189    ) -> Option<&mut PdfActionRemoteDestination<'a>> {
190        match self {
191            PdfAction::RemoteDestination(action) => Some(action),
192            _ => None,
193        }
194    }
195
196    /// Returns an immutable reference to the underlying [PdfActionEmbeddedDestination] for this [PdfAction],
197    /// if this action has an action type of [PdfActionType::GoToDestinationInEmbeddedDocument].
198    #[inline]
199    pub fn as_embedded_destination_action(&self) -> Option<&PdfActionEmbeddedDestination<'_>> {
200        match self {
201            PdfAction::EmbeddedDestination(action) => Some(action),
202            _ => None,
203        }
204    }
205
206    /// Returns a mutable reference to the underlying [PdfActionEmbeddedDestination] for this [PdfAction],
207    /// if this action has an action type of [PdfActionType::GoToDestinationInEmbeddedDocument].
208    #[inline]
209    pub fn as_embedded_destination_action_mut(
210        &mut self,
211    ) -> Option<&mut PdfActionEmbeddedDestination<'a>> {
212        match self {
213            PdfAction::EmbeddedDestination(action) => Some(action),
214            _ => None,
215        }
216    }
217
218    /// Returns an immutable reference to the underlying [PdfActionLaunch] for this [PdfAction],
219    /// if this action has an action type of [PdfActionType::Launch].
220    #[inline]
221    pub fn as_launch_action(&self) -> Option<&PdfActionLaunch<'_>> {
222        match self {
223            PdfAction::Launch(action) => Some(action),
224            _ => None,
225        }
226    }
227
228    /// Returns a mutable reference to the underlying [PdfActionLaunch] for this [PdfAction],
229    /// if this action has an action type of [PdfActionType::Launch].
230    #[inline]
231    pub fn as_launch_action_mut(&mut self) -> Option<&mut PdfActionLaunch<'a>> {
232        match self {
233            PdfAction::Launch(action) => Some(action),
234            _ => None,
235        }
236    }
237
238    /// Returns an immutable reference to the underlying [PdfActionUri] for this [PdfAction],
239    /// if this action has an action type of [PdfActionType::Uri].
240    #[inline]
241    pub fn as_uri_action(&self) -> Option<&PdfActionUri<'_>> {
242        match self {
243            PdfAction::Uri(action) => Some(action),
244            _ => None,
245        }
246    }
247
248    /// Returns a mutable reference to the underlying [PdfActionUri] for this [PdfAction],
249    /// if this action has an action type of [PdfActionType::Uri].
250    #[inline]
251    pub fn as_uri_action_mut(&mut self) -> Option<&mut PdfActionUri<'a>> {
252        match self {
253            PdfAction::Uri(action) => Some(action),
254            _ => None,
255        }
256    }
257}
258
259/// Functionality common to all [PdfAction] objects, regardless of their [PdfActionType].
260pub trait PdfActionCommon<'a> {
261    // TODO: AJRC - 18/2/23 - this trait is reserved for future expansion.
262}
263
264// Blanket implementation for all PdfAction types.
265
266impl<'a, T> PdfActionCommon<'a> for T where T: PdfActionPrivate<'a> {}
267
268impl<'a> PdfActionPrivate<'a> for PdfAction<'a> {
269    #[inline]
270    fn handle(&self) -> &FPDF_ACTION {
271        self.unwrap_as_trait().handle()
272    }
273}
274
275impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfAction<'a> {}
276
277#[cfg(feature = "thread_safe")]
278unsafe impl<'a> Send for PdfAction<'a> {}
279
280#[cfg(feature = "thread_safe")]
281unsafe impl<'a> Sync for PdfAction<'a> {}
282
283impl<'a> From<PdfActionLocalDestination<'a>> for PdfAction<'a> {
284    #[inline]
285    fn from(action: PdfActionLocalDestination<'a>) -> Self {
286        Self::LocalDestination(action)
287    }
288}
289
290impl<'a> From<PdfActionRemoteDestination<'a>> for PdfAction<'a> {
291    #[inline]
292    fn from(action: PdfActionRemoteDestination<'a>) -> Self {
293        Self::RemoteDestination(action)
294    }
295}
296
297impl<'a> From<PdfActionEmbeddedDestination<'a>> for PdfAction<'a> {
298    #[inline]
299    fn from(action: PdfActionEmbeddedDestination<'a>) -> Self {
300        Self::EmbeddedDestination(action)
301    }
302}
303
304impl<'a> From<PdfActionLaunch<'a>> for PdfAction<'a> {
305    #[inline]
306    fn from(action: PdfActionLaunch<'a>) -> Self {
307        Self::Launch(action)
308    }
309}
310
311impl<'a> From<PdfActionUri<'a>> for PdfAction<'a> {
312    #[inline]
313    fn from(action: PdfActionUri<'a>) -> Self {
314        Self::Uri(action)
315    }
316}
317
318impl<'a> From<PdfActionUnsupported<'a>> for PdfAction<'a> {
319    #[inline]
320    fn from(action: PdfActionUnsupported<'a>) -> Self {
321        Self::Unsupported(action)
322    }
323}