1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use ;
use crate;
use crate::;
/// Builds a PDF link annotation dictionary from a [`PdfLink`]
/// (see [PDF 32000-1:2008, 12.5.6.5] for link annotations, [12.6.4] for action types).
///
/// This is the Rust analogue of MuPDF's [`pdf_create_link`] (annotation-dict building portion).
/// Like [`pdf_create_link`], it transforms the bounding rectangle from Fitz space to PDF user
/// space and assembles the annotation dictionary. It differs from [`pdf_create_link`] in that it:
///
/// - supports writing either `/A` (action) or `/Dest` (direct destination) via
/// [`set_link_action_on_annot_dict`], while MuPDF always writes `/A` via
/// [`pdf_new_action_from_link`],
/// - adds a `/P` back-reference to the parent page object (see below),
/// - returns the dict without inserting it into `/Annots` or creating an indirect object
/// (the caller handles those steps).
///
/// # Dictionary structure
///
/// | Entry | Value |
/// |------------|----------------------------------------------------------------------|
/// | `Type` | `/Annot` |
/// | `Subtype` | `/Link` |
/// | `Rect` | Link bounding box in PDF user space (transformed from Fitz) |
/// | `BS` | Border style dict: `{S: /S, Type: /Border, W: 0}` — invisible border |
/// | `A`/`Dest` | Action or destination (see [`set_link_action_on_annot_dict`]) |
/// | `P` | Indirect reference to the parent page object |
///
/// where:
/// - `BS` is the Border Style dictionary ([PDF 32000-1:2008, 12.5.4], Table 166).
/// - `S = /S` selects the solid border style, `Type = /Border` types the sub-dictionary,
/// and `W = 0` sets zero width — producing an invisible border while the link region
/// remains active.
/// - `P` is the parent page back-reference ([PDF 32000-1:2008, 12.5.2], Table 164).
///
/// For action and destination entry shapes and per-variant MuPDF function mapping, see
/// [`set_link_action_on_annot_dict`].
///
/// [PDF 32000-1:2008, 12.5.6.5]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1951136
/// [12.6.4]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1697199
/// [`pdf_create_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-annot.c#L717
/// [`pdf_new_action_from_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-link.c#L1177
/// [PDF 32000-1:2008, 12.5.4]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1696585
/// [PDF 32000-1:2008, 12.5.2]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.2292182
pub
/// Writes the link target entry onto an annotation dictionary from a [`LinkAction`]
/// (see [PDF 32000-1:2008, 12.5.6.5], Table 173).
///
/// - [`LinkAction::Action`] -> delegates to [`set_action_on_annot_dict`] (writes `/A`).
/// - [`LinkAction::Dest`] -> encodes the destination and writes it as `/Dest` directly.
///
/// Unlike MuPDF's [`pdf_create_link`] and [`pdf_set_link_uri`], which always write `/A`
/// via [`pdf_new_action_from_link`], this function additionally supports writing `/Dest`
/// directly, matching PDF link annotations that carry a direct destination instead of an
/// action dictionary (see [PDF 32000-1:2008, 12.3.2]).
///
/// **Note:** Callers are responsible for removing the conflicting `/Dest` or `/A` entry before
/// calling this function when updating existing annotations.
///
/// [PDF 32000-1:2008, 12.5.6.5]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1951136
/// [PDF 32000-1:2008, 12.3.2]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.2063217
/// [`pdf_create_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-annot.c#L717
/// [`pdf_set_link_uri`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-link.c#L614
/// [`pdf_new_action_from_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-link.c#L1177
pub
/// Builds and puts the `/A` action dictionary onto an annotation dictionary from a
/// [`PdfAction`] (see [PDF 32000-1:2008, 12.6.4]).
///
/// This is the Rust analogue of MuPDF's [`pdf_new_action_from_link`], which dispatches on
/// the URI scheme to build different action dictionary shapes. This function performs the
/// same dispatch directly on structured [`PdfAction`] values. Unlike MuPDF's [`pdf_new_action_from_link`]
/// this function upports [`PdfAction::Launch`].
///
/// # Action dictionary shapes
///
/// | Variant | `S` (type) | `D` entry (`URI` for `Uri`) | `F` entry |
/// |---------------------------|------------|-----------------------------|---------------|
/// | `GoTo(Page { .. })` | `GoTo` | `[page_ref, /Kind, ...]` | - |
/// | `GoTo(Named(..))` | `GoTo` | `(name)` | - |
/// | `Uri(..)` | `URI` | `(uri)` | - |
/// | `GoToR { .. }` (explicit) | `GoToR` | `[page_int, /Kind, ...]` | filespec dict |
/// | `GoToR { .. }` (named) | `GoToR` | `(name)` | filespec dict |
/// | `Launch(..)` | `Launch` | - | filespec dict |
///
/// For `GoTo(Page { .. })`, destination coordinates are transformed from MuPDF page space to
/// PDF default user space using the inverse CTM from the `resolver`. For `GoToR` coordinates
/// are passed as-is (already in PDF default user space).
///
/// **Note:** Callers are responsible for removing any conflicting `/Dest` entry before calling
/// this function when updating existing annotations.
///
/// # MuPDF source mapping
///
/// | Variant | MuPDF function(s) |
/// |---------------------------|----------------------------------------------------------------------------|
/// | `GoTo(Page { .. })` | [`pdf_new_action_from_link`] (`#` branch) + [`pdf_new_dest_from_link`] |
/// | `GoTo(Named(..))` | [`pdf_new_action_from_link`] (`#` branch) + [`pdf_new_dest_from_link`] |
/// | `Uri(..)` | [`pdf_new_action_from_link`] ([`fz_is_external_link`] branch) |
/// | `GoToR { .. }` | [`pdf_new_action_from_link`] (`file:` branch) + [`pdf_new_dest_from_link`] |
/// | `Launch(..)` | (no direct MuPDF equivalent, see [PDF 32000-1:2008, 12.6.4.5]) |
///
/// [PDF 32000-1:2008, 12.6.4]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1697199
/// [PDF 32000-1:2008, 12.6.4.5]: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf#G11.1952224
/// [`pdf_new_action_from_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-link.c#L1177
/// [`pdf_new_dest_from_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/pdf/pdf-link.c#L1286
/// [`fz_is_external_link`]: https://github.com/ArtifexSoftware/mupdf/blob/60bf95d09f496ab67a5e4ea872bdd37a74b745fe/source/fitz/link.c#L68