Skip to main content

pdfium_render/pdf/path/
clip_path.rs

1//! Defines the [PdfClipPath] struct, exposing functionality related to a clip path.
2
3use crate::bindgen::FPDF_CLIPPATH;
4use crate::bindings::PdfiumLibraryBindings;
5use crate::error::{PdfiumError, PdfiumInternalError};
6use crate::pdf::document::page::object::ownership::PdfPageObjectOwnership;
7use crate::pdf::path::segment::PdfPathSegment;
8use crate::pdf::path::segments::{PdfPathSegmentIndex, PdfPathSegments, PdfPathSegmentsIterator};
9use std::convert::TryInto;
10use std::ops::{Range, RangeInclusive};
11use std::os::raw::c_int;
12
13/// The zero-based index of a single [PdfClipPathSegments] path object inside its
14/// containing [PdfClipPath] instance.
15pub type PdfClipPathSegmentIndex = u16;
16
17/// A single clip path, containing zero or more path objects.
18pub struct PdfClipPath<'a> {
19    handle: FPDF_CLIPPATH,
20    ownership: PdfPageObjectOwnership,
21    bindings: &'a dyn PdfiumLibraryBindings,
22}
23
24impl<'a> PdfClipPath<'a> {
25    #[inline]
26    pub(crate) fn from_pdfium(
27        handle: FPDF_CLIPPATH,
28        ownership: PdfPageObjectOwnership,
29        bindings: &'a dyn PdfiumLibraryBindings,
30    ) -> Self {
31        Self {
32            handle,
33            ownership,
34            bindings,
35        }
36    }
37
38    /// Returns the internal `FPDF_CLIPPATH` handle for this [PdfPathSegment].
39    #[inline]
40    pub(crate) fn handle(&self) -> FPDF_CLIPPATH {
41        self.handle
42    }
43
44    /// Returns the [PdfiumLibraryBindings] used by this [PdfClipPath] instance.
45    #[inline]
46    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
47        self.bindings
48    }
49
50    /// Returns the number of path objects inside this [PdfClipPath] instance.
51    #[inline]
52    pub fn len(&self) -> PdfClipPathSegmentIndex {
53        self.bindings().FPDFClipPath_CountPaths(self.handle()) as PdfClipPathSegmentIndex
54    }
55
56    /// Returns `true` if this [PdfClipPath] instance is empty.
57    #[inline]
58    pub fn is_empty(&self) -> bool {
59        self.len() == 0
60    }
61
62    /// Returns a Range from `0..(number of path objects)` for this [PdfClipPath] instance.
63    #[inline]
64    pub fn as_range(&self) -> Range<PdfClipPathSegmentIndex> {
65        0..self.len()
66    }
67
68    /// Returns an inclusive Range from `0..=(number of path objects - 1)` for this [PdfClipPath] instance.
69    #[inline]
70    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfClipPathSegmentIndex> {
71        if self.is_empty() { 0..=0 } else { 0..=(self.len() - 1) }
72    }
73
74    /// Returns a single [PdfClipPathSegments] path object from this [PdfClipPath] instance.
75    pub fn get(&self, index: PdfClipPathSegmentIndex) -> Result<PdfClipPathSegments<'a>, PdfiumError> {
76        if index >= self.len() {
77            return Err(PdfiumError::PdfClipPathSegmentIndexOutOfBounds);
78        }
79
80        Ok(PdfClipPathSegments::from_pdfium(self.handle(), index, self.bindings()))
81    }
82
83    /// Returns an iterator over all the path objects in this [PdfClipPath] instance.
84    #[inline]
85    pub fn iter(&self) -> PdfClipPathIterator<'_> {
86        PdfClipPathIterator::new(self)
87    }
88}
89
90impl<'a> Drop for PdfClipPath<'a> {
91    /// Closes this [PdfClipPath], releasing held memory.
92    #[inline]
93    fn drop(&mut self) {
94        if !self.ownership.is_owned() {
95            self.bindings.FPDF_DestroyClipPath(self.handle)
96        }
97    }
98}
99
100/// An iterator over all the [PdfPathSegments] path objects in a [PdfClipPath] instance.
101pub struct PdfClipPathIterator<'a> {
102    clip_path: &'a PdfClipPath<'a>,
103    next_index: PdfClipPathSegmentIndex,
104}
105
106impl<'a> PdfClipPathIterator<'a> {
107    #[inline]
108    pub(crate) fn new(clip_path: &'a PdfClipPath<'a>) -> Self {
109        PdfClipPathIterator {
110            clip_path,
111            next_index: 0,
112        }
113    }
114}
115
116impl<'a> Iterator for PdfClipPathIterator<'a> {
117    type Item = PdfClipPathSegments<'a>;
118
119    fn next(&mut self) -> Option<Self::Item> {
120        let next = self.clip_path.get(self.next_index);
121
122        self.next_index += 1;
123
124        next.ok()
125    }
126}
127
128/// The collection of [PdfPathSegment] objects inside a single path within a clip path.
129pub struct PdfClipPathSegments<'a> {
130    handle: FPDF_CLIPPATH,
131    index: PdfClipPathSegmentIndex,
132    bindings: &'a dyn PdfiumLibraryBindings,
133}
134
135impl<'a> PdfClipPathSegments<'a> {
136    #[inline]
137    pub(crate) fn from_pdfium(
138        handle: FPDF_CLIPPATH,
139        path_index: PdfClipPathSegmentIndex,
140        bindings: &'a dyn PdfiumLibraryBindings,
141    ) -> Self {
142        Self {
143            handle,
144            index: path_index,
145            bindings,
146        }
147    }
148}
149
150impl<'a> PdfPathSegments<'a> for PdfClipPathSegments<'a> {
151    #[inline]
152    fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
153        self.bindings
154    }
155
156    #[inline]
157    fn len(&self) -> PdfPathSegmentIndex {
158        self.bindings()
159            .FPDFClipPath_CountPathSegments(self.handle, self.index as i32)
160            .try_into()
161            .unwrap_or(0)
162    }
163
164    fn get(&self, index: PdfPathSegmentIndex) -> Result<PdfPathSegment<'a>, PdfiumError> {
165        let handle = self
166            .bindings()
167            .FPDFClipPath_GetPathSegment(self.handle, self.index as i32, index as c_int);
168
169        if handle.is_null() {
170            Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
171        } else {
172            Ok(PdfPathSegment::from_pdfium(handle, None, self.bindings()))
173        }
174    }
175
176    #[inline]
177    fn iter(&'a self) -> PdfPathSegmentsIterator<'a> {
178        PdfPathSegmentsIterator::new(self)
179    }
180}