pdfium_render/pdf/document/page/text/
search.rs1use crate::bindgen::{FPDF_MATCHCASE, FPDF_MATCHWHOLEWORD, FPDF_SCHHANDLE};
5use crate::pdf::document::page::text::chars::PdfPageTextCharIndex;
6use crate::pdf::document::page::text::segments::PdfPageTextSegments;
7use crate::pdf::document::page::text::PdfPageText;
8use crate::pdfium::PdfiumLibraryBindingsAccessor;
9use std::marker::PhantomData;
10use std::os::raw::c_ulong;
11
12#[cfg(doc)]
13use crate::pdf::document::page::PdfPage;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct PdfSearchOptions {
18 match_case: bool,
19 match_whole_word: bool,
20}
21
22impl PdfSearchOptions {
23 pub fn new() -> Self {
25 PdfSearchOptions {
26 match_case: false,
27 match_whole_word: false,
28 }
29 }
30
31 pub fn match_case(mut self, do_match_case: bool) -> Self {
34 self.match_case = do_match_case;
35
36 self
37 }
38
39 pub fn match_whole_word(mut self, do_match_whole_word: bool) -> Self {
42 self.match_whole_word = do_match_whole_word;
43
44 self
45 }
46
47 pub(crate) fn as_pdfium(&self) -> c_ulong {
48 let mut flag = 0;
49
50 if self.match_case {
51 flag |= FPDF_MATCHCASE;
52 }
53 if self.match_whole_word {
54 flag |= FPDF_MATCHWHOLEWORD;
55 }
56
57 flag as c_ulong
58 }
59}
60
61impl Default for PdfSearchOptions {
62 #[inline]
63 fn default() -> Self {
64 PdfSearchOptions::new()
65 }
66}
67
68#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
70pub enum PdfSearchDirection {
71 SearchForward,
72 SearchBackward,
73}
74
75pub struct PdfPageTextSearch<'a> {
78 search_handle: FPDF_SCHHANDLE,
79 text_page: &'a PdfPageText<'a>,
80 lifetime: PhantomData<&'a FPDF_SCHHANDLE>,
81}
82
83impl<'a> PdfPageTextSearch<'a> {
84 pub(crate) fn from_pdfium(
85 search_handle: FPDF_SCHHANDLE,
86 text_page: &'a PdfPageText<'a>,
87 ) -> Self {
88 PdfPageTextSearch {
89 search_handle,
90 text_page,
91 lifetime: PhantomData,
92 }
93 }
94
95 #[inline]
97 pub(crate) fn search_handle(&self) -> FPDF_SCHHANDLE {
98 self.search_handle
99 }
100
101 #[inline]
104 pub fn find_next(&self) -> Option<PdfPageTextSegments<'_>> {
105 self.get_next_result(PdfSearchDirection::SearchForward)
106 }
107
108 #[inline]
111 pub fn find_previous(&self) -> Option<PdfPageTextSegments<'_>> {
112 self.get_next_result(PdfSearchDirection::SearchBackward)
113 }
114
115 pub fn get_next_result(
118 &self,
119 direction: PdfSearchDirection,
120 ) -> Option<PdfPageTextSegments<'_>> {
121 let has_next = if direction == PdfSearchDirection::SearchForward {
122 (unsafe { self.bindings().FPDFText_FindNext(self.search_handle()) }) != 0
123 } else {
124 (unsafe { self.bindings().FPDFText_FindPrev(self.search_handle()) }) != 0
125 };
126
127 if has_next {
128 let start_index = unsafe {
129 self.bindings()
130 .FPDFText_GetSchResultIndex(self.search_handle())
131 };
132 let count = unsafe { self.bindings().FPDFText_GetSchCount(self.search_handle()) };
133
134 Some(self.text_page.segments_subset(
135 start_index as PdfPageTextCharIndex,
136 count as PdfPageTextCharIndex,
137 ))
138 } else {
139 None
140 }
141 }
142
143 #[inline]
146 pub fn iter(&self, direction: PdfSearchDirection) -> PdfPageTextSearchIterator<'_> {
147 PdfPageTextSearchIterator::new(self, direction)
148 }
149}
150
151impl<'a> Drop for PdfPageTextSearch<'a> {
152 #[inline]
154 fn drop(&mut self) {
155 unsafe {
156 self.bindings().FPDFText_FindClose(self.search_handle());
157 }
158 }
159}
160
161impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageTextSearch<'a> {}
162
163#[cfg(feature = "thread_safe")]
164unsafe impl<'a> Send for PdfPageTextSearch<'a> {}
165
166#[cfg(feature = "thread_safe")]
167unsafe impl<'a> Sync for PdfPageTextSearch<'a> {}
168
169pub struct PdfPageTextSearchIterator<'a> {
171 search: &'a PdfPageTextSearch<'a>,
172 direction: PdfSearchDirection,
173}
174
175impl<'a> PdfPageTextSearchIterator<'a> {
176 pub(crate) fn new(search: &'a PdfPageTextSearch<'a>, direction: PdfSearchDirection) -> Self {
177 PdfPageTextSearchIterator { search, direction }
178 }
179}
180
181impl<'a> Iterator for PdfPageTextSearchIterator<'a> {
182 type Item = PdfPageTextSegments<'a>;
183
184 fn next(&mut self) -> Option<Self::Item> {
185 self.search.get_next_result(self.direction)
186 }
187}