pdfium_render/pdf/document/page/field/
text.rs

1//! Defines the [PdfFormTextField] struct, exposing functionality related to a single
2//! form field of type [PdfFormFieldType::Text].
3
4use crate::bindgen::{FPDF_ANNOTATION, FPDF_FORMHANDLE};
5use crate::bindings::PdfiumLibraryBindings;
6use crate::error::PdfiumError;
7use crate::pdf::document::page::field::private::internal::{
8    PdfFormFieldFlags, PdfFormFieldPrivate,
9};
10
11#[cfg(doc)]
12use {
13    crate::pdf::document::form::PdfForm,
14    crate::pdf::document::page::annotation::PdfPageAnnotationType,
15    crate::pdf::document::page::field::{PdfFormField, PdfFormFieldType},
16};
17
18/// A single [PdfFormField] of type [PdfFormFieldType::Text]. The form field object defines
19/// an interactive data entry widget that allows the user to enter data by typing.
20///
21/// Form fields in Pdfium are wrapped inside page annotations of type [PdfPageAnnotationType::Widget]
22/// or [PdfPageAnnotationType::XfaWidget]. User-specified values can be retrieved directly from
23/// each form field object by unwrapping the form field from the annotation, or in bulk from the
24/// [PdfForm::field_values()] function.
25pub struct PdfFormTextField<'a> {
26    form_handle: FPDF_FORMHANDLE,
27    annotation_handle: FPDF_ANNOTATION,
28    bindings: &'a dyn PdfiumLibraryBindings,
29}
30
31impl<'a> PdfFormTextField<'a> {
32    #[inline]
33    pub(crate) fn from_pdfium(
34        form_handle: FPDF_FORMHANDLE,
35        annotation_handle: FPDF_ANNOTATION,
36        bindings: &'a dyn PdfiumLibraryBindings,
37    ) -> Self {
38        PdfFormTextField {
39            form_handle,
40            annotation_handle,
41            bindings,
42        }
43    }
44
45    /// Returns the [PdfiumLibraryBindings] used by this [PdfFormTextField] object.
46    #[inline]
47    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
48        self.bindings
49    }
50
51    /// Returns the value assigned to this [PdfFormTextField] object, if any.
52    #[inline]
53    pub fn value(&self) -> Option<String> {
54        if self.is_rich_text() {
55            self.get_string_value("RV")
56        } else {
57            self.value_impl()
58        }
59    }
60
61    /// Sets the value of this [PdfFormTextField] object.
62    #[inline]
63    pub fn set_value(&mut self, value: &str) -> Result<(), PdfiumError> {
64        if self.is_rich_text() {
65            self.set_string_value("RV", value)
66        } else {
67            self.set_value_impl(value)
68        }
69    }
70
71    /// Returns `true` if this [PdfFormTextField] is configured as a multi-line text field.
72    #[inline]
73    pub fn is_multiline(&self) -> bool {
74        self.get_flags_impl()
75            .contains(PdfFormFieldFlags::TextMultiline)
76    }
77
78    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
79    /// Controls whether or not this [PdfFormTextField] is configured as a multi-line text field.
80    #[inline]
81    pub fn set_is_multiline(&self, is_multiline: bool) -> Result<(), PdfiumError> {
82        self.update_one_flag_impl(PdfFormFieldFlags::TextMultiline, is_multiline)
83    }
84
85    /// Returns `true` if this [PdfFormTextField] is configured as a password field.
86    #[inline]
87    pub fn is_password(&self) -> bool {
88        self.get_flags_impl()
89            .contains(PdfFormFieldFlags::TextPassword)
90    }
91
92    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
93    /// Controls whether or not this [PdfFormTextField] is configured as a password text field.
94    #[inline]
95    pub fn set_is_password(&self, is_password: bool) -> Result<(), PdfiumError> {
96        self.update_one_flag_impl(PdfFormFieldFlags::TextPassword, is_password)
97    }
98
99    /// Returns `true` if this [PdfFormTextField] represents the path of a file
100    /// whose contents are to be submitted as the value of the field.
101    ///
102    /// This flag was added in PDF version 1.4
103    pub fn is_file_select(&self) -> bool {
104        self.get_flags_impl()
105            .contains(PdfFormFieldFlags::TextFileSelect)
106    }
107
108    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
109    /// Controls whether or not this [PdfFormTextField] represents the path of a file
110    /// whose contents are to be submitted as the value of the field.
111    ///
112    /// This flag was added in PDF version 1.4.
113    pub fn set_is_file_select(&mut self, is_file_select: bool) -> Result<(), PdfiumError> {
114        self.update_one_flag_impl(PdfFormFieldFlags::TextFileSelect, is_file_select)
115    }
116
117    /// Returns `true` if text entered into this [PdfFormTextField] should be spell checked.
118    pub fn is_spell_checked(&self) -> bool {
119        !self
120            .get_flags_impl()
121            .contains(PdfFormFieldFlags::TextDoNotSpellCheck)
122    }
123
124    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
125    /// Controls whether or not text entered into this [PdfFormTextField] should be spell checked.
126    pub fn set_is_spell_checked(&mut self, is_spell_checked: bool) -> Result<(), PdfiumError> {
127        self.update_one_flag_impl(PdfFormFieldFlags::TextDoNotSpellCheck, !is_spell_checked)
128    }
129
130    /// Returns `true` if the internal area of this [PdfFormTextField] can scroll either
131    /// horizontally or vertically to accommodate text entry longer than what can fit
132    /// within the field's annotation bounds. If this value is `false`, then once the
133    /// field is full, no further text entry will be accepted.
134    ///
135    /// This flag was added in PDF version 1.4.
136    pub fn is_scrollable(&self) -> bool {
137        !self
138            .get_flags_impl()
139            .contains(PdfFormFieldFlags::TextDoNotScroll)
140    }
141
142    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
143    /// Controls whether or not the internal area of this [PdfFormTextField] can scroll
144    /// either horizontally or vertically to accommodate text entry longer than what can fit
145    /// within the field's annotation bounds. If set to `false`, no further text entry
146    /// will be accepted once the field's annotation bounds are full.
147    ///
148    /// This flag was added in PDF version 1.4.
149    pub fn set_is_scrollable(&mut self, is_scrollable: bool) -> Result<(), PdfiumError> {
150        self.update_one_flag_impl(PdfFormFieldFlags::TextDoNotScroll, !is_scrollable)
151    }
152
153    /// Returns `true` if this [PdfFormTextField] is "combed", that is, automatically divided
154    /// into equally-spaced positions ("combs"), with the text in the field laid out into
155    /// those combs.
156    ///
157    /// For more information on this setting, refer to Table 8.77 of The PDF Reference
158    /// (Sixth Edition, PDF Format 1.7), on page 691.
159    ///
160    /// This flag was added in PDF version 1.5.
161    pub fn is_combed(&self) -> bool {
162        // This flag only takes effect if the multi-line, password, and file select flags
163        // are all unset.
164
165        !self.is_multiline()
166            && !self.is_password()
167            && !self.is_file_select()
168            && self.get_flags_impl().contains(PdfFormFieldFlags::TextComb)
169    }
170
171    // TODO: AJRC - 20/06/25 - there is little point providing the matching `set_is_combed()`
172    // function, because it makes little sense without being also able to set the `MaxValue`
173    // dictionary parameter that controls the number of combs. However, `MaxValue` must be
174    // an integer, and Pdfium does not currently provide a `FPDFAnnot_SetNumberValue()`
175    // function that could correctly set it.
176
177    /// Returns `true` if the text in this [PdfFormTextField] is a rich text string.
178    ///
179    /// This flag was added in PDF version 1.5.
180    pub fn is_rich_text(&self) -> bool {
181        self.get_flags_impl()
182            .contains(PdfFormFieldFlags::TextRichText)
183    }
184
185    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
186    /// Controls whether or not the text in this [PdfFormTextField] is a rich text string.
187    ///
188    /// This flag was added in PDF version 1.5.
189    pub fn set_is_rich_text(&mut self, is_rich_text: bool) -> Result<(), PdfiumError> {
190        self.update_one_flag_impl(PdfFormFieldFlags::TextRichText, is_rich_text)
191    }
192}
193
194impl<'a> PdfFormFieldPrivate<'a> for PdfFormTextField<'a> {
195    #[inline]
196    fn form_handle(&self) -> FPDF_FORMHANDLE {
197        self.form_handle
198    }
199
200    #[inline]
201    fn annotation_handle(&self) -> FPDF_ANNOTATION {
202        self.annotation_handle
203    }
204
205    #[inline]
206    fn bindings(&self) -> &dyn PdfiumLibraryBindings {
207        self.bindings
208    }
209}