pdfium_render/pdf/document/page/
field.rs

1//! Defines the [PdfFormField] enum, exposing functionality related to a single interactive
2//! form field in a [PdfForm].
3
4pub mod button;
5pub mod checkbox;
6pub mod combo;
7pub mod list;
8pub mod option;
9pub mod options;
10pub(crate) mod private; // Keep private so that the PdfFormFieldPrivate trait is not exposed.
11pub mod radio;
12pub mod signature;
13pub mod text;
14pub mod unknown;
15
16use crate::bindgen::{
17    FPDF_ANNOTATION, FPDF_FORMFIELD_CHECKBOX, FPDF_FORMFIELD_COMBOBOX, FPDF_FORMFIELD_LISTBOX,
18    FPDF_FORMFIELD_PUSHBUTTON, FPDF_FORMFIELD_RADIOBUTTON, FPDF_FORMFIELD_SIGNATURE,
19    FPDF_FORMFIELD_TEXTFIELD, FPDF_FORMFIELD_UNKNOWN, FPDF_FORMHANDLE,
20};
21use crate::bindings::PdfiumLibraryBindings;
22use crate::error::PdfiumError;
23use crate::pdf::appearance_mode::PdfAppearanceMode;
24use crate::pdf::document::page::field::button::PdfFormPushButtonField;
25use crate::pdf::document::page::field::checkbox::PdfFormCheckboxField;
26use crate::pdf::document::page::field::combo::PdfFormComboBoxField;
27use crate::pdf::document::page::field::list::PdfFormListBoxField;
28use crate::pdf::document::page::field::private::internal::PdfFormFieldPrivate;
29use crate::pdf::document::page::field::radio::PdfFormRadioButtonField;
30use crate::pdf::document::page::field::signature::PdfFormSignatureField;
31use crate::pdf::document::page::field::text::PdfFormTextField;
32use crate::pdf::document::page::field::unknown::PdfFormUnknownField;
33use std::os::raw::c_int;
34
35#[cfg(doc)]
36use crate::pdf::document::form::PdfForm;
37
38/// The widget display type of a single interactive form field in a [PdfForm].
39#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
40pub enum PdfFormFieldType {
41    // The FPDF_FORMFIELD_COUNT constant simply specifies the number of form field
42    // widget types supported by Pdfium; we do not need to expose it.
43    Unknown = FPDF_FORMFIELD_UNKNOWN as isize,
44    PushButton = FPDF_FORMFIELD_PUSHBUTTON as isize,
45    Checkbox = FPDF_FORMFIELD_CHECKBOX as isize,
46    RadioButton = FPDF_FORMFIELD_RADIOBUTTON as isize,
47    ComboBox = FPDF_FORMFIELD_COMBOBOX as isize,
48    ListBox = FPDF_FORMFIELD_LISTBOX as isize,
49    Text = FPDF_FORMFIELD_TEXTFIELD as isize,
50    Signature = FPDF_FORMFIELD_SIGNATURE as isize,
51}
52
53impl PdfFormFieldType {
54    #[inline]
55    #[allow(dead_code)]
56    pub(crate) fn from_pdfium(value: c_int) -> Result<PdfFormFieldType, PdfiumError> {
57        match value as u32 {
58            FPDF_FORMFIELD_UNKNOWN => Ok(PdfFormFieldType::Unknown),
59            FPDF_FORMFIELD_PUSHBUTTON => Ok(PdfFormFieldType::PushButton),
60            FPDF_FORMFIELD_CHECKBOX => Ok(PdfFormFieldType::Checkbox),
61            FPDF_FORMFIELD_RADIOBUTTON => Ok(PdfFormFieldType::RadioButton),
62            FPDF_FORMFIELD_COMBOBOX => Ok(PdfFormFieldType::ComboBox),
63            FPDF_FORMFIELD_LISTBOX => Ok(PdfFormFieldType::ListBox),
64            FPDF_FORMFIELD_TEXTFIELD => Ok(PdfFormFieldType::Text),
65            FPDF_FORMFIELD_SIGNATURE => Ok(PdfFormFieldType::Signature),
66            _ => Err(PdfiumError::UnknownFormFieldType),
67        }
68    }
69
70    #[inline]
71    #[allow(dead_code)]
72    // The as_pdfium() function is not currently used, but we expect it to be in future
73    pub(crate) fn as_pdfium(&self) -> u32 {
74        match self {
75            PdfFormFieldType::Unknown => FPDF_FORMFIELD_UNKNOWN,
76            PdfFormFieldType::PushButton => FPDF_FORMFIELD_PUSHBUTTON,
77            PdfFormFieldType::Checkbox => FPDF_FORMFIELD_CHECKBOX,
78            PdfFormFieldType::RadioButton => FPDF_FORMFIELD_RADIOBUTTON,
79            PdfFormFieldType::ComboBox => FPDF_FORMFIELD_COMBOBOX,
80            PdfFormFieldType::ListBox => FPDF_FORMFIELD_LISTBOX,
81            PdfFormFieldType::Text => FPDF_FORMFIELD_TEXTFIELD,
82            PdfFormFieldType::Signature => FPDF_FORMFIELD_SIGNATURE,
83        }
84    }
85}
86
87/// A single interactive form field in a [PdfForm].
88pub enum PdfFormField<'a> {
89    PushButton(PdfFormPushButtonField<'a>),
90    Checkbox(PdfFormCheckboxField<'a>),
91    RadioButton(PdfFormRadioButtonField<'a>),
92    ComboBox(PdfFormComboBoxField<'a>),
93    ListBox(PdfFormListBoxField<'a>),
94    Signature(PdfFormSignatureField<'a>),
95    Text(PdfFormTextField<'a>),
96    Unknown(PdfFormUnknownField<'a>),
97}
98
99impl<'a> PdfFormField<'a> {
100    pub(crate) fn from_pdfium(
101        form_handle: FPDF_FORMHANDLE,
102        annotation_handle: FPDF_ANNOTATION,
103        bindings: &'a dyn PdfiumLibraryBindings,
104    ) -> Option<Self> {
105        let result = bindings.FPDFAnnot_GetFormFieldType(form_handle, annotation_handle);
106
107        if result == -1 {
108            return None;
109        }
110
111        let form_field_type =
112            PdfFormFieldType::from_pdfium(result).unwrap_or(PdfFormFieldType::Unknown);
113
114        Some(match form_field_type {
115            PdfFormFieldType::PushButton => PdfFormField::PushButton(
116                PdfFormPushButtonField::from_pdfium(form_handle, annotation_handle, bindings),
117            ),
118            PdfFormFieldType::Checkbox => PdfFormField::Checkbox(
119                PdfFormCheckboxField::from_pdfium(form_handle, annotation_handle, bindings),
120            ),
121            PdfFormFieldType::RadioButton => PdfFormField::RadioButton(
122                PdfFormRadioButtonField::from_pdfium(form_handle, annotation_handle, bindings),
123            ),
124            PdfFormFieldType::ComboBox => PdfFormField::ComboBox(
125                PdfFormComboBoxField::from_pdfium(form_handle, annotation_handle, bindings),
126            ),
127            PdfFormFieldType::ListBox => PdfFormField::ListBox(PdfFormListBoxField::from_pdfium(
128                form_handle,
129                annotation_handle,
130                bindings,
131            )),
132            PdfFormFieldType::Text => PdfFormField::Text(PdfFormTextField::from_pdfium(
133                form_handle,
134                annotation_handle,
135                bindings,
136            )),
137            PdfFormFieldType::Signature => PdfFormField::Signature(
138                PdfFormSignatureField::from_pdfium(form_handle, annotation_handle, bindings),
139            ),
140            _ => PdfFormField::Unknown(PdfFormUnknownField::from_pdfium(
141                form_handle,
142                annotation_handle,
143                bindings,
144            )),
145        })
146    }
147
148    #[inline]
149    pub(crate) fn unwrap_as_trait(&self) -> &dyn PdfFormFieldPrivate<'a> {
150        match self {
151            PdfFormField::PushButton(field) => field,
152            PdfFormField::Checkbox(field) => field,
153            PdfFormField::RadioButton(field) => field,
154            PdfFormField::ComboBox(field) => field,
155            PdfFormField::ListBox(field) => field,
156            PdfFormField::Signature(field) => field,
157            PdfFormField::Text(field) => field,
158            PdfFormField::Unknown(field) => field,
159        }
160    }
161
162    /// The type of this [PdfFormField].
163    #[inline]
164    pub fn field_type(&self) -> PdfFormFieldType {
165        match self {
166            PdfFormField::PushButton(_) => PdfFormFieldType::PushButton,
167            PdfFormField::Checkbox(_) => PdfFormFieldType::Checkbox,
168            PdfFormField::RadioButton(_) => PdfFormFieldType::RadioButton,
169            PdfFormField::ComboBox(_) => PdfFormFieldType::ComboBox,
170            PdfFormField::ListBox(_) => PdfFormFieldType::ListBox,
171            PdfFormField::Signature(_) => PdfFormFieldType::Signature,
172            PdfFormField::Text(_) => PdfFormFieldType::Text,
173            PdfFormField::Unknown(_) => PdfFormFieldType::Unknown,
174        }
175    }
176
177    /// Returns a reference to the underlying [PdfFormPushButtonField] for this [PdfFormField],
178    /// if this form field has a field type of [PdfFormField::PushButton].
179    #[inline]
180    pub fn as_push_button_field(&self) -> Option<&PdfFormPushButtonField> {
181        match self {
182            PdfFormField::PushButton(field) => Some(field),
183            _ => None,
184        }
185    }
186
187    /// Returns a reference to the underlying [PdfFormCheckboxField] for this [PdfFormField],
188    /// if this form field has a field type of [PdfFormField::Checkbox].
189    #[inline]
190    pub fn as_checkbox_field(&self) -> Option<&PdfFormCheckboxField> {
191        match self {
192            PdfFormField::Checkbox(field) => Some(field),
193            _ => None,
194        }
195    }
196
197    /// Returns a mutable reference to the underlying [PdfFormCheckboxField]
198    /// for this [PdfFormField], if this form field has a field type of [PdfFormField::Checkbox].
199    #[inline]
200    pub fn as_checkbox_field_mut(&mut self) -> Option<&mut PdfFormCheckboxField<'a>> {
201        match self {
202            PdfFormField::Checkbox(field) => Some(field),
203            _ => None,
204        }
205    }
206
207    /// Returns a reference to the underlying [PdfFormRadioButtonField] for this [PdfFormField],
208    /// if this form field has a field type of [PdfFormField::RadioButton].
209    #[inline]
210    pub fn as_radio_button_field(&self) -> Option<&PdfFormRadioButtonField> {
211        match self {
212            PdfFormField::RadioButton(field) => Some(field),
213            _ => None,
214        }
215    }
216
217    /// Returns a mutable reference to the underlying [PdfFormRadioButtonField]
218    /// for this [PdfFormField], if this form field has a field type of [PdfFormField::RadioButton].
219    #[inline]
220    pub fn as_radio_button_field_mut(&mut self) -> Option<&mut PdfFormRadioButtonField<'a>> {
221        match self {
222            PdfFormField::RadioButton(field) => Some(field),
223            _ => None,
224        }
225    }
226
227    /// Returns a reference to the underlying [PdfFormComboBoxField] for this [PdfFormField],
228    /// if this form field has a field type of [PdfFormField::ComboBox].
229    #[inline]
230    pub fn as_combo_box_field(&self) -> Option<&PdfFormComboBoxField> {
231        match self {
232            PdfFormField::ComboBox(field) => Some(field),
233            _ => None,
234        }
235    }
236
237    /// Returns a reference to the underlying [PdfFormListBoxField] for this [PdfFormField],
238    /// if this form field has a field type of [PdfFormField::ListBox].
239    #[inline]
240    pub fn as_list_box_field(&self) -> Option<&PdfFormListBoxField> {
241        match self {
242            PdfFormField::ListBox(field) => Some(field),
243            _ => None,
244        }
245    }
246
247    /// Returns a reference to the underlying [PdfFormSignatureField] for this [PdfFormField],
248    /// if this form field has a field type of [PdfFormField::Signature].
249    #[inline]
250    pub fn as_signature_field(&self) -> Option<&PdfFormSignatureField> {
251        match self {
252            PdfFormField::Signature(field) => Some(field),
253            _ => None,
254        }
255    }
256
257    /// Returns a reference to the underlying [PdfFormTextField] for this [PdfFormField],
258    /// if this form field has a field type of [PdfFormField::Text].
259    #[inline]
260    pub fn as_text_field(&self) -> Option<&PdfFormTextField> {
261        match self {
262            PdfFormField::Text(field) => Some(field),
263            _ => None,
264        }
265    }
266
267    /// Returns a mutable reference to the underlying [PdfFormTextField] for this
268    /// [PdfFormField], if this form field has a field type of [PdfFormField::Text].
269    pub fn as_text_field_mut(&mut self) -> Option<&mut PdfFormTextField<'a>> {
270        match self {
271            PdfFormField::Text(field) => Some(field),
272            _ => None,
273        }
274    }
275
276    /// Returns a reference to the underlying [PdfFormUnknownField] for this [PdfFormField],
277    /// if this form field has a field type of [PdfFormField::Unknown].
278    #[inline]
279    pub fn as_unknown_field(&self) -> Option<&PdfFormUnknownField> {
280        match self {
281            PdfFormField::Unknown(field) => Some(field),
282            _ => None,
283        }
284    }
285}
286
287/// Functionality common to all [PdfFormField] objects, regardless of their [PdfFormFieldType].
288pub trait PdfFormFieldCommon {
289    /// Returns the name of this [PdfFormField], if any.
290    fn name(&self) -> Option<String>;
291
292    /// Returns the name of the currently set appearance stream for this [PdfFormField], if any.
293    fn appearance_stream(&self) -> Option<String>;
294
295    /// Returns the value currently set for the given appearance mode for this [PdfFormField],
296    /// if any.
297    fn appearance_mode_value(&self, appearance_mode: PdfAppearanceMode) -> Option<String>;
298}
299
300// Blanket implementation for all PdfFormFieldCommon types.
301
302impl<'a, T> PdfFormFieldCommon for T
303where
304    T: PdfFormFieldPrivate<'a>,
305{
306    #[inline]
307    fn name(&self) -> Option<String> {
308        self.name_impl()
309    }
310
311    #[inline]
312    fn appearance_stream(&self) -> Option<String> {
313        self.appearance_stream_impl()
314    }
315
316    #[inline]
317    fn appearance_mode_value(&self, appearance_mode: PdfAppearanceMode) -> Option<String> {
318        self.appearance_mode_value_impl(appearance_mode)
319    }
320}
321
322impl<'a> PdfFormFieldPrivate<'a> for PdfFormField<'a> {
323    #[inline]
324    fn form_handle(&self) -> &FPDF_FORMHANDLE {
325        self.unwrap_as_trait().form_handle()
326    }
327
328    #[inline]
329    fn annotation_handle(&self) -> &FPDF_ANNOTATION {
330        self.unwrap_as_trait().annotation_handle()
331    }
332
333    #[inline]
334    fn bindings(&self) -> &dyn PdfiumLibraryBindings {
335        self.unwrap_as_trait().bindings()
336    }
337}
338
339impl<'a> From<PdfFormPushButtonField<'a>> for PdfFormField<'a> {
340    #[inline]
341    fn from(field: PdfFormPushButtonField<'a>) -> Self {
342        Self::PushButton(field)
343    }
344}
345
346impl<'a> From<PdfFormCheckboxField<'a>> for PdfFormField<'a> {
347    #[inline]
348    fn from(field: PdfFormCheckboxField<'a>) -> Self {
349        Self::Checkbox(field)
350    }
351}
352
353impl<'a> From<PdfFormRadioButtonField<'a>> for PdfFormField<'a> {
354    #[inline]
355    fn from(field: PdfFormRadioButtonField<'a>) -> Self {
356        Self::RadioButton(field)
357    }
358}
359
360impl<'a> From<PdfFormComboBoxField<'a>> for PdfFormField<'a> {
361    #[inline]
362    fn from(field: PdfFormComboBoxField<'a>) -> Self {
363        Self::ComboBox(field)
364    }
365}
366
367impl<'a> From<PdfFormListBoxField<'a>> for PdfFormField<'a> {
368    #[inline]
369    fn from(field: PdfFormListBoxField<'a>) -> Self {
370        Self::ListBox(field)
371    }
372}
373
374impl<'a> From<PdfFormTextField<'a>> for PdfFormField<'a> {
375    #[inline]
376    fn from(field: PdfFormTextField<'a>) -> Self {
377        Self::Text(field)
378    }
379}
380
381impl<'a> From<PdfFormSignatureField<'a>> for PdfFormField<'a> {
382    #[inline]
383    fn from(field: PdfFormSignatureField<'a>) -> Self {
384        Self::Signature(field)
385    }
386}
387
388impl<'a> From<PdfFormUnknownField<'a>> for PdfFormField<'a> {
389    #[inline]
390    fn from(field: PdfFormUnknownField<'a>) -> Self {
391        Self::Unknown(field)
392    }
393}