pdfium_render/pdf/path/
clip_path.rs1use crate::bindgen::FPDF_CLIPPATH;
4use crate::error::{PdfiumError, PdfiumInternalError};
5use crate::pdf::document::page::object::ownership::PdfPageObjectOwnership;
6use crate::pdf::path::segment::PdfPathSegment;
7use crate::pdf::path::segments::{PdfPathSegmentIndex, PdfPathSegments, PdfPathSegmentsIterator};
8use crate::pdfium::PdfiumLibraryBindingsAccessor;
9use std::convert::TryInto;
10use std::marker::PhantomData;
11use std::ops::{Range, RangeInclusive};
12use std::os::raw::c_int;
13
14pub type PdfClipPathSegmentIndex = u16;
17
18pub struct PdfClipPath<'a> {
20 handle: FPDF_CLIPPATH,
21 ownership: PdfPageObjectOwnership,
22 lifetime: PhantomData<&'a FPDF_CLIPPATH>,
23}
24
25impl<'a> PdfClipPath<'a> {
26 #[inline]
27 pub(crate) fn from_pdfium(handle: FPDF_CLIPPATH, ownership: PdfPageObjectOwnership) -> Self {
28 Self {
29 handle,
30 ownership,
31 lifetime: PhantomData,
32 }
33 }
34
35 #[inline]
37 pub(crate) fn handle(&self) -> FPDF_CLIPPATH {
38 self.handle
39 }
40
41 #[inline]
43 pub fn len(&self) -> PdfClipPathSegmentIndex {
44 let path_count = unsafe { self.bindings().FPDFClipPath_CountPaths(self.handle()) };
45
46 if path_count < 0 {
47 return 0;
50 }
51
52 path_count as PdfClipPathSegmentIndex
53 }
54
55 #[inline]
57 pub fn is_empty(&self) -> bool {
58 self.len() == 0
59 }
60
61 #[inline]
63 pub fn as_range(&self) -> Range<PdfClipPathSegmentIndex> {
64 0..self.len()
65 }
66
67 #[inline]
69 pub fn as_range_inclusive(&self) -> RangeInclusive<PdfClipPathSegmentIndex> {
70 if self.is_empty() {
71 0..=0
72 } else {
73 0..=(self.len() - 1)
74 }
75 }
76
77 pub fn get(
79 &self,
80 index: PdfClipPathSegmentIndex,
81 ) -> Result<PdfClipPathSegments<'a>, PdfiumError> {
82 if index >= self.len() {
83 return Err(PdfiumError::PdfClipPathSegmentIndexOutOfBounds);
84 }
85
86 Ok(PdfClipPathSegments::from_pdfium(self.handle(), index))
87 }
88
89 #[inline]
91 pub fn iter(&self) -> PdfClipPathIterator<'_> {
92 PdfClipPathIterator::new(self)
93 }
94}
95
96impl<'a> Drop for PdfClipPath<'a> {
97 #[inline]
99 fn drop(&mut self) {
100 if !self.ownership.is_owned() {
101 unsafe {
105 self.bindings().FPDF_DestroyClipPath(self.handle);
106 }
107 }
108 }
109}
110
111impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfClipPath<'a> {}
112
113#[cfg(feature = "thread_safe")]
114unsafe impl<'a> Send for PdfClipPath<'a> {}
115
116#[cfg(feature = "thread_safe")]
117unsafe impl<'a> Sync for PdfClipPath<'a> {}
118
119pub struct PdfClipPathIterator<'a> {
121 clip_path: &'a PdfClipPath<'a>,
122 next_index: PdfClipPathSegmentIndex,
123}
124
125impl<'a> PdfClipPathIterator<'a> {
126 #[inline]
127 pub(crate) fn new(clip_path: &'a PdfClipPath<'a>) -> Self {
128 PdfClipPathIterator {
129 clip_path,
130 next_index: 0,
131 }
132 }
133}
134
135impl<'a> Iterator for PdfClipPathIterator<'a> {
136 type Item = PdfClipPathSegments<'a>;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 let next = self.clip_path.get(self.next_index);
140
141 self.next_index += 1;
142
143 next.ok()
144 }
145}
146
147pub struct PdfClipPathSegments<'a> {
149 handle: FPDF_CLIPPATH,
150 index: PdfClipPathSegmentIndex,
151 lifetime: PhantomData<&'a FPDF_CLIPPATH>,
152}
153
154impl<'a> PdfClipPathSegments<'a> {
155 #[inline]
156 pub(crate) fn from_pdfium(handle: FPDF_CLIPPATH, path_index: PdfClipPathSegmentIndex) -> Self {
157 Self {
158 handle,
159 index: path_index,
160 lifetime: PhantomData,
161 }
162 }
163}
164
165impl<'a> PdfPathSegments<'a> for PdfClipPathSegments<'a> {
166 #[inline]
167 fn len(&self) -> PdfPathSegmentIndex {
168 unsafe {
169 self.bindings()
170 .FPDFClipPath_CountPathSegments(self.handle, self.index as i32)
171 }
172 .try_into()
173 .unwrap_or(0)
174 }
175
176 fn get(&self, index: PdfPathSegmentIndex) -> Result<PdfPathSegment<'a>, PdfiumError> {
177 let handle = unsafe {
178 self.bindings().FPDFClipPath_GetPathSegment(
179 self.handle,
180 self.index as i32,
181 index as c_int,
182 )
183 };
184
185 if handle.is_null() {
186 Err(PdfiumError::PdfiumLibraryInternalError(
187 PdfiumInternalError::Unknown,
188 ))
189 } else {
190 Ok(PdfPathSegment::from_pdfium(handle, None))
191 }
192 }
193
194 #[inline]
195 fn iter(&'a self) -> PdfPathSegmentsIterator<'a> {
196 PdfPathSegmentsIterator::new(self)
197 }
198}
199
200impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfClipPathSegments<'a> {}
201
202#[cfg(feature = "thread_safe")]
203unsafe impl<'a> Send for PdfClipPathSegments<'a> {}
204
205#[cfg(feature = "thread_safe")]
206unsafe impl<'a> Sync for PdfClipPathSegments<'a> {}