use pdfrum_common::{Diagnostics, PageIndex};
use crate::Document;
#[derive(Debug)]
pub struct Outline<'a> {
doc: &'a Document,
entries: Vec<pdfrum_doc::Bookmark>,
}
impl<'a> Outline<'a> {
pub(crate) fn load(doc: &'a Document) -> Outline<'a> {
let mut diags = Diagnostics::default();
let entries =
pdfrum_doc::nav::outline_bookmarks(&doc.catalog(), &doc.inner, &doc.limits, &mut diags);
doc.note(&diags);
Outline { doc, entries }
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> OutlineIter<'_, 'a> {
OutlineIter {
doc: self.doc,
inner: self.entries.iter(),
}
}
}
#[derive(Debug, Clone)]
pub struct OutlineIter<'outline, 'doc: 'outline> {
doc: &'doc Document,
inner: std::slice::Iter<'outline, pdfrum_doc::Bookmark>,
}
impl<'outline, 'doc: 'outline> Iterator for OutlineIter<'outline, 'doc> {
type Item = Bookmark<'doc>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|inner| Bookmark {
doc: self.doc,
inner: inner.clone(),
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl ExactSizeIterator for OutlineIter<'_, '_> {}
impl<'outline, 'doc: 'outline> IntoIterator for &'outline Outline<'doc> {
type Item = Bookmark<'doc>;
type IntoIter = OutlineIter<'outline, 'doc>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Debug, Clone)]
pub struct Bookmark<'a> {
doc: &'a Document,
inner: pdfrum_doc::Bookmark,
}
impl Bookmark<'_> {
#[must_use]
pub fn title(&self) -> String {
self.inner.title(&self.doc.inner)
}
#[must_use]
pub fn depth(&self) -> usize {
self.inner.depth
}
#[must_use]
pub fn is_open(&self) -> bool {
self.inner.count(&self.doc.inner) > 0
}
#[must_use]
pub fn page_index(&self) -> Option<PageIndex> {
let mut diags = Diagnostics::default();
let catalog = self.doc.catalog();
let dest = self
.inner
.dest(&catalog, &self.doc.inner, &self.doc.limits, &mut diags);
let index = dest.page_index(
&self.doc.inner,
|num| self.doc.page_index_of(num),
&mut diags,
);
self.doc.note(&diags);
index
}
#[must_use]
pub fn action(&self) -> Option<pdfrum_doc::Action> {
self.inner.action(&self.doc.inner)
}
#[must_use]
pub fn color(&self) -> Option<(f32, f32, f32)> {
self.inner.color(&self.doc.inner)
}
}
impl Document {
pub(crate) fn page_index_of(&self, obj_num: u32) -> Option<PageIndex> {
(0..self.page_count()).map(PageIndex::from).find(|index| {
self.inner
.page(*index)
.ok()
.and_then(|page| page.reference)
.is_some_and(|reference| reference.num == obj_num)
})
}
}