1use std::ptr;
2
3use crate::document::PdfDocument;
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::page::PdfPage;
8use crate::types::{PdfRect, PdfTextRange};
9use crate::util::take_string;
10
11#[derive(Debug, Clone)]
12pub struct PdfSelection {
13 handle: ObjectHandle,
14}
15
16impl PdfSelection {
17 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
18 Self { handle }
19 }
20
21 pub fn new(document: &PdfDocument) -> Result<Self> {
22 let mut out_selection = ptr::null_mut();
23 let mut out_error = ptr::null_mut();
24 let status = unsafe {
25 ffi::pdf_selection_new(document.as_handle_ptr(), &mut out_selection, &mut out_error)
26 };
27 crate::util::status_result(status, out_error)?;
28 Ok(Self::from_handle(crate::util::required_handle(
29 out_selection,
30 "PDFSelection",
31 )?))
32 }
33
34 #[must_use]
35 pub fn string(&self) -> Option<String> {
36 take_string(unsafe { ffi::pdf_selection_string(self.handle.as_ptr()) })
37 }
38
39 #[must_use]
40 pub fn page_count(&self) -> usize {
41 unsafe { ffi::pdf_selection_page_count(self.handle.as_ptr()) as usize }
42 }
43
44 #[must_use]
45 pub fn page(&self, index: usize) -> Option<PdfPage> {
46 let ptr = unsafe { ffi::pdf_selection_page_at(self.handle.as_ptr(), index as u64) };
47 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfPage::from_handle)
48 }
49
50 #[must_use]
51 pub fn pages(&self) -> Vec<PdfPage> {
52 (0..self.page_count())
53 .filter_map(|index| self.page(index))
54 .collect()
55 }
56
57 #[must_use]
58 pub fn bounds_for_page(&self, page: &PdfPage) -> PdfRect {
59 let mut x = 0.0_f64;
60 let mut y = 0.0_f64;
61 let mut width = 0.0_f64;
62 let mut height = 0.0_f64;
63 unsafe {
64 ffi::pdf_selection_bounds_for_page(
65 self.handle.as_ptr(),
66 page.as_handle_ptr(),
67 &mut x,
68 &mut y,
69 &mut width,
70 &mut height,
71 );
72 }
73 PdfRect {
74 x,
75 y,
76 width,
77 height,
78 }
79 }
80
81 #[must_use]
82 pub fn number_of_text_ranges_on_page(&self, page: &PdfPage) -> usize {
83 unsafe {
84 ffi::pdf_selection_number_of_text_ranges_on_page(
85 self.handle.as_ptr(),
86 page.as_handle_ptr(),
87 ) as usize
88 }
89 }
90
91 #[must_use]
92 pub fn text_range(&self, index: usize, page: &PdfPage) -> Option<PdfTextRange> {
93 let mut location = 0_u64;
94 let mut length = 0_u64;
95 let ok = unsafe {
96 ffi::pdf_selection_range_at_index_on_page(
97 self.handle.as_ptr(),
98 index as u64,
99 page.as_handle_ptr(),
100 &mut location,
101 &mut length,
102 ) != 0
103 };
104 ok.then_some(PdfTextRange {
105 location: location as usize,
106 length: length as usize,
107 })
108 }
109
110 #[must_use]
111 pub fn selection_by_line_count(&self) -> usize {
112 unsafe { ffi::pdf_selection_selections_by_line_count(self.handle.as_ptr()) as usize }
113 }
114
115 #[must_use]
116 pub fn selection_by_line(&self, index: usize) -> Option<Self> {
117 let ptr = unsafe { ffi::pdf_selection_selection_by_line_at(self.handle.as_ptr(), index as u64) };
118 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle)
119 }
120
121 #[must_use]
122 pub fn selections_by_line(&self) -> Vec<Self> {
123 (0..self.selection_by_line_count())
124 .filter_map(|index| self.selection_by_line(index))
125 .collect()
126 }
127
128 pub fn add_selection(&self, other: &Self) -> Result<()> {
129 let mut out_error = ptr::null_mut();
130 let status = unsafe {
131 ffi::pdf_selection_add_selection(
132 self.handle.as_ptr(),
133 other.handle.as_ptr(),
134 &mut out_error,
135 )
136 };
137 crate::util::status_result(status, out_error)
138 }
139
140 pub fn extend_selection_at_end(&self, amount: isize) {
141 unsafe { ffi::pdf_selection_extend_at_end(self.handle.as_ptr(), amount as i64) };
142 }
143
144 pub fn extend_selection_at_start(&self, amount: isize) {
145 unsafe { ffi::pdf_selection_extend_at_start(self.handle.as_ptr(), amount as i64) };
146 }
147
148 pub fn extend_selection_for_line_boundaries(&self) {
149 unsafe { ffi::pdf_selection_extend_for_line_boundaries(self.handle.as_ptr()) };
150 }
151
152 pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
153 self.handle.as_ptr()
154 }
155}