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