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(
124 &self,
125 direction: PdfSearchDirection,
126 ) -> Option<PdfPageTextSegments<'_>> {
127 let has_next = if direction == PdfSearchDirection::SearchForward {
128 self.bindings().FPDFText_FindNext(self.search_handle()) != 0
129 } else {
130 self.bindings().FPDFText_FindPrev(self.search_handle()) != 0
131 };
132
133 if has_next {
134 let start_index = self
135 .bindings()
136 .FPDFText_GetSchResultIndex(self.search_handle());
137 let count = self.bindings().FPDFText_GetSchCount(self.search_handle());
138
139 Some(self.text_page.segments_subset(
140 start_index as PdfPageTextCharIndex,
141 count as PdfPageTextCharIndex,
142 ))
143 } else {
144 None
145 }
146 }
147
148 #[inline]
151 pub fn iter(&self, direction: PdfSearchDirection) -> PdfPageTextSearchIterator<'_> {
152 PdfPageTextSearchIterator::new(self, direction)
153 }
154}
155
156impl<'a> Drop for PdfPageTextSearch<'a> {
157 #[inline]
159 fn drop(&mut self) {
160 self.bindings().FPDFText_FindClose(self.search_handle());
161 }
162}
163
164pub struct PdfPageTextSearchIterator<'a> {
166 search: &'a PdfPageTextSearch<'a>,
167 direction: PdfSearchDirection,
168}
169
170impl<'a> PdfPageTextSearchIterator<'a> {
171 pub(crate) fn new(search: &'a PdfPageTextSearch<'a>, direction: PdfSearchDirection) -> Self {
172 PdfPageTextSearchIterator { search, direction }
173 }
174}
175
176impl<'a> Iterator for PdfPageTextSearchIterator<'a> {
177 type Item = PdfPageTextSegments<'a>;
178
179 fn next(&mut self) -> Option<Self::Item> {
180 self.search.get_next_result(self.direction)
181 }
182}