pdfium_render/pdf/document/page/field/
options.rs1use crate::bindgen::{FPDF_ANNOTATION, FPDF_FORMHANDLE, FPDF_WCHAR};
5use crate::error::PdfiumError;
6use crate::pdf::document::page::field::option::PdfFormFieldOption;
7use crate::pdfium::PdfiumLibraryBindingsAccessor;
8use crate::utils::mem::create_byte_buffer;
9use crate::utils::utf16le::get_string_from_pdfium_utf16le_bytes;
10use std::marker::PhantomData;
11use std::ops::{Range, RangeInclusive};
12use std::os::raw::c_int;
13
14pub type PdfFormFieldOptionIndex = usize;
16
17pub struct PdfFormFieldOptions<'a> {
19 form_handle: FPDF_FORMHANDLE,
20 annotation_handle: FPDF_ANNOTATION,
21 lifetime: PhantomData<&'a FPDF_ANNOTATION>,
22}
23
24impl<'a> PdfFormFieldOptions<'a> {
25 #[inline]
26 pub(crate) fn from_pdfium(
27 form_handle: FPDF_FORMHANDLE,
28 annotation_handle: FPDF_ANNOTATION,
29 ) -> Self {
30 PdfFormFieldOptions {
31 form_handle,
32 annotation_handle,
33 lifetime: PhantomData,
34 }
35 }
36
37 pub fn len(&self) -> PdfFormFieldOptionIndex {
39 let result = unsafe {
40 self.bindings()
41 .FPDFAnnot_GetOptionCount(self.form_handle, self.annotation_handle)
42 };
43
44 if result == -1 {
45 0
46 } else {
47 result as PdfFormFieldOptionIndex
48 }
49 }
50
51 #[inline]
53 pub fn is_empty(&self) -> bool {
54 self.len() == 0
55 }
56
57 #[inline]
59 pub fn as_range(&self) -> Range<PdfFormFieldOptionIndex> {
60 0..self.len()
61 }
62
63 #[inline]
66 pub fn as_range_inclusive(&self) -> RangeInclusive<PdfFormFieldOptionIndex> {
67 if self.is_empty() {
68 0..=0
69 } else {
70 0..=(self.len() - 1)
71 }
72 }
73
74 pub fn get(&self, index: PdfFormFieldOptionIndex) -> Result<PdfFormFieldOption, PdfiumError> {
76 if index >= self.len() {
77 return Err(PdfiumError::FormFieldOptionIndexOutOfBounds);
78 }
79
80 let buffer_length = unsafe {
89 self.bindings().FPDFAnnot_GetOptionLabel(
90 self.form_handle,
91 self.annotation_handle,
92 index as c_int,
93 std::ptr::null_mut(),
94 0,
95 )
96 };
97
98 let option_label = if buffer_length == 0 {
99 None
102 } else {
103 let mut buffer = create_byte_buffer(buffer_length as usize);
104
105 let result = unsafe {
106 self.bindings().FPDFAnnot_GetOptionLabel(
107 self.form_handle,
108 self.annotation_handle,
109 index as c_int,
110 buffer.as_mut_ptr() as *mut FPDF_WCHAR,
111 buffer_length,
112 )
113 };
114
115 debug_assert_eq!(result, buffer_length);
116
117 get_string_from_pdfium_utf16le_bytes(buffer)
118 };
119
120 let option_is_set = self.bindings().is_true(unsafe {
121 self.bindings().FPDFAnnot_IsOptionSelected(
122 self.form_handle,
123 self.annotation_handle,
124 index as c_int,
125 )
126 });
127
128 Ok(PdfFormFieldOption::new(index, option_is_set, option_label))
129 }
130
131 #[inline]
133 pub fn iter(&self) -> PdfFormFieldOptionsIterator<'_> {
134 PdfFormFieldOptionsIterator::new(self)
135 }
136}
137
138impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfFormFieldOptions<'a> {}
139
140#[cfg(feature = "thread_safe")]
141unsafe impl<'a> Send for PdfFormFieldOptions<'a> {}
142
143#[cfg(feature = "thread_safe")]
144unsafe impl<'a> Sync for PdfFormFieldOptions<'a> {}
145
146pub struct PdfFormFieldOptionsIterator<'a> {
148 options: &'a PdfFormFieldOptions<'a>,
149 next_index: PdfFormFieldOptionIndex,
150}
151
152impl<'a> PdfFormFieldOptionsIterator<'a> {
153 #[inline]
154 pub(crate) fn new(options: &'a PdfFormFieldOptions<'a>) -> Self {
155 PdfFormFieldOptionsIterator {
156 options,
157 next_index: 0,
158 }
159 }
160}
161
162impl<'a> Iterator for PdfFormFieldOptionsIterator<'a> {
163 type Item = PdfFormFieldOption;
164
165 fn next(&mut self) -> Option<Self::Item> {
166 let next = self.options.get(self.next_index);
167
168 self.next_index += 1;
169
170 next.ok()
171 }
172}