use crate::bindgen::FPDF_CLIPPATH;
use crate::error::{PdfiumError, PdfiumInternalError};
use crate::pdf::document::page::object::ownership::PdfPageObjectOwnership;
use crate::pdf::path::segment::PdfPathSegment;
use crate::pdf::path::segments::{PdfPathSegmentIndex, PdfPathSegments, PdfPathSegmentsIterator};
use crate::pdfium::PdfiumLibraryBindingsAccessor;
use std::convert::TryInto;
use std::marker::PhantomData;
use std::ops::{Range, RangeInclusive};
use std::os::raw::c_int;
pub type PdfClipPathSegmentIndex = u16;
pub struct PdfClipPath<'a> {
handle: FPDF_CLIPPATH,
ownership: PdfPageObjectOwnership,
lifetime: PhantomData<&'a FPDF_CLIPPATH>,
}
impl<'a> PdfClipPath<'a> {
#[inline]
pub(crate) fn from_pdfium(handle: FPDF_CLIPPATH, ownership: PdfPageObjectOwnership) -> Self {
Self {
handle,
ownership,
lifetime: PhantomData,
}
}
#[inline]
pub(crate) fn handle(&self) -> FPDF_CLIPPATH {
self.handle
}
#[inline]
pub fn len(&self) -> PdfClipPathSegmentIndex {
let path_count = unsafe { self.bindings().FPDFClipPath_CountPaths(self.handle()) };
if path_count < 0 {
return 0;
}
path_count as PdfClipPathSegmentIndex
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn as_range(&self) -> Range<PdfClipPathSegmentIndex> {
0..self.len()
}
#[inline]
pub fn as_range_inclusive(&self) -> RangeInclusive<PdfClipPathSegmentIndex> {
if self.is_empty() {
0..=0
} else {
0..=(self.len() - 1)
}
}
pub fn get(
&self,
index: PdfClipPathSegmentIndex,
) -> Result<PdfClipPathSegments<'a>, PdfiumError> {
if index >= self.len() {
return Err(PdfiumError::PdfClipPathSegmentIndexOutOfBounds);
}
Ok(PdfClipPathSegments::from_pdfium(self.handle(), index))
}
#[inline]
pub fn iter(&self) -> PdfClipPathIterator<'_> {
PdfClipPathIterator::new(self)
}
}
impl<'a> Drop for PdfClipPath<'a> {
#[inline]
fn drop(&mut self) {
if !self.ownership.is_owned() {
unsafe {
self.bindings().FPDF_DestroyClipPath(self.handle);
}
}
}
}
impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfClipPath<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Send for PdfClipPath<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Sync for PdfClipPath<'a> {}
pub struct PdfClipPathIterator<'a> {
clip_path: &'a PdfClipPath<'a>,
next_index: PdfClipPathSegmentIndex,
}
impl<'a> PdfClipPathIterator<'a> {
#[inline]
pub(crate) fn new(clip_path: &'a PdfClipPath<'a>) -> Self {
PdfClipPathIterator {
clip_path,
next_index: 0,
}
}
}
impl<'a> Iterator for PdfClipPathIterator<'a> {
type Item = PdfClipPathSegments<'a>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.clip_path.get(self.next_index);
self.next_index += 1;
next.ok()
}
}
pub struct PdfClipPathSegments<'a> {
handle: FPDF_CLIPPATH,
index: PdfClipPathSegmentIndex,
lifetime: PhantomData<&'a FPDF_CLIPPATH>,
}
impl<'a> PdfClipPathSegments<'a> {
#[inline]
pub(crate) fn from_pdfium(handle: FPDF_CLIPPATH, path_index: PdfClipPathSegmentIndex) -> Self {
Self {
handle,
index: path_index,
lifetime: PhantomData,
}
}
}
impl<'a> PdfPathSegments<'a> for PdfClipPathSegments<'a> {
#[inline]
fn len(&self) -> PdfPathSegmentIndex {
unsafe {
self.bindings()
.FPDFClipPath_CountPathSegments(self.handle, self.index as i32)
}
.try_into()
.unwrap_or(0)
}
fn get(&self, index: PdfPathSegmentIndex) -> Result<PdfPathSegment<'a>, PdfiumError> {
let handle = unsafe {
self.bindings().FPDFClipPath_GetPathSegment(
self.handle,
self.index as i32,
index as c_int,
)
};
if handle.is_null() {
Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
))
} else {
Ok(PdfPathSegment::from_pdfium(handle, None))
}
}
#[inline]
fn iter(&'a self) -> PdfPathSegmentsIterator<'a> {
PdfPathSegmentsIterator::new(self)
}
}
impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfClipPathSegments<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Send for PdfClipPathSegments<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Sync for PdfClipPathSegments<'a> {}