pdfium_render/pdf/document/page/object/
x_object_form.rs

1//! Defines the [PdfPageXObjectFormObject] struct, exposing functionality related to a single
2//! page object of type `PdfPageObjectType::XObjectForm`.
3
4use crate::bindgen::{FPDF_DOCUMENT, FPDF_PAGEOBJECT};
5use crate::bindings::PdfiumLibraryBindings;
6use crate::error::{PdfiumError, PdfiumInternalError};
7use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
8use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectOwnership};
9use crate::pdf::document::page::objects::common::{PdfPageObjectIndex, PdfPageObjectsIterator};
10use crate::pdf::document::page::objects::private::internal::PdfPageObjectsPrivate;
11use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
12use crate::pdf::points::PdfPoints;
13use crate::{create_transform_getters, create_transform_setters};
14use std::ops::{Range, RangeInclusive};
15use std::os::raw::c_ulong;
16
17#[cfg(doc)]
18use {
19    crate::pdf::document::page::object::group::PdfPageGroupObject,
20    crate::pdf::document::page::object::PdfPageObjectType,
21    crate::pdf::document::page::objects::PdfPageObjects,
22};
23
24/// A single [PdfPageObject] of type [PdfPageObjectType::XObjectForm]. The page object contains a
25/// content stream that itself may consist of multiple other page objects. When this page object
26/// is rendered, it renders all its constituent page objects, effectively serving as a template or
27/// stamping object.
28///
29/// Despite the page object name including "form", this page object type bears no relation
30/// to an interactive form containing form fields.
31///
32/// New [PdfPageObjectType::XObjectForm] objects can be created by calling either the
33/// [PdfPageObjects::copy_into_x_object_form_object()] function or the
34/// [PdfPageGroupObject::copy_into_x_object_form_object()] function.
35pub struct PdfPageXObjectFormObject<'a> {
36    object_handle: FPDF_PAGEOBJECT,
37    ownership: PdfPageObjectOwnership,
38    bindings: &'a dyn PdfiumLibraryBindings,
39}
40
41impl<'a> PdfPageXObjectFormObject<'a> {
42    pub(crate) fn from_pdfium(
43        object_handle: FPDF_PAGEOBJECT,
44        ownership: PdfPageObjectOwnership,
45        bindings: &'a dyn PdfiumLibraryBindings,
46    ) -> Self {
47        PdfPageXObjectFormObject {
48            object_handle,
49            ownership,
50            bindings,
51        }
52    }
53
54    /// Returns the total number of child page objects in this [PdfPageXObjectFormObject].
55    #[inline]
56    pub fn len(&self) -> PdfPageObjectIndex {
57        self.len_impl()
58    }
59
60    /// Returns `true` if this page objects collection is empty.
61    #[inline]
62    pub fn is_empty(&self) -> bool {
63        self.len() == 0
64    }
65
66    /// Returns a Range from `0..(number of objects)` for the child page objects in
67    /// this [PdfPageXObjectFormObject].
68    #[inline]
69    pub fn as_range(&self) -> Range<PdfPageObjectIndex> {
70        0..self.len()
71    }
72
73    /// Returns an inclusive Range from `0..=(number of objects - 1)` for the child page objects
74    /// in this [PdfPageXObjectFormObject].
75    #[inline]
76    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageObjectIndex> {
77        if self.is_empty() {
78            0..=0
79        } else {
80            0..=(self.len() - 1)
81        }
82    }
83
84    /// Returns a single child [PdfPageObject] from this [PdfPageXObjectFormObject].
85    #[inline]
86    pub fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
87        self.get_impl(index)
88    }
89
90    /// Returns the first child [PdfPageObject] in this [PdfPageXObjectFormObject].
91    #[inline]
92    pub fn first(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
93        if !self.is_empty() {
94            self.get(0)
95        } else {
96            Err(PdfiumError::NoPageObjectsInCollection)
97        }
98    }
99
100    /// Returns the last child [PdfPageObject] in this [PdfPageXObjectFormObject].
101    #[inline]
102    pub fn last(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
103        if !self.is_empty() {
104            self.get(self.len() - 1)
105        } else {
106            Err(PdfiumError::NoPageObjectsInCollection)
107        }
108    }
109
110    /// Returns an iterator over all the child [PdfPageObject] objects in this [PdfPageXObjectFormObject].
111    #[inline]
112    pub fn iter(&'a self) -> PdfPageObjectsIterator<'a> {
113        self.iter_impl()
114    }
115
116    create_transform_setters!(
117        &mut Self,
118        Result<(), PdfiumError>,
119        "this [PdfPageXObjectFormObject]",
120        "this [PdfPageXObjectFormObject].",
121        "this [PdfPageXObjectFormObject],"
122    );
123
124    // The transform_impl() function required by the create_transform_setters!() macro
125    // is provided by the PdfPageObjectPrivate trait.
126
127    create_transform_getters!(
128        "this [PdfPageXObjectFormObject]",
129        "this [PdfPageXObjectFormObject].",
130        "this [PdfPageXObjectFormObject],"
131    );
132
133    // The get_matrix_impl() function required by the create_transform_getters!() macro
134    // is provided by the PdfPageObjectPrivate trait.
135}
136
137impl<'a> PdfPageObjectPrivate<'a> for PdfPageXObjectFormObject<'a> {
138    #[inline]
139    fn object_handle(&self) -> FPDF_PAGEOBJECT {
140        self.object_handle
141    }
142
143    #[inline]
144    fn ownership(&self) -> &PdfPageObjectOwnership {
145        &self.ownership
146    }
147
148    #[inline]
149    fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
150        self.ownership = ownership;
151    }
152
153    #[inline]
154    fn bindings(&self) -> &dyn PdfiumLibraryBindings {
155        self.bindings
156    }
157
158    #[inline]
159    fn is_copyable_impl(&self) -> bool {
160        false
161    }
162
163    #[inline]
164    fn try_copy_impl<'b>(
165        &self,
166        _: FPDF_DOCUMENT,
167        _: &'b dyn PdfiumLibraryBindings,
168    ) -> Result<PdfPageObject<'b>, PdfiumError> {
169        Err(PdfiumError::PageObjectNotCopyable)
170    }
171}
172
173impl<'a> PdfPageObjectsPrivate<'a> for PdfPageXObjectFormObject<'a> {
174    #[inline]
175    fn ownership(&self) -> &PdfPageObjectOwnership {
176        &self.ownership
177    }
178
179    #[inline]
180    fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
181        self.bindings
182    }
183
184    #[inline]
185    fn len_impl(&self) -> PdfPageObjectIndex {
186        self.bindings.FPDFFormObj_CountObjects(self.object_handle) as PdfPageObjectIndex
187    }
188
189    fn get_impl(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
190        let object_handle = self
191            .bindings
192            .FPDFFormObj_GetObject(self.object_handle, index as c_ulong);
193
194        if object_handle.is_null() {
195            if index >= self.len() {
196                Err(PdfiumError::PageObjectIndexOutOfBounds)
197            } else {
198                Err(PdfiumError::PdfiumLibraryInternalError(
199                    PdfiumInternalError::Unknown,
200                ))
201            }
202        } else {
203            Ok(PdfPageObject::from_pdfium(
204                object_handle,
205                *PdfPageObjectPrivate::ownership(self),
206                PdfPageObjectsPrivate::bindings(self),
207            ))
208        }
209    }
210
211    #[inline]
212    fn iter_impl(&'a self) -> PdfPageObjectsIterator<'a> {
213        PdfPageObjectsIterator::new(self)
214    }
215
216    // The child objects collection is read-only.
217
218    fn add_object_impl(
219        &mut self,
220        _object: PdfPageObject<'a>,
221    ) -> Result<PdfPageObject<'a>, PdfiumError> {
222        Err(PdfiumError::PageObjectsCollectionIsImmutable)
223    }
224
225    #[cfg(any(feature = "pdfium_future", feature = "pdfium_7350"))]
226    fn remove_object_impl(
227        &mut self,
228        mut object: PdfPageObject<'a>,
229    ) -> Result<PdfPageObject<'a>, PdfiumError> {
230        if self.bindings.is_true(
231            self.bindings
232                .FPDFFormObj_RemoveObject(self.object_handle, object.object_handle()),
233        ) {
234            object.set_ownership(PdfPageObjectOwnership::Unowned);
235
236            Ok(object)
237        } else {
238            Err(PdfiumError::PdfiumLibraryInternalError(
239                PdfiumInternalError::Unknown,
240            ))
241        }
242    }
243
244    #[cfg(not(any(feature = "pdfium_future", feature = "pdfium_7350")))]
245    fn remove_object_impl(
246        &mut self,
247        _object: PdfPageObject<'a>,
248    ) -> Result<PdfPageObject<'a>, PdfiumError> {
249        Err(PdfiumError::PageObjectsCollectionIsImmutable)
250    }
251}
252
253impl<'a> Drop for PdfPageXObjectFormObject<'a> {
254    /// Closes this [PdfPageXObjectFormObject], releasing held memory.
255    fn drop(&mut self) {
256        self.drop_impl();
257    }
258}