pdfium_render/pdf/document/page/objects/
common.rs

1//! Defines the [PdfPageObjectsCommon] trait, providing functionality common to all
2//! containers of multiple `PdfPageObject` objects.
3
4use crate::error::{PdfiumError, PdfiumInternalError};
5use crate::pdf::color::PdfColor;
6use crate::pdf::document::fonts::ToPdfFontToken;
7use crate::pdf::document::page::object::image::PdfPageImageObject;
8use crate::pdf::document::page::object::path::PdfPagePathObject;
9use crate::pdf::document::page::object::text::PdfPageTextObject;
10use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectCommon};
11use crate::pdf::document::page::objects::private::internal::PdfPageObjectsPrivate;
12use crate::pdf::document::page::PdfPageObjectOwnership;
13use crate::pdf::points::PdfPoints;
14use crate::pdf::rect::PdfRect;
15use std::ops::{Range, RangeInclusive};
16
17#[cfg(any(feature = "image_latest", feature = "image_025"))]
18use image_025::DynamicImage;
19
20#[cfg(feature = "image_024")]
21use image_024::DynamicImage;
22
23#[cfg(feature = "image_023")]
24use image_023::{DynamicImage, GenericImageView};
25
26#[cfg(doc)]
27use crate::pdf::document::page::PdfPageObjects;
28
29/// The zero-based index of a single [PdfPageObject] inside its containing [PdfPageObjects] collection.
30pub type PdfPageObjectIndex = usize;
31
32/// Functionality common to all containers of multiple [PdfPageObject] objects.
33/// Both pages and annotations can contain page objects.
34pub trait PdfPageObjectsCommon<'a> {
35    /// Returns the total number of page objects in the collection.
36    fn len(&self) -> PdfPageObjectIndex;
37
38    /// Returns true if this page objects collection is empty.
39    #[inline]
40    fn is_empty(&self) -> bool {
41        self.len() == 0
42    }
43
44    /// Returns a Range from `0..(number of objects)` for this page objects collection.
45    #[inline]
46    fn as_range(&self) -> Range<PdfPageObjectIndex> {
47        0..self.len()
48    }
49
50    /// Returns an inclusive Range from `0..=(number of objects - 1)` for this page objects collection.
51    #[inline]
52    fn as_range_inclusive(&self) -> RangeInclusive<PdfPageObjectIndex> {
53        if self.is_empty() {
54            0..=0
55        } else {
56            0..=(self.len() - 1)
57        }
58    }
59
60    /// Returns a single [PdfPageObject] from this page objects collection.
61    fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError>;
62
63    /// Returns the first [PdfPageObject] in this page objects collection.
64    #[inline]
65    fn first(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
66        if !self.is_empty() {
67            self.get(0)
68        } else {
69            Err(PdfiumError::NoPageObjectsInCollection)
70        }
71    }
72
73    /// Returns the last [PdfPageObject] in this page objects collection.
74    #[inline]
75    fn last(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
76        if !self.is_empty() {
77            self.get(self.len() - 1)
78        } else {
79            Err(PdfiumError::NoPageObjectsInCollection)
80        }
81    }
82
83    /// Returns an iterator over all the [PdfPageObject] objects in this page objects collection.
84    fn iter(&'a self) -> PdfPageObjectsIterator<'a>;
85
86    /// Returns the smallest bounding box that contains all the [PdfPageObject] objects in this
87    /// page objects collection.
88    fn bounds(&'a self) -> PdfRect {
89        let mut bottom: f32 = 0.0;
90        let mut top: f32 = 0.0;
91        let mut left: f32 = 0.0;
92        let mut right: f32 = 0.0;
93
94        for object in self.iter() {
95            if let Ok(bounds) = object.bounds() {
96                bottom = bottom.min(bounds.bottom().value);
97                top = top.max(bounds.top().value);
98                left = left.min(bounds.left().value);
99                right = right.max(bounds.right().value);
100            }
101        }
102
103        PdfRect::new_from_values(bottom, left, top, right)
104    }
105
106    /// Adds the given [PdfPageObject] to this page objects collection. The object's
107    /// memory ownership will be transferred to the `PdfPage` containing this page objects
108    /// collection, and the updated page object will be returned.
109    ///
110    /// If the containing `PdfPage` has a content regeneration strategy of
111    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
112    /// will be triggered on the page.
113    fn add_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError>;
114
115    /// Adds the given [PdfPageTextObject] to this page objects collection,
116    /// returning the text object wrapped inside a generic [PdfPageObject] wrapper.
117    ///
118    /// If the containing `PdfPage` has a content regeneration strategy of
119    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
120    /// will be triggered on the page.
121    #[inline]
122    fn add_text_object(
123        &mut self,
124        object: PdfPageTextObject<'a>,
125    ) -> Result<PdfPageObject<'a>, PdfiumError> {
126        self.add_object(PdfPageObject::Text(object))
127    }
128
129    /// Creates a new [PdfPageTextObject] at the given x and y page co-ordinates
130    /// from the given arguments and adds it to this page objects collection,
131    /// returning the text object wrapped inside a generic [PdfPageObject] wrapper.
132    ///
133    /// If the containing `PdfPage` has a content regeneration strategy of
134    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
135    /// will be triggered on the page.
136    fn create_text_object(
137        &mut self,
138        x: PdfPoints,
139        y: PdfPoints,
140        text: impl ToString,
141        font: impl ToPdfFontToken,
142        font_size: PdfPoints,
143    ) -> Result<PdfPageObject<'a>, PdfiumError>;
144
145    /// Adds the given [PdfPagePathObject] to this page objects collection,
146    /// returning the path object wrapped inside a generic [PdfPageObject] wrapper.
147    ///
148    /// If the containing `PdfPage` has a content regeneration strategy of
149    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
150    /// will be triggered on the page.
151    #[inline]
152    fn add_path_object(
153        &mut self,
154        object: PdfPagePathObject<'a>,
155    ) -> Result<PdfPageObject<'a>, PdfiumError> {
156        self.add_object(PdfPageObject::Path(object))
157    }
158
159    /// Creates a new [PdfPagePathObject] for the given line, with the given
160    /// stroke settings applied. The new path object will be added to this page objects collection
161    /// and then returned, wrapped inside a generic [PdfPageObject] wrapper.
162    ///
163    /// If the containing `PdfPage` has a content regeneration strategy of
164    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
165    /// will be triggered on the page.
166    fn create_path_object_line(
167        &mut self,
168        x1: PdfPoints,
169        y1: PdfPoints,
170        x2: PdfPoints,
171        y2: PdfPoints,
172        stroke_color: PdfColor,
173        stroke_width: PdfPoints,
174    ) -> Result<PdfPageObject<'a>, PdfiumError>;
175
176    /// Creates a new [PdfPagePathObject] for the given cubic Bézier curve, with the given
177    /// stroke settings applied. The new path object will be added to this page objects collection
178    /// and then returned, wrapped inside a generic [PdfPageObject] wrapper.
179    ///
180    /// If the containing `PdfPage` has a content regeneration strategy of
181    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
182    /// will be triggered on the page.
183    #[allow(clippy::too_many_arguments)]
184    fn create_path_object_bezier(
185        &mut self,
186        x1: PdfPoints,
187        y1: PdfPoints,
188        x2: PdfPoints,
189        y2: PdfPoints,
190        control1_x: PdfPoints,
191        control1_y: PdfPoints,
192        control2_x: PdfPoints,
193        control2_y: PdfPoints,
194        stroke_color: PdfColor,
195        stroke_width: PdfPoints,
196    ) -> Result<PdfPageObject<'a>, PdfiumError>;
197
198    /// Creates a new [PdfPagePathObject] for the given rectangle, with the given
199    /// fill and stroke settings applied. Both the stroke color and the stroke width must be
200    /// provided for the rectangle to be stroked. The new path object will be added to
201    /// this page objects collection and then returned, wrapped inside a generic
202    /// [PdfPageObject] wrapper.
203    ///
204    /// If the containing `PdfPage` has a content regeneration strategy of
205    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
206    /// will be triggered on the page.
207    fn create_path_object_rect(
208        &mut self,
209        rect: PdfRect,
210        stroke_color: Option<PdfColor>,
211        stroke_width: Option<PdfPoints>,
212        fill_color: Option<PdfColor>,
213    ) -> Result<PdfPageObject<'a>, PdfiumError>;
214
215    /// Creates a new [PdfPagePathObject]. The new path will be created with a circle that fills
216    /// the given rectangle, with the given fill and stroke settings applied. Both the stroke color
217    /// and the stroke width must be provided for the circle to be stroked. The new path object
218    /// will be added to this page objects collection and then returned, wrapped inside a generic
219    /// [PdfPageObject] wrapper.
220    ///
221    /// If the containing `PdfPage` has a content regeneration strategy of
222    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
223    /// will be triggered on the page.
224    fn create_path_object_circle(
225        &mut self,
226        rect: PdfRect,
227        stroke_color: Option<PdfColor>,
228        stroke_width: Option<PdfPoints>,
229        fill_color: Option<PdfColor>,
230    ) -> Result<PdfPageObject<'a>, PdfiumError>;
231
232    /// Creates a new [PdfPagePathObject]. The new path will be created with a circle centered
233    /// at the given coordinates, with the given radius, and with the given fill and stroke settings
234    /// applied. Both the stroke color and the stroke width must be provided for the circle to be
235    /// stroked. The new path object will be added to this page objects collection and then
236    /// returned, wrapped inside a generic [PdfPageObject] wrapper.
237    ///
238    /// If the containing `PdfPage` has a content regeneration strategy of
239    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then the content regeneration
240    /// will be triggered on the page.
241    fn create_path_object_circle_at(
242        &mut self,
243        center_x: PdfPoints,
244        center_y: PdfPoints,
245        radius: PdfPoints,
246        stroke_color: Option<PdfColor>,
247        stroke_width: Option<PdfPoints>,
248        fill_color: Option<PdfColor>,
249    ) -> Result<PdfPageObject<'a>, PdfiumError>;
250
251    /// Creates a new [PdfPagePathObject]. The new path will be created with an ellipse that fills
252    /// the given rectangle, with the given fill and stroke settings applied. Both the stroke color
253    /// and the stroke width must be provided for the ellipse to be stroked. The new path object
254    /// will be added to this page objects collection and then returned, wrapped inside a generic
255    /// [PdfPageObject] wrapper.
256    ///
257    /// If the containing `PdfPage` has a content regeneration strategy of
258    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then the content regeneration
259    /// will be triggered on the page.
260    fn create_path_object_ellipse(
261        &mut self,
262        rect: PdfRect,
263        stroke_color: Option<PdfColor>,
264        stroke_width: Option<PdfPoints>,
265        fill_color: Option<PdfColor>,
266    ) -> Result<PdfPageObject<'a>, PdfiumError>;
267
268    /// Creates a new [PdfPagePathObject]. The new path will be created with an ellipse centered
269    /// at the given coordinates, with the given radii, and with the given fill and stroke settings
270    /// applied. Both the stroke color and the stroke width must be provided for the ellipse to be
271    /// stroked. The new path object will be added to this page objects collection and then
272    /// returned, wrapped inside a generic [PdfPageObject] wrapper.
273    ///
274    /// If the containing `PdfPage` has a content regeneration strategy of
275    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then the content regeneration
276    /// will be triggered on the page.
277    #[allow(clippy::too_many_arguments)]
278    fn create_path_object_ellipse_at(
279        &mut self,
280        center_x: PdfPoints,
281        center_y: PdfPoints,
282        x_radius: PdfPoints,
283        y_radius: PdfPoints,
284        stroke_color: Option<PdfColor>,
285        stroke_width: Option<PdfPoints>,
286        fill_color: Option<PdfColor>,
287    ) -> Result<PdfPageObject<'a>, PdfiumError>;
288
289    /// Adds the given [PdfPageImageObject] to this page objects collection,
290    /// returning the image object wrapped inside a generic [PdfPageObject] wrapper.
291    ///
292    /// If the containing `PdfPage` has a content regeneration strategy of
293    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
294    /// will be triggered on the page.
295    #[inline]
296    fn add_image_object(
297        &mut self,
298        object: PdfPageImageObject<'a>,
299    ) -> Result<PdfPageObject<'a>, PdfiumError> {
300        self.add_object(PdfPageObject::Image(object))
301    }
302
303    /// Creates a new [PdfPageImageObject] at the given x and y page co-ordinates
304    /// from the given arguments and adds it to this page objects collection,
305    /// returning the image object wrapped inside a generic [PdfPageObject] wrapper.
306    ///
307    /// By default, new image objects have their width and height both set to 1.0 points.
308    /// If provided, the given width and/or height will be applied to the newly created object to
309    /// scale its size.
310    ///
311    /// If the containing `PdfPage` has a content regeneration strategy of
312    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then the content regeneration
313    /// will be triggered on the page.
314    ///
315    /// This function is only available when this crate's `image` feature is enabled.
316    #[cfg(feature = "image_api")]
317    fn create_image_object(
318        &mut self,
319        x: PdfPoints,
320        y: PdfPoints,
321        image: &DynamicImage,
322        width: Option<PdfPoints>,
323        height: Option<PdfPoints>,
324    ) -> Result<PdfPageObject<'a>, PdfiumError>;
325
326    /// Removes the given [PdfPageObject] from this page objects collection. The object's
327    /// memory ownership will be removed from the `PdfPage` containing this page objects
328    /// collection, and the updated page object will be returned. It can be added back to a
329    /// page objects collection or dropped, at which point the memory owned by the object will
330    /// be freed.
331    ///
332    /// If the containing `PdfPage` has a content regeneration strategy of
333    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
334    /// will be triggered on the page.
335    fn remove_object(
336        &mut self,
337        object: PdfPageObject<'a>,
338    ) -> Result<PdfPageObject<'a>, PdfiumError>;
339
340    /// Removes the [PdfPageObject] at the given index from this page objects collection.
341    /// The object's memory ownership will be removed from the `PdfPage` containing this page objects
342    /// collection, and the updated page object will be returned. It can be added back into a
343    /// page objects collection or discarded, at which point the memory owned by the object will
344    /// be freed.
345    ///
346    /// If the containing `PdfPage` has a content regeneration strategy of
347    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
348    /// will be triggered on the page.
349    fn remove_object_at_index(
350        &mut self,
351        index: PdfPageObjectIndex,
352    ) -> Result<PdfPageObject<'a>, PdfiumError>;
353}
354
355// Blanket implementation for all PdfPageObjects collection types.
356
357impl<'a, T> PdfPageObjectsCommon<'a> for T
358where
359    T: PdfPageObjectsPrivate<'a>,
360{
361    #[inline]
362    fn len(&self) -> PdfPageObjectIndex {
363        self.len_impl()
364    }
365
366    #[inline]
367    fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
368        self.get_impl(index)
369    }
370
371    #[inline]
372    fn iter(&'a self) -> PdfPageObjectsIterator<'a> {
373        self.iter_impl()
374    }
375
376    #[inline]
377    fn add_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
378        self.add_object_impl(object)
379    }
380
381    #[inline]
382    fn create_text_object(
383        &mut self,
384        x: PdfPoints,
385        y: PdfPoints,
386        text: impl ToString,
387        font: impl ToPdfFontToken,
388        font_size: PdfPoints,
389    ) -> Result<PdfPageObject<'a>, PdfiumError> {
390        let document_handle = match self.ownership() {
391            PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
392            PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
393                Some(ownership.document_handle())
394            }
395            PdfPageObjectOwnership::UnattachedAnnotation(ownership) => {
396                Some(ownership.document_handle())
397            }
398            _ => None,
399        };
400
401        if let Some(document_handle) = document_handle {
402            let mut object = PdfPageTextObject::new_from_handles(
403                document_handle,
404                text,
405                font.token().handle(),
406                font_size,
407                self.bindings(),
408            )?;
409
410            object.translate(x, y)?;
411
412            self.add_text_object(object)
413        } else {
414            Err(PdfiumError::OwnershipNotAttachedToPage)
415        }
416    }
417
418    #[inline]
419    fn create_path_object_line(
420        &mut self,
421        x1: PdfPoints,
422        y1: PdfPoints,
423        x2: PdfPoints,
424        y2: PdfPoints,
425        stroke_color: PdfColor,
426        stroke_width: PdfPoints,
427    ) -> Result<PdfPageObject<'a>, PdfiumError> {
428        let object = PdfPagePathObject::new_line_from_bindings(
429            self.bindings(),
430            x1,
431            y1,
432            x2,
433            y2,
434            stroke_color,
435            stroke_width,
436        )?;
437
438        self.add_path_object(object)
439    }
440
441    #[inline]
442    fn create_path_object_bezier(
443        &mut self,
444        x1: PdfPoints,
445        y1: PdfPoints,
446        x2: PdfPoints,
447        y2: PdfPoints,
448        control1_x: PdfPoints,
449        control1_y: PdfPoints,
450        control2_x: PdfPoints,
451        control2_y: PdfPoints,
452        stroke_color: PdfColor,
453        stroke_width: PdfPoints,
454    ) -> Result<PdfPageObject<'a>, PdfiumError> {
455        let object = PdfPagePathObject::new_bezier_from_bindings(
456            self.bindings(),
457            x1,
458            y1,
459            x2,
460            y2,
461            control1_x,
462            control1_y,
463            control2_x,
464            control2_y,
465            stroke_color,
466            stroke_width,
467        )?;
468
469        self.add_path_object(object)
470    }
471
472    #[inline]
473    fn create_path_object_rect(
474        &mut self,
475        rect: PdfRect,
476        stroke_color: Option<PdfColor>,
477        stroke_width: Option<PdfPoints>,
478        fill_color: Option<PdfColor>,
479    ) -> Result<PdfPageObject<'a>, PdfiumError> {
480        let object = PdfPagePathObject::new_rect_from_bindings(
481            self.bindings(),
482            rect,
483            stroke_color,
484            stroke_width,
485            fill_color,
486        )?;
487
488        self.add_path_object(object)
489    }
490
491    #[inline]
492    fn create_path_object_circle(
493        &mut self,
494        rect: PdfRect,
495        stroke_color: Option<PdfColor>,
496        stroke_width: Option<PdfPoints>,
497        fill_color: Option<PdfColor>,
498    ) -> Result<PdfPageObject<'a>, PdfiumError> {
499        let object = PdfPagePathObject::new_circle_from_bindings(
500            self.bindings(),
501            rect,
502            stroke_color,
503            stroke_width,
504            fill_color,
505        )?;
506
507        self.add_path_object(object)
508    }
509
510    #[inline]
511    fn create_path_object_circle_at(
512        &mut self,
513        center_x: PdfPoints,
514        center_y: PdfPoints,
515        radius: PdfPoints,
516        stroke_color: Option<PdfColor>,
517        stroke_width: Option<PdfPoints>,
518        fill_color: Option<PdfColor>,
519    ) -> Result<PdfPageObject<'a>, PdfiumError> {
520        let object = PdfPagePathObject::new_circle_at_from_bindings(
521            self.bindings(),
522            center_x,
523            center_y,
524            radius,
525            stroke_color,
526            stroke_width,
527            fill_color,
528        )?;
529
530        self.add_path_object(object)
531    }
532
533    #[inline]
534    fn create_path_object_ellipse(
535        &mut self,
536        rect: PdfRect,
537        stroke_color: Option<PdfColor>,
538        stroke_width: Option<PdfPoints>,
539        fill_color: Option<PdfColor>,
540    ) -> Result<PdfPageObject<'a>, PdfiumError> {
541        let object = PdfPagePathObject::new_ellipse_from_bindings(
542            self.bindings(),
543            rect,
544            stroke_color,
545            stroke_width,
546            fill_color,
547        )?;
548
549        self.add_path_object(object)
550    }
551
552    #[inline]
553    fn create_path_object_ellipse_at(
554        &mut self,
555        center_x: PdfPoints,
556        center_y: PdfPoints,
557        x_radius: PdfPoints,
558        y_radius: PdfPoints,
559        stroke_color: Option<PdfColor>,
560        stroke_width: Option<PdfPoints>,
561        fill_color: Option<PdfColor>,
562    ) -> Result<PdfPageObject<'a>, PdfiumError> {
563        let object = PdfPagePathObject::new_ellipse_at_from_bindings(
564            self.bindings(),
565            center_x,
566            center_y,
567            x_radius,
568            y_radius,
569            stroke_color,
570            stroke_width,
571            fill_color,
572        )?;
573
574        self.add_path_object(object)
575    }
576
577    #[cfg(feature = "image_api")]
578    fn create_image_object(
579        &mut self,
580        x: PdfPoints,
581        y: PdfPoints,
582        image: &DynamicImage,
583        width: Option<PdfPoints>,
584        height: Option<PdfPoints>,
585    ) -> Result<PdfPageObject<'a>, PdfiumError> {
586        let document_handle = match self.ownership() {
587            PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
588            PdfPageObjectOwnership::AttachedAnnotation(ownership) => {
589                Some(ownership.document_handle())
590            }
591            PdfPageObjectOwnership::UnattachedAnnotation(ownership) => {
592                Some(ownership.document_handle())
593            }
594            _ => None,
595        };
596
597        if let Some(document_handle) = document_handle {
598            let image_width = image.width();
599
600            let image_height = image.height();
601
602            let mut object = PdfPageImageObject::new_from_handle(document_handle, self.bindings())?;
603
604            object.set_image(image)?;
605
606            // Apply specified dimensions, if provided.
607
608            match (width, height) {
609                (Some(width), Some(height)) => {
610                    object.scale(width.value, height.value)?;
611                }
612                (Some(width), None) => {
613                    let aspect_ratio = image_height as f32 / image_width as f32;
614
615                    let height = width * aspect_ratio;
616
617                    object.scale(width.value, height.value)?;
618                }
619                (None, Some(height)) => {
620                    let aspect_ratio = image_height as f32 / image_width as f32;
621
622                    let width = height / aspect_ratio;
623
624                    object.scale(width.value, height.value)?;
625                }
626                (None, None) => {}
627            }
628
629            object.translate(x, y)?;
630
631            self.add_image_object(object)
632        } else {
633            Err(PdfiumError::OwnershipNotAttachedToPage)
634        }
635    }
636
637    #[inline]
638    fn remove_object(
639        &mut self,
640        object: PdfPageObject<'a>,
641    ) -> Result<PdfPageObject<'a>, PdfiumError> {
642        self.remove_object_impl(object)
643    }
644
645    fn remove_object_at_index(
646        &mut self,
647        index: PdfPageObjectIndex,
648    ) -> Result<PdfPageObject<'a>, PdfiumError> {
649        if index >= self.len() {
650            return Err(PdfiumError::PageObjectIndexOutOfBounds);
651        }
652
653        if let Ok(object) = self.get(index) {
654            self.remove_object(object)
655        } else {
656            Err(PdfiumError::PdfiumLibraryInternalError(
657                PdfiumInternalError::Unknown,
658            ))
659        }
660    }
661}
662
663/// An iterator over all the [PdfPageObject] objects in a page objects collection.
664pub struct PdfPageObjectsIterator<'a> {
665    objects: &'a dyn PdfPageObjectsPrivate<'a>,
666    next_index: PdfPageObjectIndex,
667}
668
669impl<'a> PdfPageObjectsIterator<'a> {
670    #[inline]
671    pub(crate) fn new(objects: &'a dyn PdfPageObjectsPrivate<'a>) -> Self {
672        PdfPageObjectsIterator {
673            objects,
674            next_index: 0,
675        }
676    }
677}
678
679impl<'a> Iterator for PdfPageObjectsIterator<'a> {
680    type Item = PdfPageObject<'a>;
681
682    fn next(&mut self) -> Option<Self::Item> {
683        let next = self.objects.get_impl(self.next_index);
684
685        self.next_index += 1;
686
687        next.ok()
688    }
689}