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}