Skip to main content

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_PAGEOBJECT;
5use crate::error::{PdfiumError, PdfiumInternalError};
6use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
7use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectOwnership};
8use crate::pdf::document::page::objects::common::{PdfPageObjectIndex, PdfPageObjectsIterator};
9use crate::pdf::document::page::objects::private::internal::PdfPageObjectsPrivate;
10use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
11use crate::pdf::points::PdfPoints;
12use crate::pdfium::PdfiumLibraryBindingsAccessor;
13use crate::{create_transform_getters, create_transform_setters};
14use std::marker::PhantomData;
15use std::ops::{Range, RangeInclusive};
16use std::os::raw::c_ulong;
17
18#[cfg(doc)]
19use {
20    crate::pdf::document::page::object::group::PdfPageGroupObject,
21    crate::pdf::document::page::object::PdfPageObjectType,
22    crate::pdf::document::page::objects::PdfPageObjects,
23};
24
25/// A single [PdfPageObject] of type [PdfPageObjectType::XObjectForm]. The page object contains a
26/// content stream that itself may consist of multiple other page objects. When this page object
27/// is rendered, it renders all its constituent page objects, effectively serving as a template or
28/// stamping object.
29///
30/// Despite the page object name including "form", this page object type bears no relation
31/// to an interactive form containing form fields.
32///
33/// New [PdfPageObjectType::XObjectForm] objects can be created by calling either the
34/// [PdfPageObjects::copy_into_x_object_form_object()] function or the
35/// [PdfPageGroupObject::copy_into_x_object_form_object()] function.
36pub struct PdfPageXObjectFormObject<'a> {
37    object_handle: FPDF_PAGEOBJECT,
38    ownership: PdfPageObjectOwnership,
39    lifetime: PhantomData<&'a FPDF_PAGEOBJECT>,
40}
41
42impl<'a> PdfPageXObjectFormObject<'a> {
43    pub(crate) fn from_pdfium(
44        object_handle: FPDF_PAGEOBJECT,
45        ownership: PdfPageObjectOwnership,
46    ) -> Self {
47        PdfPageXObjectFormObject {
48            object_handle,
49            ownership,
50            lifetime: PhantomData,
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
154impl<'a> PdfPageObjectsPrivate<'a> for PdfPageXObjectFormObject<'a> {
155    #[inline]
156    fn ownership(&self) -> &PdfPageObjectOwnership {
157        &self.ownership
158    }
159
160    #[inline]
161    fn len_impl(&self) -> PdfPageObjectIndex {
162        (unsafe { self.bindings().FPDFFormObj_CountObjects(self.object_handle) })
163            as PdfPageObjectIndex
164    }
165
166    fn get_impl(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
167        let object_handle = unsafe {
168            self.bindings()
169                .FPDFFormObj_GetObject(self.object_handle, index as c_ulong)
170        };
171
172        if object_handle.is_null() {
173            if index >= self.len() {
174                Err(PdfiumError::PageObjectIndexOutOfBounds)
175            } else {
176                Err(PdfiumError::PdfiumLibraryInternalError(
177                    PdfiumInternalError::Unknown,
178                ))
179            }
180        } else {
181            Ok(PdfPageObject::from_pdfium(
182                object_handle,
183                *PdfPageObjectPrivate::ownership(self),
184                PdfiumLibraryBindingsAccessor::bindings(self),
185            ))
186        }
187    }
188
189    #[inline]
190    fn iter_impl(&'a self) -> PdfPageObjectsIterator<'a> {
191        PdfPageObjectsIterator::new(self)
192    }
193
194    // The child objects collection is read-only.
195
196    fn add_object_impl(
197        &mut self,
198        _object: PdfPageObject<'a>,
199    ) -> Result<PdfPageObject<'a>, PdfiumError> {
200        Err(PdfiumError::PageObjectsCollectionIsImmutable)
201    }
202
203    #[cfg(any(
204        feature = "pdfium_future",
205        feature = "pdfium_7543",
206        feature = "pdfium_7350"
207    ))]
208    fn remove_object_impl(
209        &mut self,
210        mut object: PdfPageObject<'a>,
211    ) -> Result<PdfPageObject<'a>, PdfiumError> {
212        if self.bindings().is_true(unsafe {
213            self.bindings()
214                .FPDFFormObj_RemoveObject(self.object_handle, object.object_handle())
215        }) {
216            object.set_ownership(PdfPageObjectOwnership::Unowned);
217
218            Ok(object)
219        } else {
220            Err(PdfiumError::PdfiumLibraryInternalError(
221                PdfiumInternalError::Unknown,
222            ))
223        }
224    }
225
226    #[cfg(not(any(
227        feature = "pdfium_future",
228        feature = "pdfium_7543",
229        feature = "pdfium_7350"
230    )))]
231    fn remove_object_impl(
232        &mut self,
233        _object: PdfPageObject<'a>,
234    ) -> Result<PdfPageObject<'a>, PdfiumError> {
235        Err(PdfiumError::PageObjectsCollectionIsImmutable)
236    }
237}
238
239impl<'a> Drop for PdfPageXObjectFormObject<'a> {
240    /// Closes this [PdfPageXObjectFormObject], releasing held memory.
241    fn drop(&mut self) {
242        self.drop_impl();
243    }
244}
245
246impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageXObjectFormObject<'a> {}
247
248#[cfg(feature = "thread_safe")]
249unsafe impl<'a> Send for PdfPageXObjectFormObject<'a> {}
250
251#[cfg(feature = "thread_safe")]
252unsafe impl<'a> Sync for PdfPageXObjectFormObject<'a> {}