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