use crate::bindgen::{FPDF_MATCHCASE, FPDF_MATCHWHOLEWORD, FPDF_SCHHANDLE};
use crate::bindings::PdfiumLibraryBindings;
use crate::page_text::PdfPageText;
use crate::page_text_chars::PdfPageTextCharIndex;
use crate::page_text_segments::PdfPageTextSegments;
use std::os::raw::c_ulong;
#[cfg(doc)]
use crate::page::PdfPage;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PdfSearchOptions {
match_case: bool,
match_whole_word: bool,
}
impl PdfSearchOptions {
pub fn new() -> Self {
PdfSearchOptions {
match_case: false,
match_whole_word: false,
}
}
pub fn match_case(mut self, do_match_case: bool) -> Self {
self.match_case = do_match_case;
self
}
pub fn match_whole_word(mut self, do_match_whole_word: bool) -> Self {
self.match_whole_word = do_match_whole_word;
self
}
pub(crate) fn as_pdfium(&self) -> c_ulong {
let mut flag = 0;
if self.match_case {
flag |= FPDF_MATCHCASE;
}
if self.match_whole_word {
flag |= FPDF_MATCHWHOLEWORD;
}
flag as c_ulong
}
}
impl Default for PdfSearchOptions {
#[inline]
fn default() -> Self {
PdfSearchOptions::new()
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum PdfSearchDirection {
SearchForward,
SearchBackward,
}
pub struct PdfPageTextSearch<'a> {
handle: FPDF_SCHHANDLE,
text_page: &'a PdfPageText<'a>,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfPageTextSearch<'a> {
pub(crate) fn from_pdfium(
handle: FPDF_SCHHANDLE,
text_page: &'a PdfPageText<'a>,
bindings: &'a dyn PdfiumLibraryBindings,
) -> Self {
PdfPageTextSearch {
handle,
text_page,
bindings,
}
}
#[allow(unused)]
#[inline]
pub(crate) fn handle(&self) -> FPDF_SCHHANDLE {
self.handle
}
#[inline]
pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
self.bindings
}
#[inline]
pub fn find_next(&self) -> Option<PdfPageTextSegments> {
self.get_next_result(PdfSearchDirection::SearchForward)
}
#[inline]
pub fn find_previous(&self) -> Option<PdfPageTextSegments> {
self.get_next_result(PdfSearchDirection::SearchBackward)
}
pub fn get_next_result(&self, direction: PdfSearchDirection) -> Option<PdfPageTextSegments> {
let has_next = if direction == PdfSearchDirection::SearchForward {
self.bindings.FPDFText_FindNext(self.handle) != 0
} else {
self.bindings.FPDFText_FindPrev(self.handle) != 0
};
if has_next {
let start_index = self.bindings.FPDFText_GetSchResultIndex(self.handle);
let count = self.bindings.FPDFText_GetSchCount(self.handle);
return Some(self.text_page.segments_subset(
start_index as PdfPageTextCharIndex,
count as PdfPageTextCharIndex,
));
} else {
None
}
}
#[inline]
pub fn iter(&self, direction: PdfSearchDirection) -> PdfPageTextSearchIterator {
PdfPageTextSearchIterator::new(self, direction)
}
}
impl<'a> Drop for PdfPageTextSearch<'a> {
#[inline]
fn drop(&mut self) {
self.bindings.FPDFText_FindClose(self.handle);
}
}
pub struct PdfPageTextSearchIterator<'a> {
search: &'a PdfPageTextSearch<'a>,
direction: PdfSearchDirection,
}
impl<'a> PdfPageTextSearchIterator<'a> {
pub(crate) fn new(search: &'a PdfPageTextSearch<'a>, direction: PdfSearchDirection) -> Self {
PdfPageTextSearchIterator { search, direction }
}
}
impl<'a> Iterator for PdfPageTextSearchIterator<'a> {
type Item = PdfPageTextSegments<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.search.get_next_result(self.direction)
}
}