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