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_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::PdfPageObjectType,
20    crate::pdf::document::page::object::group::PdfPageGroupObject, crate::pdf::document::page::objects::PdfPageObjects,
21};
22
23/// A single [PdfPageObject] of type [PdfPageObjectType::XObjectForm]. The page object contains a
24/// content stream that itself may consist of multiple other page objects. When this page object
25/// is rendered, it renders all its constituent page objects, effectively serving as a template or
26/// stamping object.
27///
28/// Despite the page object name including "form", this page object type bears no relation
29/// to an interactive form containing form fields.
30///
31/// New [PdfPageObjectType::XObjectForm] objects can be created by calling either the
32/// [PdfPageObjects::copy_into_x_object_form_object()] function or the
33/// [PdfPageGroupObject::copy_into_x_object_form_object()] function.
34pub struct PdfPageXObjectFormObject<'a> {
35    object_handle: FPDF_PAGEOBJECT,
36    ownership: PdfPageObjectOwnership,
37    bindings: &'a dyn PdfiumLibraryBindings,
38}
39
40impl<'a> PdfPageXObjectFormObject<'a> {
41    pub(crate) fn from_pdfium(
42        object_handle: FPDF_PAGEOBJECT,
43        ownership: PdfPageObjectOwnership,
44        bindings: &'a dyn PdfiumLibraryBindings,
45    ) -> Self {
46        PdfPageXObjectFormObject {
47            object_handle,
48            ownership,
49            bindings,
50        }
51    }
52
53    /// Returns the total number of child page objects in this [PdfPageXObjectFormObject].
54    #[inline]
55    pub fn len(&self) -> PdfPageObjectIndex {
56        self.len_impl()
57    }
58
59    /// Returns `true` if this page objects collection is empty.
60    #[inline]
61    pub fn is_empty(&self) -> bool {
62        self.len() == 0
63    }
64
65    /// Returns a Range from `0..(number of objects)` for the child page objects in
66    /// this [PdfPageXObjectFormObject].
67    #[inline]
68    pub fn as_range(&self) -> Range<PdfPageObjectIndex> {
69        0..self.len()
70    }
71
72    /// Returns an inclusive Range from `0..=(number of objects - 1)` for the child page objects
73    /// in this [PdfPageXObjectFormObject].
74    #[inline]
75    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageObjectIndex> {
76        if self.is_empty() { 0..=0 } else { 0..=(self.len() - 1) }
77    }
78
79    /// Returns a single child [PdfPageObject] from this [PdfPageXObjectFormObject].
80    #[inline]
81    pub fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
82        self.get_impl(index)
83    }
84
85    /// Returns the first child [PdfPageObject] in this [PdfPageXObjectFormObject].
86    #[inline]
87    pub fn first(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
88        if !self.is_empty() {
89            self.get(0)
90        } else {
91            Err(PdfiumError::NoPageObjectsInCollection)
92        }
93    }
94
95    /// Returns the last child [PdfPageObject] in this [PdfPageXObjectFormObject].
96    #[inline]
97    pub fn last(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
98        if !self.is_empty() {
99            self.get(self.len() - 1)
100        } else {
101            Err(PdfiumError::NoPageObjectsInCollection)
102        }
103    }
104
105    /// Returns an iterator over all the child [PdfPageObject] objects in this [PdfPageXObjectFormObject].
106    #[inline]
107    pub fn iter(&'a self) -> PdfPageObjectsIterator<'a> {
108        self.iter_impl()
109    }
110
111    create_transform_setters!(
112        &mut Self,
113        Result<(), PdfiumError>,
114        "this [PdfPageXObjectFormObject]",
115        "this [PdfPageXObjectFormObject].",
116        "this [PdfPageXObjectFormObject],"
117    );
118
119    create_transform_getters!(
120        "this [PdfPageXObjectFormObject]",
121        "this [PdfPageXObjectFormObject].",
122        "this [PdfPageXObjectFormObject],"
123    );
124}
125
126impl<'a> PdfPageObjectPrivate<'a> for PdfPageXObjectFormObject<'a> {
127    #[inline]
128    fn object_handle(&self) -> FPDF_PAGEOBJECT {
129        self.object_handle
130    }
131
132    #[inline]
133    fn ownership(&self) -> &PdfPageObjectOwnership {
134        &self.ownership
135    }
136
137    #[inline]
138    fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
139        self.ownership = ownership;
140    }
141
142    #[inline]
143    fn bindings(&self) -> &dyn PdfiumLibraryBindings {
144        self.bindings
145    }
146
147    #[inline]
148    fn is_copyable_impl(&self) -> bool {
149        false
150    }
151
152    #[inline]
153    fn try_copy_impl<'b>(
154        &self,
155        _: FPDF_DOCUMENT,
156        _: &'b dyn PdfiumLibraryBindings,
157    ) -> Result<PdfPageObject<'b>, PdfiumError> {
158        Err(PdfiumError::PageObjectNotCopyable)
159    }
160}
161
162impl<'a> PdfPageObjectsPrivate<'a> for PdfPageXObjectFormObject<'a> {
163    #[inline]
164    fn ownership(&self) -> &PdfPageObjectOwnership {
165        &self.ownership
166    }
167
168    #[inline]
169    fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
170        self.bindings
171    }
172
173    #[inline]
174    fn len_impl(&self) -> PdfPageObjectIndex {
175        self.bindings.FPDFFormObj_CountObjects(self.object_handle) as PdfPageObjectIndex
176    }
177
178    fn get_impl(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
179        let object_handle = self
180            .bindings
181            .FPDFFormObj_GetObject(self.object_handle, index as c_ulong);
182
183        if object_handle.is_null() {
184            if index >= self.len() {
185                Err(PdfiumError::PageObjectIndexOutOfBounds)
186            } else {
187                Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
188            }
189        } else {
190            Ok(PdfPageObject::from_pdfium(
191                object_handle,
192                *PdfPageObjectPrivate::ownership(self),
193                PdfPageObjectsPrivate::bindings(self),
194            ))
195        }
196    }
197
198    #[inline]
199    fn iter_impl(&'a self) -> PdfPageObjectsIterator<'a> {
200        PdfPageObjectsIterator::new(self)
201    }
202
203    fn add_object_impl(&mut self, _object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
204        Err(PdfiumError::PageObjectsCollectionIsImmutable)
205    }
206
207    fn remove_object_impl(&mut self, _object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
208        Err(PdfiumError::PageObjectsCollectionIsImmutable)
209    }
210}
211
212impl<'a> Drop for PdfPageXObjectFormObject<'a> {
213    /// Closes this [PdfPageXObjectFormObject], releasing held memory.
214    fn drop(&mut self) {
215        self.drop_impl();
216    }
217}