Skip to main content

folio_nav/
destination.rs

1//! PDF destinations — specify a page and view.
2
3use folio_cos::{ObjectId, PdfObject};
4
5/// Destination fit types.
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub enum FitType {
8    /// /XYZ left top zoom
9    XYZ { left: f64, top: f64, zoom: f64 },
10    /// /Fit — fit entire page
11    Fit,
12    /// /FitH top
13    FitH { top: f64 },
14    /// /FitV left
15    FitV { left: f64 },
16    /// /FitR left bottom right top
17    FitR {
18        left: f64,
19        bottom: f64,
20        right: f64,
21        top: f64,
22    },
23    /// /FitB — fit bounding box
24    FitB,
25    /// /FitBH top
26    FitBH { top: f64 },
27    /// /FitBV left
28    FitBV { left: f64 },
29}
30
31/// A parsed PDF destination.
32#[derive(Debug, Clone)]
33pub struct Destination {
34    /// The target page reference.
35    pub page_ref: Option<ObjectId>,
36    /// The fit type and parameters.
37    pub fit: FitType,
38}
39
40impl Destination {
41    /// Parse a destination from a PDF object.
42    ///
43    /// Destinations can be:
44    /// - An array: [page /FitType params...]
45    /// - A name (named destination — needs resolution from the Names tree)
46    /// - A string (named destination)
47    pub fn from_object(obj: &PdfObject) -> Option<Self> {
48        let arr = obj.as_array()?;
49        if arr.is_empty() {
50            return None;
51        }
52
53        let page_ref = arr[0].as_reference();
54        let fit_name = arr.get(1).and_then(|o| o.as_name()).unwrap_or(b"Fit");
55
56        let f = |idx: usize| -> f64 { arr.get(idx).and_then(|o| o.as_f64()).unwrap_or(0.0) };
57
58        let fit = match fit_name {
59            b"XYZ" => FitType::XYZ {
60                left: f(2),
61                top: f(3),
62                zoom: f(4),
63            },
64            b"Fit" => FitType::Fit,
65            b"FitH" => FitType::FitH { top: f(2) },
66            b"FitV" => FitType::FitV { left: f(2) },
67            b"FitR" => FitType::FitR {
68                left: f(2),
69                bottom: f(3),
70                right: f(4),
71                top: f(5),
72            },
73            b"FitB" => FitType::FitB,
74            b"FitBH" => FitType::FitBH { top: f(2) },
75            b"FitBV" => FitType::FitBV { left: f(2) },
76            _ => FitType::Fit,
77        };
78
79        Some(Self { page_ref, fit })
80    }
81}