use crate::bindgen::FPDF_STRUCTTREE;
use crate::bindings::PdfiumLibraryBindings;
use crate::pdf::document::page::struct_element::PdfStructElement;
use std::os::raw::c_int;
pub struct PdfStructTree<'a> {
tree_handle: FPDF_STRUCTTREE,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfStructTree<'a> {
pub(crate) fn from_pdfium(tree_handle: FPDF_STRUCTTREE, bindings: &'a dyn PdfiumLibraryBindings) -> Self {
Self { tree_handle, bindings }
}
pub fn children_count(&self) -> usize {
let count = self.bindings.FPDF_StructTree_CountChildren(self.tree_handle);
if count < 0 { 0 } else { count as usize }
}
pub fn child_at_index(&self, index: usize) -> Option<PdfStructElement<'_>> {
let handle = self
.bindings
.FPDF_StructTree_GetChildAtIndex(self.tree_handle, index as c_int);
if handle.is_null() {
None
} else {
Some(PdfStructElement::from_pdfium(handle, self.bindings))
}
}
pub fn children(&self) -> PdfStructTreeChildrenIterator<'_> {
PdfStructTreeChildrenIterator {
tree: self,
count: self.children_count(),
index: 0,
}
}
pub fn iter(&self) -> PdfStructTreeIterator<'_> {
let mut stack = Vec::new();
let count = self.children_count();
for i in (0..count).rev() {
if let Some(child) = self.child_at_index(i) {
stack.push((child, 0usize));
}
}
PdfStructTreeIterator { stack }
}
}
impl Drop for PdfStructTree<'_> {
fn drop(&mut self) {
self.bindings.FPDF_StructTree_Close(self.tree_handle);
}
}
pub struct PdfStructTreeChildrenIterator<'a> {
tree: &'a PdfStructTree<'a>,
count: usize,
index: usize,
}
impl<'a> Iterator for PdfStructTreeChildrenIterator<'a> {
type Item = PdfStructElement<'a>;
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.count {
let current = self.index;
self.index += 1;
if let Some(child) = self.tree.child_at_index(current) {
return Some(child);
}
}
None
}
}
pub struct PdfStructTreeIterator<'a> {
stack: Vec<(PdfStructElement<'a>, usize)>,
}
impl<'a> Iterator for PdfStructTreeIterator<'a> {
type Item = (PdfStructElement<'a>, usize);
fn next(&mut self) -> Option<Self::Item> {
let (element, depth) = self.stack.pop()?;
let child_count = element.children_count();
for i in (0..child_count).rev() {
if let Some(child) = element.child_at_index(i) {
self.stack.push((child, depth + 1));
}
}
Some((element, depth))
}
}