1use crate::bindgen::{
5 FPDF_BOOL, FPDF_DOCUMENT, FPDF_FILLMODE_ALTERNATE, FPDF_FILLMODE_NONE, FPDF_FILLMODE_WINDING, FPDF_PAGEOBJECT,
6};
7use crate::bindings::PdfiumLibraryBindings;
8use crate::error::{PdfiumError, PdfiumInternalError};
9use crate::pdf::color::PdfColor;
10use crate::pdf::document::PdfDocument;
11use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
12use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectCommon, PdfPageObjectOwnership};
13use crate::pdf::matrix::{PdfMatrix, PdfMatrixValue};
14use crate::pdf::path::segment::{PdfPathSegment, PdfPathSegmentType};
15use crate::pdf::path::segments::{PdfPathSegmentIndex, PdfPathSegments, PdfPathSegmentsIterator};
16use crate::pdf::points::PdfPoints;
17use crate::pdf::rect::PdfRect;
18use crate::{create_transform_getters, create_transform_setters};
19use std::convert::TryInto;
20use std::os::raw::{c_int, c_uint};
21
22#[cfg(doc)]
23use {
24 crate::pdf::document::page::PdfPage, crate::pdf::document::page::object::PdfPageObjectType,
25 crate::pdf::document::page::objects::common::PdfPageObjectsCommon,
26};
27
28#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum PdfPathFillMode {
35 None = FPDF_FILLMODE_NONE as isize,
37
38 EvenOdd = FPDF_FILLMODE_ALTERNATE as isize,
49
50 Winding = FPDF_FILLMODE_WINDING as isize,
67}
68
69impl PdfPathFillMode {
70 #[inline]
71 pub(crate) fn from_pdfium(value: c_int) -> Result<PdfPathFillMode, PdfiumError> {
72 match value as u32 {
73 FPDF_FILLMODE_NONE => Ok(PdfPathFillMode::None),
74 FPDF_FILLMODE_ALTERNATE => Ok(PdfPathFillMode::EvenOdd),
75 FPDF_FILLMODE_WINDING => Ok(PdfPathFillMode::Winding),
76 _ => Err(PdfiumError::UnknownPdfPagePathFillMode),
77 }
78 }
79
80 #[inline]
81 #[allow(dead_code)]
82 pub(crate) fn as_pdfium(&self) -> c_uint {
83 match self {
84 PdfPathFillMode::None => FPDF_FILLMODE_NONE,
85 PdfPathFillMode::EvenOdd => FPDF_FILLMODE_ALTERNATE,
86 PdfPathFillMode::Winding => FPDF_FILLMODE_WINDING,
87 }
88 }
89}
90
91impl Default for PdfPathFillMode {
92 #[inline]
96 fn default() -> Self {
97 PdfPathFillMode::Winding
98 }
99}
100
101pub(crate) struct PathStroke {
106 pub(crate) color: PdfColor,
107 pub(crate) width: PdfPoints,
108}
109
110pub(crate) struct PathFillStroke {
113 pub(crate) stroke_color: Option<PdfColor>,
114 pub(crate) stroke_width: Option<PdfPoints>,
115 pub(crate) fill_color: Option<PdfColor>,
116}
117
118pub(crate) struct BezierPoints {
121 pub(crate) start: (PdfPoints, PdfPoints),
122 pub(crate) end: (PdfPoints, PdfPoints),
123 pub(crate) control1: (PdfPoints, PdfPoints),
124 pub(crate) control2: (PdfPoints, PdfPoints),
125}
126
127pub struct PdfPagePathObject<'a> {
175 object_handle: FPDF_PAGEOBJECT,
176 ownership: PdfPageObjectOwnership,
177 bindings: &'a dyn PdfiumLibraryBindings,
178 current_point_x: PdfPoints,
179 current_point_y: PdfPoints,
180}
181
182impl<'a> PdfPagePathObject<'a> {
183 #[inline]
184 pub(crate) fn from_pdfium(
185 object_handle: FPDF_PAGEOBJECT,
186 ownership: PdfPageObjectOwnership,
187 bindings: &'a dyn PdfiumLibraryBindings,
188 ) -> Self {
189 PdfPagePathObject {
190 object_handle,
191 ownership,
192 bindings,
193 current_point_x: PdfPoints::ZERO,
194 current_point_y: PdfPoints::ZERO,
195 }
196 }
197
198 #[inline]
215 pub fn new(
216 document: &PdfDocument<'a>,
217 x: PdfPoints,
218 y: PdfPoints,
219 stroke_color: Option<PdfColor>,
220 stroke_width: Option<PdfPoints>,
221 fill_color: Option<PdfColor>,
222 ) -> Result<Self, PdfiumError> {
223 Self::new_from_bindings(document.bindings(), x, y, stroke_color, stroke_width, fill_color)
224 }
225
226 pub(crate) fn new_from_bindings(
227 bindings: &'a dyn PdfiumLibraryBindings,
228 x: PdfPoints,
229 y: PdfPoints,
230 stroke_color: Option<PdfColor>,
231 stroke_width: Option<PdfPoints>,
232 fill_color: Option<PdfColor>,
233 ) -> Result<Self, PdfiumError> {
234 let handle = bindings.FPDFPageObj_CreateNewPath(x.value, y.value);
235
236 if handle.is_null() {
237 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
238 } else {
239 let mut result = PdfPagePathObject {
240 object_handle: handle,
241 ownership: PdfPageObjectOwnership::unowned(),
242 bindings,
243 current_point_x: x,
244 current_point_y: y,
245 };
246
247 result.move_to(x, y)?;
248
249 let do_stroke = if let Some(stroke_color) = stroke_color {
250 if let Some(stroke_width) = stroke_width {
251 result.set_stroke_color(stroke_color)?;
252 result.set_stroke_width(stroke_width)?;
253
254 true
255 } else {
256 false
257 }
258 } else {
259 false
260 };
261
262 let fill_mode = if let Some(fill_color) = fill_color {
263 result.set_fill_color(fill_color)?;
264
265 PdfPathFillMode::default()
266 } else {
267 PdfPathFillMode::None
268 };
269
270 result.set_fill_and_stroke_mode(fill_mode, do_stroke)?;
271
272 Ok(result)
273 }
274 }
275
276 #[inline]
277 pub(crate) fn new_line_from_bindings(
278 bindings: &'a dyn PdfiumLibraryBindings,
279 x1: PdfPoints,
280 y1: PdfPoints,
281 x2: PdfPoints,
282 y2: PdfPoints,
283 stroke: PathStroke,
284 ) -> Result<Self, PdfiumError> {
285 let mut result = Self::new_from_bindings(bindings, x1, y1, Some(stroke.color), Some(stroke.width), None)?;
286
287 result.line_to(x2, y2)?;
288
289 Ok(result)
290 }
291
292 #[inline]
299 pub fn new_line(
300 document: &PdfDocument<'a>,
301 x1: PdfPoints,
302 y1: PdfPoints,
303 x2: PdfPoints,
304 y2: PdfPoints,
305 stroke_color: PdfColor,
306 stroke_width: PdfPoints,
307 ) -> Result<Self, PdfiumError> {
308 Self::new_line_from_bindings(
309 document.bindings(),
310 x1,
311 y1,
312 x2,
313 y2,
314 PathStroke {
315 color: stroke_color,
316 width: stroke_width,
317 },
318 )
319 }
320
321 #[inline]
322 pub(crate) fn new_bezier_from_bindings(
323 bindings: &'a dyn PdfiumLibraryBindings,
324 points: BezierPoints,
325 stroke: PathStroke,
326 ) -> Result<Self, PdfiumError> {
327 let (x1, y1) = points.start;
328 let (x2, y2) = points.end;
329 let (control1_x, control1_y) = points.control1;
330 let (control2_x, control2_y) = points.control2;
331
332 let mut result = Self::new_from_bindings(bindings, x1, y1, Some(stroke.color), Some(stroke.width), None)?;
333
334 result.bezier_to(x2, y2, control1_x, control1_y, control2_x, control2_y)?;
335
336 Ok(result)
337 }
338
339 #[allow(clippy::too_many_arguments)]
346 #[inline]
347 pub fn new_bezier(
348 document: &PdfDocument<'a>,
349 x1: PdfPoints,
350 y1: PdfPoints,
351 x2: PdfPoints,
352 y2: PdfPoints,
353 control1_x: PdfPoints,
354 control1_y: PdfPoints,
355 control2_x: PdfPoints,
356 control2_y: PdfPoints,
357 stroke_color: PdfColor,
358 stroke_width: PdfPoints,
359 ) -> Result<Self, PdfiumError> {
360 Self::new_bezier_from_bindings(
361 document.bindings(),
362 BezierPoints {
363 start: (x1, y1),
364 end: (x2, y2),
365 control1: (control1_x, control1_y),
366 control2: (control2_x, control2_y),
367 },
368 PathStroke {
369 color: stroke_color,
370 width: stroke_width,
371 },
372 )
373 }
374
375 #[inline]
376 pub(crate) fn new_rect_from_bindings(
377 bindings: &'a dyn PdfiumLibraryBindings,
378 rect: PdfRect,
379 stroke_color: Option<PdfColor>,
380 stroke_width: Option<PdfPoints>,
381 fill_color: Option<PdfColor>,
382 ) -> Result<Self, PdfiumError> {
383 let mut result = Self::new_from_bindings(
384 bindings,
385 rect.left(),
386 rect.bottom(),
387 stroke_color,
388 stroke_width,
389 fill_color,
390 )?;
391
392 result.rect_to(rect.right(), rect.top())?;
393
394 Ok(result)
395 }
396
397 #[inline]
405 pub fn new_rect(
406 document: &PdfDocument<'a>,
407 rect: PdfRect,
408 stroke_color: Option<PdfColor>,
409 stroke_width: Option<PdfPoints>,
410 fill_color: Option<PdfColor>,
411 ) -> Result<Self, PdfiumError> {
412 Self::new_rect_from_bindings(document.bindings(), rect, stroke_color, stroke_width, fill_color)
413 }
414
415 #[inline]
416 pub(crate) fn new_circle_from_bindings(
417 bindings: &'a dyn PdfiumLibraryBindings,
418 rect: PdfRect,
419 stroke_color: Option<PdfColor>,
420 stroke_width: Option<PdfPoints>,
421 fill_color: Option<PdfColor>,
422 ) -> Result<Self, PdfiumError> {
423 let mut result = Self::new_from_bindings(
424 bindings,
425 rect.left(),
426 rect.bottom(),
427 stroke_color,
428 stroke_width,
429 fill_color,
430 )?;
431
432 result.circle_to(rect.right(), rect.top())?;
433
434 Ok(result)
435 }
436
437 #[inline]
445 pub fn new_circle(
446 document: &PdfDocument<'a>,
447 rect: PdfRect,
448 stroke_color: Option<PdfColor>,
449 stroke_width: Option<PdfPoints>,
450 fill_color: Option<PdfColor>,
451 ) -> Result<Self, PdfiumError> {
452 Self::new_circle_from_bindings(document.bindings(), rect, stroke_color, stroke_width, fill_color)
453 }
454
455 #[inline]
456 pub(crate) fn new_circle_at_from_bindings(
457 bindings: &'a dyn PdfiumLibraryBindings,
458 center_x: PdfPoints,
459 center_y: PdfPoints,
460 radius: PdfPoints,
461 style: PathFillStroke,
462 ) -> Result<Self, PdfiumError> {
463 Self::new_circle_from_bindings(
464 bindings,
465 PdfRect::new(
466 center_y - radius,
467 center_x - radius,
468 center_y + radius,
469 center_x + radius,
470 ),
471 style.stroke_color,
472 style.stroke_width,
473 style.fill_color,
474 )
475 }
476
477 #[inline]
485 pub fn new_circle_at(
486 document: &PdfDocument<'a>,
487 center_x: PdfPoints,
488 center_y: PdfPoints,
489 radius: PdfPoints,
490 stroke_color: Option<PdfColor>,
491 stroke_width: Option<PdfPoints>,
492 fill_color: Option<PdfColor>,
493 ) -> Result<Self, PdfiumError> {
494 Self::new_circle_at_from_bindings(
495 document.bindings(),
496 center_x,
497 center_y,
498 radius,
499 PathFillStroke {
500 stroke_color,
501 stroke_width,
502 fill_color,
503 },
504 )
505 }
506
507 #[inline]
508 pub(crate) fn new_ellipse_from_bindings(
509 bindings: &'a dyn PdfiumLibraryBindings,
510 rect: PdfRect,
511 stroke_color: Option<PdfColor>,
512 stroke_width: Option<PdfPoints>,
513 fill_color: Option<PdfColor>,
514 ) -> Result<Self, PdfiumError> {
515 let mut result = Self::new_from_bindings(
516 bindings,
517 rect.left(),
518 rect.bottom(),
519 stroke_color,
520 stroke_width,
521 fill_color,
522 )?;
523
524 result.ellipse_to(rect.right(), rect.top())?;
525
526 Ok(result)
527 }
528
529 #[inline]
537 pub fn new_ellipse(
538 document: &PdfDocument<'a>,
539 rect: PdfRect,
540 stroke_color: Option<PdfColor>,
541 stroke_width: Option<PdfPoints>,
542 fill_color: Option<PdfColor>,
543 ) -> Result<Self, PdfiumError> {
544 Self::new_ellipse_from_bindings(document.bindings(), rect, stroke_color, stroke_width, fill_color)
545 }
546
547 #[inline]
548 pub(crate) fn new_ellipse_at_from_bindings(
549 bindings: &'a dyn PdfiumLibraryBindings,
550 center_x: PdfPoints,
551 center_y: PdfPoints,
552 x_radius: PdfPoints,
553 y_radius: PdfPoints,
554 style: PathFillStroke,
555 ) -> Result<Self, PdfiumError> {
556 Self::new_ellipse_from_bindings(
557 bindings,
558 PdfRect::new(
559 center_y - y_radius,
560 center_x - x_radius,
561 center_y + y_radius,
562 center_x + x_radius,
563 ),
564 style.stroke_color,
565 style.stroke_width,
566 style.fill_color,
567 )
568 }
569
570 #[allow(clippy::too_many_arguments)]
578 #[inline]
579 pub fn new_ellipse_at(
580 document: &PdfDocument<'a>,
581 center_x: PdfPoints,
582 center_y: PdfPoints,
583 x_radius: PdfPoints,
584 y_radius: PdfPoints,
585 stroke_color: Option<PdfColor>,
586 stroke_width: Option<PdfPoints>,
587 fill_color: Option<PdfColor>,
588 ) -> Result<Self, PdfiumError> {
589 Self::new_ellipse_at_from_bindings(
590 document.bindings(),
591 center_x,
592 center_y,
593 x_radius,
594 y_radius,
595 PathFillStroke {
596 stroke_color,
597 stroke_width,
598 fill_color,
599 },
600 )
601 }
602
603 pub fn move_to(&mut self, x: PdfPoints, y: PdfPoints) -> Result<(), PdfiumError> {
606 if self
607 .bindings()
608 .is_true(self.bindings().FPDFPath_MoveTo(self.object_handle(), x.value, y.value))
609 {
610 self.current_point_x = x;
611 self.current_point_y = y;
612
613 Ok(())
614 } else {
615 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
616 }
617 }
618
619 pub fn line_to(&mut self, x: PdfPoints, y: PdfPoints) -> Result<(), PdfiumError> {
622 if self
623 .bindings()
624 .is_true(self.bindings().FPDFPath_LineTo(self.object_handle(), x.value, y.value))
625 {
626 self.current_point_x = x;
627 self.current_point_y = y;
628
629 Ok(())
630 } else {
631 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
632 }
633 }
634
635 pub fn bezier_to(
639 &mut self,
640 x: PdfPoints,
641 y: PdfPoints,
642 control1_x: PdfPoints,
643 control1_y: PdfPoints,
644 control2_x: PdfPoints,
645 control2_y: PdfPoints,
646 ) -> Result<(), PdfiumError> {
647 if self.bindings().is_true(self.bindings().FPDFPath_BezierTo(
648 self.object_handle(),
649 control1_x.value,
650 control1_y.value,
651 control2_x.value,
652 control2_y.value,
653 x.value,
654 y.value,
655 )) {
656 self.current_point_x = x;
657 self.current_point_y = y;
658
659 Ok(())
660 } else {
661 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
662 }
663 }
664
665 pub fn rect_to(&mut self, x: PdfPoints, y: PdfPoints) -> Result<(), PdfiumError> {
669 let orig_x = self.current_point_x;
670
671 let orig_y = self.current_point_y;
672
673 self.close_path()?;
674 self.line_to(orig_x, y)?;
675 self.line_to(x, y)?;
676 self.line_to(x, orig_y)?;
677 self.close_path()?;
678 self.move_to(x, y)
679 }
680
681 pub fn ellipse_to(&mut self, x: PdfPoints, y: PdfPoints) -> Result<(), PdfiumError> {
685 let x_radius = (x - self.current_point_x) / 2.0;
686
687 let y_radius = (y - self.current_point_y) / 2.0;
688
689 self.close_path()?;
690 self.move_to(self.current_point_x + x_radius, self.current_point_y + y_radius)?;
691 self.ellipse(x_radius, y_radius)?;
692 self.move_to(x, y)
693 }
694
695 pub fn circle_to(&mut self, x: PdfPoints, y: PdfPoints) -> Result<(), PdfiumError> {
703 let radius = (x - self.current_point_x) / 2.0;
704
705 self.move_to(self.current_point_x + radius, self.current_point_y + radius)?;
706 self.ellipse(radius, radius)?;
707 self.move_to(x, y)
708 }
709
710 fn ellipse(&mut self, x_radius: PdfPoints, y_radius: PdfPoints) -> Result<(), PdfiumError> {
713 const C: f32 = 0.551915;
714
715 let x_c = x_radius * C;
716
717 let y_c = y_radius * C;
718
719 let orig_x = self.current_point_x;
720
721 let orig_y = self.current_point_y;
722
723 self.move_to(orig_x - x_radius, orig_y)?;
724 self.bezier_to(
725 orig_x,
726 orig_y + y_radius,
727 orig_x - x_radius,
728 orig_y + y_c,
729 orig_x - x_c,
730 orig_y + y_radius,
731 )?;
732 self.bezier_to(
733 orig_x + x_radius,
734 orig_y,
735 orig_x + x_c,
736 orig_y + y_radius,
737 orig_x + x_radius,
738 orig_y + y_c,
739 )?;
740 self.bezier_to(
741 orig_x,
742 orig_y - y_radius,
743 orig_x + x_radius,
744 orig_y - y_c,
745 orig_x + x_c,
746 orig_y - y_radius,
747 )?;
748 self.bezier_to(
749 orig_x - x_radius,
750 orig_y,
751 orig_x - x_c,
752 orig_y - y_radius,
753 orig_x - x_radius,
754 orig_y - y_c,
755 )?;
756 self.close_path()
757 }
758
759 pub fn close_path(&mut self) -> Result<(), PdfiumError> {
762 if self
763 .bindings
764 .is_true(self.bindings().FPDFPath_Close(self.object_handle))
765 {
766 Ok(())
767 } else {
768 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
769 }
770 }
771
772 pub fn fill_mode(&self) -> Result<PdfPathFillMode, PdfiumError> {
775 let mut raw_fill_mode: c_int = 0;
776
777 let mut _raw_stroke: FPDF_BOOL = self.bindings().FALSE();
778
779 if self.bindings().is_true(self.bindings.FPDFPath_GetDrawMode(
780 self.object_handle(),
781 &mut raw_fill_mode,
782 &mut _raw_stroke,
783 )) {
784 PdfPathFillMode::from_pdfium(raw_fill_mode)
785 } else {
786 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
787 }
788 }
789
790 pub fn is_stroked(&self) -> Result<bool, PdfiumError> {
796 let mut _raw_fill_mode: c_int = 0;
797
798 let mut raw_stroke: FPDF_BOOL = self.bindings().FALSE();
799
800 if self.bindings().is_true(self.bindings().FPDFPath_GetDrawMode(
801 self.object_handle(),
802 &mut _raw_fill_mode,
803 &mut raw_stroke,
804 )) {
805 Ok(self.bindings().is_true(raw_stroke))
806 } else {
807 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
808 }
809 }
810
811 pub fn set_fill_and_stroke_mode(&mut self, fill_mode: PdfPathFillMode, do_stroke: bool) -> Result<(), PdfiumError> {
817 if self.bindings().is_true(self.bindings().FPDFPath_SetDrawMode(
818 self.object_handle(),
819 fill_mode.as_pdfium() as c_int,
820 self.bindings.bool_to_pdfium(do_stroke),
821 )) {
822 Ok(())
823 } else {
824 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
825 }
826 }
827
828 #[inline]
830 pub fn segments(&self) -> PdfPagePathObjectSegments<'_> {
831 PdfPagePathObjectSegments::from_pdfium(self.object_handle(), self.bindings())
832 }
833
834 create_transform_setters!(
835 &mut Self,
836 Result<(), PdfiumError>,
837 "this [PdfPagePathObject]",
838 "this [PdfPagePathObject].",
839 "this [PdfPagePathObject],"
840 );
841
842 create_transform_getters!(
843 "this [PdfPagePathObject]",
844 "this [PdfPagePathObject].",
845 "this [PdfPagePathObject],"
846 );
847}
848
849impl<'a> PdfPageObjectPrivate<'a> for PdfPagePathObject<'a> {
850 #[inline]
851 fn object_handle(&self) -> FPDF_PAGEOBJECT {
852 self.object_handle
853 }
854
855 #[inline]
856 fn ownership(&self) -> &PdfPageObjectOwnership {
857 &self.ownership
858 }
859
860 #[inline]
861 fn set_ownership(&mut self, ownership: PdfPageObjectOwnership) {
862 self.ownership = ownership;
863 }
864
865 #[inline]
866 fn bindings(&self) -> &dyn PdfiumLibraryBindings {
867 self.bindings
868 }
869
870 #[inline]
871 fn is_copyable_impl(&self) -> bool {
872 !self
873 .segments()
874 .iter()
875 .any(|segment| segment.segment_type() == PdfPathSegmentType::BezierTo)
876 }
877
878 fn try_copy_impl<'b>(
879 &self,
880 _: FPDF_DOCUMENT,
881 bindings: &'b dyn PdfiumLibraryBindings,
882 ) -> Result<PdfPageObject<'b>, PdfiumError> {
883 let mut copy =
884 PdfPagePathObject::new_from_bindings(bindings, PdfPoints::ZERO, PdfPoints::ZERO, None, None, None)?;
885
886 copy.set_fill_and_stroke_mode(self.fill_mode()?, self.is_stroked()?)?;
887 copy.set_fill_color(self.fill_color()?)?;
888 copy.set_stroke_color(self.stroke_color()?)?;
889 copy.set_stroke_width(self.stroke_width()?)?;
890 copy.set_line_join(self.line_join()?)?;
891 copy.set_line_cap(self.line_cap()?)?;
892
893 for segment in self.segments().iter() {
894 if segment.segment_type() == PdfPathSegmentType::Unknown {
895 return Err(PdfiumError::PathObjectUnknownSegmentTypeNotCopyable);
896 } else if segment.segment_type() == PdfPathSegmentType::BezierTo {
897 return Err(PdfiumError::PathObjectBezierControlPointsNotCopyable);
898 } else {
899 match segment.segment_type() {
900 PdfPathSegmentType::Unknown | PdfPathSegmentType::BezierTo => {}
901 PdfPathSegmentType::LineTo => copy.line_to(segment.x(), segment.y())?,
902 PdfPathSegmentType::MoveTo => copy.move_to(segment.x(), segment.y())?,
903 }
904
905 if segment.is_close() {
906 copy.close_path()?;
907 }
908 }
909 }
910
911 copy.reset_matrix(self.matrix()?)?;
912
913 Ok(PdfPageObject::Path(copy))
914 }
915}
916
917pub struct PdfPagePathObjectSegments<'a> {
924 handle: FPDF_PAGEOBJECT,
925 matrix: Option<PdfMatrix>,
926 bindings: &'a dyn PdfiumLibraryBindings,
927}
928
929impl<'a> PdfPagePathObjectSegments<'a> {
930 #[inline]
931 pub(crate) fn from_pdfium(handle: FPDF_PAGEOBJECT, bindings: &'a dyn PdfiumLibraryBindings) -> Self {
932 Self {
933 handle,
934 matrix: None,
935 bindings,
936 }
937 }
938
939 #[inline]
942 pub fn transform(&self, matrix: PdfMatrix) -> PdfPagePathObjectSegments<'a> {
943 Self {
944 handle: self.handle,
945 matrix: Some(matrix),
946 bindings: self.bindings,
947 }
948 }
949
950 #[inline]
953 pub fn raw(&self) -> PdfPagePathObjectSegments<'a> {
954 Self {
955 handle: self.handle,
956 matrix: None,
957 bindings: self.bindings,
958 }
959 }
960}
961
962impl<'a> PdfPathSegments<'a> for PdfPagePathObjectSegments<'a> {
963 #[inline]
964 fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
965 self.bindings
966 }
967
968 #[inline]
969 fn len(&self) -> PdfPathSegmentIndex {
970 self.bindings()
971 .FPDFPath_CountSegments(self.handle)
972 .try_into()
973 .unwrap_or(0)
974 }
975
976 fn get(&self, index: PdfPathSegmentIndex) -> Result<PdfPathSegment<'a>, PdfiumError> {
977 let handle = self.bindings().FPDFPath_GetPathSegment(self.handle, index as c_int);
978
979 if handle.is_null() {
980 Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
981 } else {
982 Ok(PdfPathSegment::from_pdfium(handle, self.matrix, self.bindings()))
983 }
984 }
985
986 #[inline]
987 fn iter(&'a self) -> PdfPathSegmentsIterator<'a> {
988 PdfPathSegmentsIterator::new(self)
989 }
990}
991
992impl<'a> Drop for PdfPagePathObject<'a> {
993 fn drop(&mut self) {
995 self.drop_impl();
996 }
997}