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