| Commit | Line | Data |
|---|---|---|
| 465b256c JR |
1 | .\" -*- nroff -*- |
| 2 | .ig | |
| 3 | ||
| 4 | pdfmark.tmac | |
| 5 | ||
| 4d3e9548 | 6 | Copyright (C) 2004, 2005, 2006, 2007, 2009 |
| 465b256c JR |
7 | Free Software Foundation, Inc. |
| 8 | Written by Keith Marshall (keith.d.marshall@ntlworld.com) | |
| 9 | ||
| 10 | This file is part of groff. | |
| 11 | ||
| 12 | groff is free software; you can redistribute it and/or modify it under | |
| 13 | the terms of the GNU General Public License as published by the Free | |
| 4d3e9548 JL |
14 | Software Foundation, either version 3 of the License, or |
| 15 | (at your option) any later version. | |
| 465b256c JR |
16 | |
| 17 | groff is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 18 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 19 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 20 | for more details. | |
| 21 | ||
| 4d3e9548 JL |
22 | You should have received a copy of the GNU General Public License |
| 23 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 465b256c JR |
24 | |
| 25 | Author's Note | |
| 26 | ============= | |
| 27 | ||
| 28 | While I have written this macro package from scratch, much of my | |
| 29 | inspiration has come from discussion on the groff mailing list | |
| 30 | (mailto:groff@gnu.org). I am particularly indebted to: | |
| 31 | ||
| 32 | Kees Zeelenberg, for an earlier macro package he posted, | |
| 33 | a study of which helped me to get started. | |
| 34 | ||
| 35 | Carlos J. G. Duarte and Werner Lemberg, whose discussion | |
| 36 | on computation of the bounding boxes for link "hot-spots" | |
| 37 | forms the basis of such computations in this package. | |
| 38 | .. | |
| 39 | .if !\n(.g .ab These pdfmark macros require groff. | |
| 40 | .\" | |
| 41 | .\" Check if we have already been loaded -- do not reload | |
| 42 | .if d pdfmark .nx | |
| 43 | .\" | |
| 44 | .\" ====================================================================== | |
| 4d3e9548 | 45 | .\" Module PDFMARK: Insert Arbitrary PDFMARK Code in the Postscript Stream |
| 465b256c JR |
46 | .\" ====================================================================== |
| 47 | .\" | |
| 48 | .\" PDFMARK output may be disabled, by zeroing the PDFOPMODE register, | |
| 49 | .\" ( which mimics a more generic OPMODE, if it is defined ). | |
| 50 | .\" | |
| 51 | .if rOPMODE .aln PDFOPMODE OPMODE | |
| 52 | .\" | |
| 53 | .\" but if OPMODE wasn't defined, | |
| 54 | .\" then make the default PDFMARK mode ENABLED. | |
| 55 | .\" | |
| 56 | .if !rPDFOPMODE .nr PDFOPMODE 1 | |
| 57 | .\" | |
| 4d3e9548 JL |
58 | .\" PDFMARK output must be constrained to a maximum line length limit, |
| 59 | .\" for strict compliance with the Postscript DSC. This limit is defined | |
| 60 | .\" in register "PDFMARK.FOLDWIDTH.MAX". This is user definable, up to a | |
| 61 | .\" ceiling value of 255, which is also its default value; this limit | |
| 62 | .\" is enforced for each PDFMARK, by macro "pdf*pdfmark.limit". | |
| 63 | .\" | |
| 64 | .de pdf*pdfmark.limit | |
| 65 | .\" ---------------------------------------------------------------- | |
| 66 | .\" Usage: | |
| 67 | .\" .pdf*pdfmark.limit REGISTER-NAME DEFAULT-MAXIMUM-VALUE | |
| 68 | .\" ---------------------------------------------------------------- | |
| 69 | .\" | |
| 70 | .\" If a register named REGISTER-NAME has not been defined, then | |
| 71 | .\" define it now, with default value = DEFAULT-MAXIMUM-VALUE. | |
| 72 | .\" | |
| 73 | .if !r\\$1 .nr \\$1 \\$2 | |
| 74 | .\" | |
| 75 | .\" But when it has already been defined, ensure that its value does | |
| 76 | .\" not exceed DEFAULT-MAXIMUM-VALUE; if value does exceed this ceiling, | |
| 77 | .\" then redefine it, to enforce the limit. | |
| 78 | .\" | |
| 79 | .if (\\n[\\$1] > \\$2) .nr \\$1 \\$2 | |
| 80 | .. | |
| 465b256c | 81 | .\" The "pdfmark" macro is responsible for emitting the appropriate |
| 4d3e9548 | 82 | .\" Postscript code. |
| 465b256c JR |
83 | .\" |
| 84 | .de pdfmark | |
| 85 | .\" ---------------------------------------------------------------- | |
| 86 | .\" Usage: | |
| 87 | .\" .pdfmark text of pdfmark instruction | |
| 88 | .\" Macro supplies the required opening "[" and closing "pdfmark" | |
| 89 | .\" operator; DO NOT include them in the instruction text! | |
| 90 | .\" ---------------------------------------------------------------- | |
| 91 | .\" | |
| 4d3e9548 JL |
92 | .if \\n[PDFOPMODE] \{\ |
| 93 | .\" | |
| 94 | .\" Strict DSC compliance forbids emission of ps:exec lines which | |
| 95 | .\" exceed 255 characters in length. We will allow the user to specify | |
| 96 | .\" an alternative lesser limit ... | |
| 97 | .\" | |
| 98 | . pdf*pdfmark.limit PDFMARK.FOLDWIDTH.MAX 255 | |
| 99 | .\" | |
| 100 | .\" ... and we will also support a second lesser limit, which will be | |
| 101 | .\" applied to literal text parenthetically embedded within the PDFMARK. | |
| 102 | .\" | |
| 103 | . pdf*pdfmark.limit PDFMARK.FOLDWIDTH \\n[PDFMARK.FOLDWIDTH.MAX] | |
| 104 | .\" | |
| 105 | .\" We will push out the entire PDFMARK in one chunk, provided it fits | |
| 106 | .\" within this limit. | |
| 107 | .\" | |
| 108 | . length pdf:length "[\\$* pdfmark\" | |
| 109 | . ie !(\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH]) \{\ | |
| 110 | . \" | |
| 111 | . \" This PDFMARK is suitable for single chunk output ... | |
| 112 | . \" | |
| 113 | . nop \X'ps:exec [\\$* pdfmark'\c | |
| 114 | . \} | |
| 115 | . el \{\ | |
| 116 | . \" ... but, when the limit would be violated, then we must | |
| 117 | . \" recompose the specified PDFMARK, spreading it over as many | |
| 118 | . \" continuation lines as are necessary. | |
| 119 | . \" | |
| 120 | . als pdf*compose pdf*compose.first | |
| 121 | . while \\n(.$ \{\ | |
| 122 | . pdf*compose \\$1 | |
| 123 | . shift | |
| 124 | . \} | |
| 125 | . \" | |
| 126 | . \" Complete the PDFMARK recomposition, by appending a | |
| 127 | . \" "pdfmark" operator, and push it out to the intermediate | |
| 128 | . \" output stream, (excluding its final line break). | |
| 129 | . \" | |
| 130 | . pdf*compose pdfmark | |
| 131 | . pdf*pdfmark.dispatch | |
| 132 | . chop pdf:composed | |
| 133 | . nop \Y[pdf:composed]\c | |
| 134 | . \" | |
| 135 | . \" And clean up when done. | |
| 136 | . \" | |
| 137 | . rm pdf*compose pdf*pdfmark.post | |
| 138 | . rm pdf:compose.test pdf:composed pdf:composed.literal | |
| 139 | . \} | |
| 140 | . rr pdf:length | |
| 141 | . \} | |
| 142 | .. | |
| 143 | .\" When a PDFMARK exceeds the specified output record length limit, | |
| 144 | .\" then we decompose it, subsequently using the dynamically overloaded | |
| 145 | .\" macro, "pdf*compose", to reassemble it into as many continuation | |
| 146 | .\" records as it may require. | |
| 147 | .\" | |
| 148 | .\" Each call to "pdf*compose" uses macro "pdf*length.increment" to | |
| 149 | .\" keep track of the current output record length, so ensuring that | |
| 150 | .\" the active maximum length limit is not violated. | |
| 151 | .\" | |
| 152 | .de pdf*length.increment | |
| 153 | .\" ---------------------------------------------------------------- | |
| 154 | .\" Usage: | |
| 155 | .\" .pdf*length.increment NEXT-ADDITION | |
| 156 | .\" ---------------------------------------------------------------- | |
| 157 | .\" | |
| 158 | .ie d pdf:composed.line \ | |
| 159 | . length pdf:length "\\*[pdf:composed.line] \\$*\" | |
| 160 | .el .length pdf:length "\\$*\" | |
| 161 | .. | |
| 162 | .\" The first call to "pdf*compose" for each PDFMARK is directed | |
| 163 | .\" to "pdf*compose.first"; this initialises the local strings | |
| 164 | .\" and macros used to compose the eventual PDFMARK output. | |
| 165 | .\" | |
| 166 | .de pdf*compose.first | |
| 167 | .\" ---------------------------------------------------------------- | |
| 168 | .\" Usage: | |
| 169 | .\" .als pdf*compose pdf*compose.first | |
| 170 | .\" . pdf*compose TOKEN | |
| 171 | .\" ---------------------------------------------------------------- | |
| 172 | .\" | |
| 173 | .\" Ensure that the output record accumulator will be initialised | |
| 174 | .\" on posting of the first composed PDFMARK record. | |
| 175 | .\" | |
| 176 | .als pdf*pdfmark.post pdf*pdfmark.post.first | |
| 177 | .\" | |
| 178 | .\" The first token passed to "pdf*compose" should not be a | |
| 179 | .\" literal, but be prepared to handle one, just in case. | |
| 180 | .\" | |
| 181 | .ds pdf:compose.test \\$1 | |
| 182 | .substring pdf:compose.test 0 0 | |
| 183 | .ie '('\\*[pdf:compose.test]' \{\ | |
| 184 | .\" | |
| 185 | .\" We found a literal, even though we didn't expect it; | |
| 186 | .\" if it's a single element literal, we can just handle it | |
| 187 | .\" as if it is a regular token anyway. | |
| 188 | .\" | |
| 189 | . ds pdf:compose.test "\\$\\n(.$\" | |
| 190 | . substring pdf:compose.test -1 | |
| 191 | . if !')'\\*[pdf:compose.test]' \{\ | |
| 192 | . \" | |
| 193 | . \" But when it is the first of a literal sequence, | |
| 194 | . \" then we need to set up "pdf*compose" to handle it. | |
| 195 | . \" | |
| 196 | . ds pdf:composed.literal "[\\$*\" | |
| 197 | . als pdf*compose pdf*compose.literal | |
| 198 | . \} | |
| 199 | . \} | |
| 200 | .el .ds pdf:compose.test ) | |
| 201 | .if ')'\\*[pdf:compose.test]' \{\ | |
| 202 | .\" | |
| 203 | .\" In the normal case, we start each new PDFMARK with a | |
| 204 | .\" regular token; save it as the first in the composed output | |
| 205 | .\" line sequence, and set up "pdf*compose" to collect | |
| 206 | .\" the rest of the sequence. | |
| 207 | .\" | |
| 208 | . ds pdf:composed.line "[\\$*\" | |
| 209 | . als pdf*compose pdf*compose.next | |
| 210 | . \} | |
| 211 | .. | |
| 212 | .\" Subsequent calls to "pdf*compose", while collecting | |
| 213 | .\" regular tokens, are then directed to "pdf*compose.next". | |
| 214 | .\" | |
| 215 | .de pdf*compose.next | |
| 216 | .\" ---------------------------------------------------------------- | |
| 217 | .\" Usage: | |
| 218 | .\" .als pdf*compose pdf*compose.next | |
| 219 | .\" . pdf*compose TOKEN | |
| 220 | .\" ---------------------------------------------------------------- | |
| 221 | .\" | |
| 222 | .\" This first checks to ensure that the supplied token really is | |
| 223 | .\" a regular token, and not the first element in a literal. | |
| 224 | .\" | |
| 225 | .ds pdf:compose.test \\$1 | |
| 226 | .substring pdf:compose.test 0 0 | |
| 227 | .ie '('\\*[pdf:compose.test]' \{\ | |
| 228 | .\" | |
| 229 | .\" The supplied token represents the first element of a literal, | |
| 230 | .\" but it may be a single element literal, which we simply handle | |
| 231 | .\" as a regular token anyway. | |
| 232 | .\" | |
| 233 | . ds pdf:compose.test "\\$\\n(.$\" | |
| 234 | . substring pdf:compose.test -1 | |
| 235 | . if !')'\\*[pdf:compose.test]' \{\ | |
| 236 | . \" | |
| 237 | . \" The supplied token is the first of a sequence of elements | |
| 238 | . \" which collectively define a literal, so start collecting a | |
| 239 | . \" composite literal token, and change the "pdf*compose" | |
| 240 | . \" state, to collect and append the remaining elements. | |
| 241 | . \" | |
| 242 | . ds pdf:composed.literal "\\$*\" | |
| 243 | . als pdf*compose pdf*compose.literal | |
| 244 | . \} | |
| 245 | . \} | |
| 246 | .el .ds pdf:compose.test ) | |
| 247 | .if ')'\\*[pdf:compose.test]' \{\ | |
| 248 | .\" | |
| 249 | .\" The supplied token IS a regular token; add it, but ensure that | |
| 250 | .\" the active maximum record length limit is honoured. | |
| 251 | .\" | |
| 252 | . pdf*length.increment "\\$*\" | |
| 253 | . ie (\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH.MAX]) \{\ | |
| 254 | . \" | |
| 255 | . \" Adding this token would cause the current PDFMARK record, in | |
| 256 | . \" groff's intermediate output file, to overflow the active record | |
| 257 | . \" length limit, so post the current record and start another. | |
| 258 | . \" | |
| 259 | . pdf*pdfmark.dispatch | |
| 260 | . ds pdf:composed.line "\\$*\" | |
| 261 | . \} | |
| 262 | . el \{\ | |
| 263 | . \" | |
| 264 | . \" This token will fit in the current PDFMARK record, without | |
| 265 | . \" violating the active length limit, so simply add it. | |
| 266 | . \" | |
| 267 | . ie d pdf:composed.line .as pdf:composed.line " \\$*\" | |
| 268 | . el .ds pdf:composed.line "\\$*\" | |
| 269 | . \} | |
| 270 | . \} | |
| 271 | .. | |
| 272 | .\" While assembling a multiple token literal sequence into a single | |
| 273 | .\" literal token, successive calls to "pdf*compose" are directed | |
| 274 | .\" to "pdf*compose.literal". | |
| 275 | .\" | |
| 276 | .de pdf*compose.literal | |
| 277 | .\" ---------------------------------------------------------------- | |
| 278 | .\" Usage: | |
| 279 | .\" .als pdf*compose pdf*compose.literal | |
| 280 | .\" . pdf*compose TOKEN | |
| 281 | .\" ---------------------------------------------------------------- | |
| 282 | .\" | |
| 283 | .\" First, check to ensure that the current token can be appended to | |
| 284 | .\" the accumulated literal, without extending it beyond the maximum | |
| 285 | .\" allowed literal token length. | |
| 286 | .\" | |
| 287 | .length pdf:length "\\*[pdf:composed.literal] \\$*\" | |
| 288 | .ie (\\n[pdf:length] > (\\n[PDFMARK.FOLDWIDTH] - 2)) \{\ | |
| 289 | .\" | |
| 290 | .\" If it has grown too long, then it must be folded across two | |
| 291 | .\" physical PDFMARK output records, so check if we can accommodate | |
| 292 | .\" the portion collected so far within the current output record. | |
| 293 | .\" | |
| 294 | . pdf*length.increment "\\*[pdf:composed.literal]\" | |
| 295 | . if (\\n[pdf:length] > (\\n[PDFMARK.FOLDWIDTH.MAX] - 2)) \{\ | |
| 296 | . \" | |
| 297 | . \" The current output record CAN'T accommodate the currently | |
| 298 | . \" composed portion of the literal, so flush out the current | |
| 299 | . \" record, to make way for the accumulated literal, and mark | |
| 300 | . \" the dispatch mode as "wrapped", for the fragments of the | |
| 301 | . \" folded literal string, which are to follow. | |
| 302 | . \" | |
| 303 | . pdf*pdfmark.dispatch | |
| 304 | . ds pdf*pdfmark.dispatch.wrapped | |
| 305 | . \} | |
| 306 | . ie d pdf:composed.line \{\ | |
| 307 | . \" | |
| 308 | . \" If we DIDN'T need to flush the current output record, | |
| 309 | . \" then we can simply append the accumulated literal to it... | |
| 310 | . \" | |
| 311 | . as pdf:composed.line " \\*[pdf:composed.literal]\" | |
| 312 | . \} | |
| 313 | . el \{\ | |
| 314 | . \" | |
| 315 | . \" otherwise, when the current record has been flushed, or is | |
| 316 | . \" empty, then we promote the accumulated literal, to make it | |
| 317 | . \" the next output record... | |
| 318 | . \" | |
| 319 | . rn pdf:composed.literal pdf:composed.line | |
| 320 | . \} | |
| 321 | .\" | |
| 322 | .\" Now, to complete the fold, flush out any accumulated partial | |
| 323 | .\" output record, and continue accumulating the literal, starting | |
| 324 | .\" with the current token. | |
| 325 | .\" | |
| 326 | . pdf*pdfmark.dispatch | |
| 327 | . ds pdf:composed.literal "\\$*\" | |
| 328 | . \} | |
| 329 | .el \{\ | |
| 330 | .\" | |
| 331 | .\" Alternatively, when we HAVEN'T identified a need to fold the | |
| 332 | .\" current output record, then we simply append the current token | |
| 333 | .\" to the accumulated literal token buffer string. | |
| 334 | .\" | |
| 335 | . as pdf:composed.literal " \\$*\" | |
| 336 | . \} | |
| 337 | .\" | |
| 338 | .\" Having ensured that we have sufficient space, in which to | |
| 339 | .\" append the current token to the currently accumulated literal, | |
| 340 | .\" we check its rightmost character, to see if is the closing | |
| 341 | .\" parenthesis, which completes the literal. | |
| 342 | .\" | |
| 343 | .ds pdf:compose.test \\$\\n(.$ | |
| 344 | .substring pdf:compose.test -1 | |
| 345 | .if ')'\\*[pdf:compose.test]' \{\ | |
| 346 | .\" | |
| 347 | .\" The literal has been completely collected, so we may now append | |
| 348 | .\" it to the current output record, as a single literal token, but | |
| 349 | .\" subject to the constraint that it must not extend the output | |
| 350 | .\" record beyond the maximum permitted length. | |
| 351 | .\" | |
| 352 | . pdf*length.increment "\\*[pdf:composed.literal]\" | |
| 353 | . ie (\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH.MAX]) \{\ | |
| 354 | . \" | |
| 355 | . \" So, when the literal cannot be accommodated within the maximum | |
| 356 | . \" length constraint, then we flush the current record, and start | |
| 357 | . \" a new one, with the literal token as its first entry. | |
| 358 | . \" | |
| 359 | . pdf*pdfmark.dispatch | |
| 360 | . rn pdf:composed.literal pdf:composed.line | |
| 361 | . \} | |
| 362 | . el \{\ | |
| 363 | . \" | |
| 364 | . \" When the literal CAN be accommodated within the maximum length | |
| 365 | . \" constraint, then ... | |
| 366 | . \" | |
| 367 | . ie d pdf:composed.line \{\ | |
| 368 | . \" | |
| 369 | . \" When an output record has already been instantiated, we | |
| 370 | . \" append the literal token to it, and discard the accumulator | |
| 371 | . \" string, which is no longer required. | |
| 372 | . \" | |
| 373 | . as pdf:composed.line " \\*[pdf:composed.literal]\" | |
| 374 | . rm pdf:composed.literal | |
| 375 | . \} | |
| 376 | . el \{\ | |
| 377 | . \" | |
| 378 | . \" But when no output record yet exists, then we simply | |
| 379 | . \" reassign the accumulated literal token, to instantiate a | |
| 380 | . \" new output record. | |
| 381 | . \" | |
| 382 | . rn pdf:composed.literal pdf:composed.line | |
| 383 | . \} | |
| 384 | . \} | |
| 385 | .\" | |
| 386 | .\" Finally, since we have completed the accumulation of the literal, we | |
| 387 | .\" revert to the "unwrapped" mode of operation for "pdf*pdfmark.dispatch", | |
| 388 | .\" and restore the normal "pdf*compose" action, for collection of the next | |
| 389 | .\" token (if any). | |
| 390 | .\" | |
| 391 | . rm pdf*pdfmark.dispatch.wrapped | |
| 392 | . als pdf*compose pdf*compose.next | |
| 393 | . \} | |
| 394 | .. | |
| 395 | .\" While composing a multiple record PDFMARK, each composed record | |
| 396 | .\" must be added to the collection, whenever the partially composed | |
| 397 | .\" output record has been filled; this is handled when necessary, | |
| 398 | .\" by calling the "pdf*pdfmark.dispatch" macro. | |
| 399 | .\" | |
| 400 | .de pdf*pdfmark.dispatch | |
| 401 | .\" ---------------------------------------------------------------- | |
| 402 | .\" Usage: | |
| 403 | .\" .pdf*pdfmark.dispatch | |
| 404 | .\" ---------------------------------------------------------------- | |
| 405 | .\" | |
| 406 | .if d pdf:composed.line \{\ | |
| 407 | .\" | |
| 408 | .\" This is simply a wrapper around the overloaded "pdf*pdfmark.post" | |
| 409 | .\" macro, ensuring that an output record has actually been collected | |
| 410 | .\" before attempting to post it; it then cleans up after posting, to | |
| 411 | .\" ensure that each collected record is posted only once. | |
| 412 | .\" | |
| 413 | . if d pdf*pdfmark.dispatch.wrapped \{\ | |
| 414 | . \" | |
| 415 | . \" When dispatching an excessively long literal string, which | |
| 416 | . \" must be wrapped over multiple records, this mode is active | |
| 417 | . \" for all but the closing record; we must escape the newline | |
| 418 | . \" at the end of each such unclosed literal record. | |
| 419 | . \" | |
| 420 | . as pdf:composed.line " \\\\\\\\\" | |
| 421 | . \} | |
| 422 | . pdf*pdfmark.post | |
| 423 | . rm pdf:composed.line | |
| 424 | . \} | |
| 425 | .. | |
| 426 | .\" For each PDFMARK, the first call of "pdf*pdfmark.post" is directed | |
| 427 | .\" to the "pdf*pdfmark.post.first" macro; this initialises the state | |
| 428 | .\" of the "pdf:composed" macro, for assembly of a new PDFMARK. | |
| 429 | .\" | |
| 430 | .de pdf*pdfmark.post.first | |
| 431 | .de pdf:composed pdf*end | |
| 432 | ps:exec \\*[pdf:composed.line] | |
| 433 | .pdf*end | |
| 434 | .\" | |
| 435 | .\" Subsequent calls to "pdf*pdfmark.post" are redirected to the | |
| 436 | .\" alternative "pdf*pdfmark.post.next" macro, which simply appends | |
| 437 | .\" additional PDFMARK records to the "pdf:composed" macro. | |
| 438 | .\" | |
| 439 | .als pdf*pdfmark.post pdf*pdfmark.post.next | |
| 440 | .. | |
| 441 | .de pdf*pdfmark.post.next | |
| 442 | .am pdf:composed pdf*end | |
| 443 | \\*[pdf:composed.line] | |
| 444 | .pdf*end | |
| 445 | .. | |
| 446 | .\" "pdf*end" is a dummy macro. It is required to mark the end | |
| 447 | .\" of each individual fragment which is added to "pdf:composed"; | |
| 448 | .\" other than this, it does nothing. | |
| 449 | .\" | |
| 450 | .de pdf*end | |
| 465b256c JR |
451 | .. |
| 452 | .\" | |
| 453 | .\" Some supporting macros defer actual pdfmark output until an | |
| 454 | .\" appropriate time for it to be written; the "pdfsync" macro | |
| 455 | .\" provides a mechanism for flushing such deferred output; | |
| 456 | .\" it should be called from an end macro, and at any other time | |
| 457 | .\" when it may be deemed necessary to flush pdfmark context. | |
| 458 | .\" | |
| 459 | .de pdfsync | |
| 460 | .\" ---------------------------------------------------------------- | |
| 461 | .\" Usage: | |
| 462 | .\" .pdfsync buffer ... | |
| 463 | .\" Arguments indicate which "buffer(s)" to flush: | |
| 464 | .\" O -> bookmark (outline) cache | |
| 465 | .\" M -> document metadata diversion | |
| 466 | .\" If no argument, flush ALL buffers | |
| 467 | .\" ---------------------------------------------------------------- | |
| 468 | .\" | |
| 469 | .ie \\n(.$ \{\ | |
| 470 | . while \\n(.$ \{\ | |
| 471 | . if '\\$1'O' .pdf:bm.sync 1 | |
| 472 | . if '\\$1'M' \{\ | |
| 473 | . if dpdf:metadata .pdf:metadata | |
| 474 | . rm pdf:metadata | |
| 475 | . \} | |
| 476 | . shift | |
| 477 | . \} | |
| 478 | . \} | |
| 479 | .el .pdfsync O M | |
| 480 | .. | |
| 481 | .\" | |
| 482 | .\" some helper functions ... | |
| 483 | .\" | |
| 484 | .\" "pdf:warn" and "pdf:error" write diagnostic messages to stderr | |
| 485 | .\" | |
| 486 | .de pdf:warn | |
| 487 | .\" ---------------------------------------------------------- | |
| 488 | .\" Usage: | |
| 489 | .\" .pdf:warn text of message | |
| 490 | .\" ---------------------------------------------------------- | |
| 491 | .\" | |
| 492 | .tm \\n(.F:\\n(.c: macro warning: \\$* | |
| 493 | .. | |
| 494 | .de pdf:error | |
| 495 | .\" ---------------------------------------------------------- | |
| 496 | .\" Usage: | |
| 497 | .\" .pdf:error text of message | |
| 498 | .\" ---------------------------------------------------------- | |
| 499 | .\" | |
| 500 | .tm \\n(.F:\\n(.c: macro error: \\$* | |
| 501 | .. | |
| 502 | .\" "pdf:pop", assisted by "pdf*pop", allows us to retrieve register, | |
| 503 | .\" or string values, from a string masquerading as a data queue, | |
| 504 | .\" or as a stack. | |
| 505 | .\" | |
| 506 | .de pdf:pop | |
| 507 | .\" ---------------------------------------------------------------- | |
| 508 | .\" Usage: | |
| 509 | .\" .pdf:pop <type> <to-name> <from-name> | |
| 510 | .\" $1 = nr for numeric register, ds for string | |
| 511 | .\" $2 = name of register or string to be assigned | |
| 512 | .\" $3 = name of string, from which data is to be retrieved | |
| 513 | .\" ---------------------------------------------------------------- | |
| 514 | .\" | |
| 515 | .pdf*pop \\$* \\*[\\$3] | |
| 516 | .. | |
| 517 | .de pdf*pop | |
| 518 | .ds pdf:stack \\$3 | |
| 519 | .\\$1 \\$2 \\$4 | |
| 520 | .shift 4 | |
| 521 | .ie \\n(.$ .ds \\*[pdf:stack] \\$* | |
| 522 | .el .rm \\*[pdf:stack] | |
| 523 | .rm pdf:stack | |
| 524 | .. | |
| 525 | .\" | |
| 526 | .\" | |
| 527 | .\" =========================================================== | |
| 528 | .\" Module PDFINFO: Insert MetaData Entries into a PDF Document | |
| 529 | .\" =========================================================== | |
| 530 | .\" | |
| 531 | .\" N.B. | |
| 532 | .\" Output from the macros in this module is deferred, until | |
| 533 | .\" subsequent invocation of .pdfsync, or .pdfexit | |
| 534 | .\" | |
| 535 | .\" ."pdfinfo" provides a general purpose form of metadata entry ... | |
| 536 | .\" it allows arbitrary text to be associated with any specified | |
| 537 | .\" metadata field name. | |
| 538 | .\" | |
| 539 | .de pdfinfo | |
| 540 | .\" ------------------------------------------------------------------- | |
| 541 | .\" Usage: | |
| 542 | .\" .pdfinfo /FieldName field content ... | |
| 543 | .\" Examples: | |
| 544 | .\" .pdfinfo /Title A PDF Document | |
| 545 | .\" .pdfinfo /Author Keith Marshall | |
| 546 | .\" ------------------------------------------------------------------- | |
| 547 | .\" | |
| 548 | .ds pdf:meta.field \\$1 | |
| 549 | .shift | |
| 550 | .da pdf:metadata | |
| 551 | \!.pdfmark \\*[pdf:meta.field] (\\$*) /DOCINFO | |
| 552 | .di | |
| 553 | .rm pdf:meta.field | |
| 554 | .. | |
| 555 | .\" | |
| 556 | .\" Macro "pdfview" defines a special form of metadata entry ... | |
| 557 | .\" it uses the /DOCVIEW pdfmark, to specify the initial (default) view, | |
| 558 | .\" when the document is opened. | |
| 559 | .\" | |
| 560 | .de pdfview | |
| 561 | .\" ------------------------------------------------------------------- | |
| 562 | .\" Usage: | |
| 563 | .\" .pdfview view parameters ... | |
| 564 | .\" Examples: | |
| 565 | .\" .pdfview /PageMode /UseOutlines | |
| 566 | .\" .pdfview /Page 2 /View [/FitH \n(.p u] | |
| 567 | .\" ------------------------------------------------------------------- | |
| 568 | .\" | |
| 569 | .da pdf:metadata | |
| 570 | \!.pdfmark \\$* /DOCVIEW | |
| 571 | .di | |
| 572 | .. | |
| 573 | .\" | |
| 574 | .\" | |
| 575 | .\" ===================================================================== | |
| 576 | .\" Module PDFNOTE: Insert "Sticky Note" Style Comments in a PDF Document | |
| 577 | .\" ===================================================================== | |
| 578 | .\" | |
| 579 | .\" "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" set the preferred size for | |
| 580 | .\" display of the "sticky note" pane, when opened. Acrobat Reader | |
| 581 | .\" seems not to honour these -- perhaps GhostScript doesn't encode | |
| 582 | .\" them correctly! Anyway, let's set some suitable default values, | |
| 583 | .\" in case the user has a set up which does work as advertised. | |
| 584 | .\" | |
| 585 | .nr PDFNOTE.WIDTH 3.5i | |
| 586 | .nr PDFNOTE.HEIGHT 2.0i | |
| 587 | .\" | |
| 588 | .\" "pdf:bbox" defines the expression used to set the size and location | |
| 589 | .\" of the bounding rectangle for display of notes and link "hot-spots". | |
| 590 | .\" This is defined, such that a note is placed at troff's current text | |
| 591 | .\" position on the current page, with its displayed image size defined | |
| 592 | .\" by the "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" registers, while the | |
| 593 | .\" bounds for a link "hot-spot" are matched to the text region which | |
| 594 | .\" defines the "hot-spot". | |
| 595 | .\" | |
| 596 | .ds pdf:bbox \\n[pdf:llx] u \\n[pdf:lly] u \\n[pdf:urx] u \\n[pdf:ury] u | |
| 597 | .\" | |
| 598 | .\" Getting line breaks into the text of a PDFNOTE is tricky -- we need | |
| 4d3e9548 | 599 | .\" to get a "\n" into the Postscript stream, but three levels of "\" are |
| 465b256c JR |
600 | .\" swallowed, when we invoke "pdfnote". The following definition of "PDFLB", |
| 601 | .\" (for LineBreak), is rather ugly, but does allow us to use | |
| 602 | .\" | |
| 603 | .\" .pdfnote Some text.\*[PDFLB]Some more text, on a new line. | |
| 604 | .\" | |
| 605 | .ds PDFLB \\\\\\\\\\\\\\\\n | |
| 606 | .\" | |
| 607 | .de pdfnote | |
| 608 | .\" ---------------------------------------------------------------------- | |
| 609 | .\" Usage: | |
| 610 | .\" .pdfnote [-T "Text for Title"] Text of note ... | |
| 611 | .\" ---------------------------------------------------------------------- | |
| 612 | .\" | |
| 613 | .if \\n[PDFOPMODE] \{\ | |
| 614 | .\" | |
| 615 | .\" First, compute the bounding rectangle, | |
| 616 | .\" for this PDFNOTE instance | |
| 617 | .\" | |
| 618 | . mk pdf:ury | |
| 619 | . nr pdf:llx \\n(.k+\\n(.o+\\n[.in] | |
| 620 | . nr pdf:lly \\n[pdf:ury]-\\n[PDFNOTE.HEIGHT] | |
| 621 | . nr pdf:urx \\n[pdf:llx]+\\n[PDFNOTE.WIDTH] | |
| 622 | . ds pdf:note.instance /Rect [\\*[pdf:bbox]] | |
| 623 | .\" | |
| 624 | .\" Parse any specified (recognisable) PDFNOTE options | |
| 625 | .\" | |
| 626 | . while dpdf:note\\$1 \{\ | |
| 627 | . pdf:note\\$1 \\$@ | |
| 628 | . shift \\n[pdf:note.argc] | |
| 629 | . \} | |
| 630 | .\" | |
| 631 | .\" Emit the note, and clean up | |
| 632 | .\" | |
| 633 | . pdfmark \\*[pdf:note.instance] /Contents (\\$*) /ANN | |
| 634 | . rm pdf:note.instance | |
| 635 | . rr pdf:note.argc | |
| 636 | . \} | |
| 637 | .. | |
| 638 | .de pdf:note-T | |
| 639 | .nr pdf:note.argc 2 | |
| 640 | .as pdf:note.instance " /Title (\\$2) | |
| 641 | .. | |
| 642 | .\" | |
| 643 | .\" | |
| 644 | .\" ===================================================================== | |
| 645 | .\" Module PDFBOOKMARK: Add an Outline Reference in the PDF Bookmark Pane | |
| 646 | .\" ===================================================================== | |
| 647 | .\" | |
| 648 | .\" "PDFBOOKMARK.VIEW" controls how the document will be displayed, | |
| 649 | .\" when the user selects a bookmark. This default setting will fit | |
| 650 | .\" the page width to the viewing window, with the bookmarked entry | |
| 651 | .\" located at the top of the viewable area. | |
| 652 | .\" | |
| 653 | .ds PDFBOOKMARK.VIEW /FitH \\n[PDFPAGE.Y] u | |
| 654 | .\" | |
| 655 | .\" "PDFOUTLINE.FOLDLEVEL" controls how the document outline will be | |
| 656 | .\" displayed. It is a number, defining the maximum heading level | |
| 657 | .\" which will be visible, without outline expansion by the user, in | |
| 658 | .\" the initial view of the document outline. Assuming that no sane | |
| 659 | .\" document will ever extend to 10,000 levels of nested headings, | |
| 660 | .\" this initial default value causes outlines to be fully expanded. | |
| 661 | .\" | |
| 662 | .nr PDFOUTLINE.FOLDLEVEL 10000 | |
| 663 | .\" | |
| 664 | .\" The actual job of creating an outline reference | |
| 665 | .\" is performed by the "pdfbookmark" macro. | |
| 666 | .\" | |
| 667 | .de pdfbookmark | |
| 668 | .\" ------------------------------------------------------------------ | |
| 669 | .\" Usage: | |
| 670 | .\" .pdfbookmark [-T tag] level "Text of Outline Entry" | |
| 671 | .\" | |
| 672 | .\" $1 = nesting level for bookmark (1 is top level) | |
| 673 | .\" $2 = text for bookmark, (in PDF viewer bookmarks list) | |
| 674 | .\" $3 = suffix for PDF internal bookmark name (optional) | |
| 675 | .\" ------------------------------------------------------------------ | |
| 676 | .\" | |
| 4d3e9548 | 677 | .ie '\\n(.z'' \{\ |
| 465b256c | 678 | .\" |
| 4d3e9548 JL |
679 | .\" When we are at the top diversion level, i.e. actually emitting text |
| 680 | .\" to the output device stream, then we compute the location of, and | |
| 681 | .\" plant this bookmark immediately. | |
| 465b256c | 682 | .\" |
| 4d3e9548 JL |
683 | . if \\n[PDFOPMODE] \{\ |
| 684 | . \" | |
| 685 | . \" Make the bookmark name "untagged" by default, | |
| 686 | . \" then parse any specified options, to set a "tag", if required | |
| 687 | . \" | |
| 688 | . ds pdf:href-T | |
| 689 | . while dpdf:href.opt\\$1 \{\ | |
| 690 | . pdf:href.opt\\$1 \\$@ | |
| 691 | . shift \\n[pdf:href.argc] | |
| 692 | . \} | |
| 693 | . rr pdf:href.argc | |
| 694 | . \" | |
| 695 | . \" If we found "--" to mark the end of the options, discard it | |
| 696 | . \" | |
| 697 | . if '\\$1'--' .shift | |
| 698 | . \" | |
| 699 | . \" Synchronise the bookmark cache | |
| 700 | . \" to the requested bookmark nesting level | |
| 701 | . \" | |
| 702 | . pdf:bm.sync \\$1 | |
| 703 | . shift | |
| 704 | . \" | |
| 705 | . \" Increment the bookmark serialisation index | |
| 706 | . \" in order to generate a uniquely serialised bookmark name, | |
| 707 | . \" ( which we return in the string "PDFBOOKMARK.NAME" ), | |
| 708 | . \" and insert this bookmark into the cache | |
| 709 | . \" | |
| 710 | . pdf:href.sety | |
| 711 | . nr pdf:bm.nr +1 | |
| 712 | . ds PDFBOOKMARK.NAME pdf:bm\\n[pdf:bm.nr]\\*[pdf:href-T] | |
| 713 | . ds pdf:bm\\n[pdf:bm.nr] /Dest /\\*[PDFBOOKMARK.NAME] | |
| 714 | . pdfmark \\*[pdf:bm\\n[pdf:bm.nr]] /View [\\*[PDFBOOKMARK.VIEW]] /DEST | |
| 715 | . as pdf:bm\\n[pdf:bm.nr] " /Title (\\$*) | |
| 716 | . pdf:href.options.clear | |
| 717 | . rr PDFPAGE.Y | |
| 465b256c | 718 | . \} |
| 4d3e9548 JL |
719 | . \} |
| 720 | .el \{\ | |
| 465b256c | 721 | .\" |
| 4d3e9548 JL |
722 | .\" But when we are collecting a diversion which will be written out later, |
| 723 | .\" then we must defer bookmark placement, until we emit the diversion. | |
| 724 | .\" (don't rely on $0 == pdfbookmark here; it may be a volatile alias). | |
| 465b256c | 725 | .\" |
| 4d3e9548 | 726 | . nop \!.pdfbookmark \\$@ |
| 465b256c JR |
727 | . \} |
| 728 | .. | |
| 729 | .\" | |
| 730 | .\" Macro "pdf:bm.sync" is called for each bookmark created, | |
| 731 | .\" to establish a cache entry at the appropriate nesting level. | |
| 732 | .\" It will flush ALL previous cache content, when called to | |
| 733 | .\" add a new bookmark at level 1, or if simply called at | |
| 734 | .\" level 1, without adding any bookmark. | |
| 735 | .\" | |
| 736 | .de pdf:bm.sync | |
| 737 | .\" ------------------------------------------------------------------ | |
| 738 | .\" Usage: | |
| 739 | .\" .pdf:bm.sync level | |
| 740 | .\" $1 = nesting level of current bookmark, or 1 to flush cache | |
| 741 | .\" ------------------------------------------------------------------ | |
| 742 | .\" | |
| 743 | .\" First validate the bookmark nesting level | |
| 744 | .\" adjusting it if required | |
| 745 | .\" | |
| 746 | .if \\$1>\\n[pdf:bm.nl] .nr pdf:bm.nl +1 | |
| 747 | .ie \\$1>\\n[pdf:bm.nl] \{\ | |
| 748 | . pdf:warn adjusted level \\$1 bookmark; should be <= \\n[pdf:bm.nl] | |
| 749 | . \} | |
| 750 | .el .nr pdf:bm.nl \\$1 | |
| 751 | .if \\n[pdf:bm.nl]<1 \{\ | |
| 752 | . pdf:warn bad arg (\\$1) in \\$0 \\$1; \\$0 1 forced | |
| 753 | . nr pdf:bm.nl 1 | |
| 754 | . \} | |
| 755 | .\" | |
| 756 | .\" If reverting from a higher to a lower nesting level, | |
| 757 | .\" cyclicly adjust cache counts for each pending higher level | |
| 758 | .\" | |
| 759 | .if \\n[pdf:bm.lc]>=\\n[pdf:bm.nl] \{\ | |
| 760 | . nr pdf:bm.lc +1 | |
| 761 | . if !rpdf:bm.c\\n[pdf:bm.lc].c .nr pdf:bm.c\\n[pdf:bm.lc].c 0 | |
| 762 | . while \\n[pdf:bm.lc]>\\n[pdf:bm.nl] \{\ | |
| 763 | . as pdf:bm.c\\n[pdf:bm.lc] " \\n[pdf:bm.c\\n[pdf:bm.lc].c] | |
| 764 | . rr pdf:bm.c\\n[pdf:bm.lc].c | |
| 765 | . nr pdf:bm.lc -1 | |
| 766 | . \} | |
| 767 | . \} | |
| 768 | .\" | |
| 769 | .\" Update the cache level, | |
| 770 | .\" flushing when we are at level 1 | |
| 771 | .\" | |
| 772 | .nr pdf:bm.lc \\n[pdf:bm.nl] | |
| 773 | .ie \\n[pdf:bm.nl]=1 \{\ | |
| 774 | . while \\n[pdf:bm.ic]<\\n[pdf:bm.nr] .pdf:bm.emit 0 | |
| 775 | . rr pdf:bm.rc | |
| 776 | . \} | |
| 777 | .el .nr pdf:bm.c\\n[pdf:bm.nl].c +1 | |
| 778 | .. | |
| 779 | .\" Macro "pdf:bm.emit" is called, when the cache is at level 1. | |
| 780 | .\" This flushes ALL pending bookmarks from the cache, i.e. the | |
| 781 | .\" preceding level 1 bookmark, and any nested dependents, | |
| 782 | .\" which it may have. | |
| 783 | .\" | |
| 784 | .de pdf:bm.emit | |
| 785 | .\" ------------------------------------------------------------------ | |
| 786 | .\" Usage: | |
| 787 | .\" .pdf:bm.emit flag | |
| 788 | .\" $1 = reference counting flag, used to control recursion | |
| 789 | .\" ------------------------------------------------------------------ | |
| 790 | .\" | |
| 791 | .\" First check for nested dependents, | |
| 792 | .\" and append the "dependent count" to the bookmark, as required. | |
| 793 | .\" | |
| 794 | .nr pdf:bm.ic +1 | |
| 795 | .nr pdf:bm.lc +1 | |
| 796 | .pdf:pop nr pdf:bm.rc pdf:bm.c\\n[pdf:bm.lc] | |
| 797 | .if \\n[pdf:bm.rc] \{\ | |
| 798 | . ds pdf:bm.fold | |
| 799 | . if \\n[pdf:bm.lc]>\\n[PDFOUTLINE.FOLDLEVEL] .ds pdf:bm.fold - | |
| 800 | . as pdf:bm\\n[pdf:bm.ic] " /Count \\*[pdf:bm.fold]\\n[pdf:bm.rc] | |
| 801 | . rm pdf:bm.fold | |
| 802 | . \} | |
| 803 | .pdfmark \\*[pdf:bm\\n[pdf:bm.ic]] /OUT | |
| 804 | .rm pdf:bm\\n[pdf:bm.ic] | |
| 805 | .\" | |
| 806 | .\" For ALL dependents, if any, | |
| 807 | .\" recursively flush out any higher level dependents, | |
| 808 | .\" which they themselves may have | |
| 809 | .\" | |
| 810 | .while \\n[pdf:bm.rc] \{\ | |
| 811 | . nr pdf:bm.rc -1 | |
| 812 | . pdf:bm.emit \\n[pdf:bm.rc] | |
| 813 | . \} | |
| 814 | .\" | |
| 815 | .\" Finally, | |
| 816 | .\" unwind the recursive call stack, until we return to the top level. | |
| 817 | .\" | |
| 818 | .nr pdf:bm.rc \\$1 | |
| 819 | .nr pdf:bm.lc -1 | |
| 820 | .. | |
| 821 | .nr pdf:bm.nr 0 | |
| 822 | .nr pdf:bm.nl 1 | |
| 823 | .nr pdf:bm.lc 0 | |
| 824 | .nr pdf:bm.ic 0 | |
| 825 | .\" | |
| 826 | .\" | |
| 827 | .\" ============================================================= | |
| 828 | .\" Module PDFHREF: Create Hypertext References in a PDF Document | |
| 829 | .\" ============================================================= | |
| 830 | .\" | |
| 831 | .\" "PDFHREF.VIEW" controls how the document will be displayed, | |
| 832 | .\" when the user follows a link to a named reference. | |
| 833 | .\" | |
| 834 | .ds PDFHREF.VIEW /FitH \\n[PDFPAGE.Y] u | |
| 835 | .\" | |
| 836 | .\" This default setting will fit the page width to the viewing | |
| 837 | .\" window, with the bookmarked entry located close to the top | |
| 838 | .\" of the viewable area. "PDFHREF.VIEW.LEADING" controls the | |
| 839 | .\" actual distance below the top of the viewing window, where | |
| 840 | .\" the reference will be positioned; 5 points is a reasonable | |
| 841 | .\" default offset. | |
| 842 | .\" | |
| 843 | .nr PDFHREF.VIEW.LEADING 5.0p | |
| 844 | .\" | |
| 845 | .\" Yuk!!! | |
| 846 | .\" PDF view co-ordinates are mapped from the bottom left corner, | |
| 847 | .\" of the page, whereas page printing co-ordinates are mapped | |
| 848 | .\" conventionally, from top left. | |
| 849 | .\" | |
| 850 | .\" Macro "pdf:href.sety" transforms the vertical position of the | |
| 851 | .\" last printed baseline, from the printing co-ordinate domain to | |
| 852 | .\" the PDF view domain. | |
| 853 | .\" | |
| 854 | .de pdf:href.sety | |
| 855 | .\" ---------------------------------------------------------------- | |
| 856 | .\" Usage: | |
| 857 | .\" .pdf:href.sety | |
| 858 | .\" ---------------------------------------------------------------- | |
| 859 | .\" | |
| 860 | .\" This computation yields the vertical view co-ordinate | |
| 861 | .\" in groff's basic units; don't forget to append grops' "u" | |
| 862 | .\" conversion operator, when writing the pdfmark! | |
| 863 | .\" | |
| 864 | .nr PDFPAGE.Y \\n(.p-\\n(nl+\\n[PDFHREF.VIEW.LEADING] | |
| 865 | .. | |
| 866 | .\" When we create a link "hot-spot" ... | |
| 867 | .\" "PDFHREF.LEADING" sets the distance above the top of the glyph | |
| 868 | .\" bounding boxes, in each line of link text, over which the link | |
| 869 | .\" hot-spot will extend, while "PDFHREF.HEIGHT" sets the hot-spot | |
| 870 | .\" height, PER LINE of text occupied by the reference. | |
| 871 | .\" | |
| 872 | .\" Since most fonts specify some leading space within the bounding | |
| 873 | .\" boxes of their glyphs, a better appearance may be achieved when | |
| 874 | .\" NEGATIVE leading is specified for link hot-spots; indeed, when | |
| 875 | .\" the default 10pt Times font is used, -1.0 point seems to be a | |
| 876 | .\" reasonable default value for "PDFHREF.LEADING" -- it may be | |
| 877 | .\" changed, if desired. | |
| 878 | .\" | |
| 879 | .\" "PDFHREF.HEIGHT" is initially set as one vertical spacing unit; | |
| 880 | .\" note that it is defined as a string, so it will adapt to changes | |
| 881 | .\" in the vertical spacing. Changing it is NOT RECOMMENDED. | |
| 882 | .\" | |
| 883 | .nr PDFHREF.LEADING -1.0p | |
| 884 | .ds PDFHREF.HEIGHT 1.0v | |
| 885 | .\" | |
| 886 | .\" PDF readers generally place a rectangular border around link | |
| 887 | .\" "hot-spots". Within text, this looks rather ugly, so we set | |
| 888 | .\" "PDFHREF.BORDER" to suppress it -- the three zeroes represent | |
| 889 | .\" the border parameters in the "/Border [0 0 0]" PDFMARK string, | |
| 890 | .\" and may be changed to any valid form, as defined in Adobe's | |
| 891 | .\" PDFMARK Reference Manual. | |
| 892 | .\" | |
| 893 | .ds PDFHREF.BORDER 0 0 0 | |
| 894 | .\" | |
| 895 | .\" "PDFHREF.COLOUR" (note British spelling) defines the colour to | |
| 896 | .\" be used for display of link "hot-spots". This will apply both | |
| 897 | .\" to borders, if used, and, by default to text; however, actual | |
| 898 | .\" text colour is set by "PDFHREF.TEXT.COLOUR", which may be reset | |
| 899 | .\" independently of "PDFHREF.COLOUR", to achieve contrasting text | |
| 900 | .\" and border colours. | |
| 901 | .\" | |
| 902 | .\" "PDFHREF.COLOUR" must be set to a sequence of three values, | |
| 903 | .\" each in the range 0.0 .. 1.0, representing the red, green, and | |
| 904 | .\" blue components of the colour specification in the RGB colour | |
| 905 | .\" domain, which is shared by "groff" and the PDF readers. | |
| 906 | .\" | |
| 907 | .ds PDFHREF.COLOUR 0.35 0.00 0.60 | |
| 908 | .defcolor pdf:href.colour rgb \*[PDFHREF.COLOUR] | |
| 909 | .\" | |
| 910 | .\" "PDFHREF.TEXT.COLOUR", on the other hand, is simply defined | |
| 911 | .\" using any "groff" colour name -- this default maps it to the | |
| 912 | .\" same colour value as "PDFHREF.COLOUR". | |
| 913 | .\" | |
| 914 | .ds PDFHREF.TEXT.COLOUR pdf:href.colour | |
| 915 | .\" | |
| 916 | .\" Accommodate users who prefer the American spelling, COLOR, to | |
| 917 | .\" the British spelling, COLOUR. | |
| 918 | .\" | |
| 919 | .als PDFHREF.COLOR PDFHREF.COLOUR | |
| 920 | .als PDFHREF.TEXT.COLOR PDFHREF.TEXT.COLOUR | |
| 921 | .\" | |
| 922 | .\" All PDF "Hypertext" reference capabilities are accessed | |
| 923 | .\" through the "pdfhref" macro | |
| 924 | .\" | |
| 925 | .de pdfhref | |
| 926 | .\" ----------------------------------------------------------------- | |
| 927 | .\" Usage: | |
| 928 | .\" .pdfhref <subcommand [options ...] [parameters ...]> ... | |
| 929 | .\" ----------------------------------------------------------------- | |
| 930 | .\" | |
| 931 | .if \\n[PDFOPMODE] \{\ | |
| 932 | .\" | |
| 933 | .\" Loop over all subcommands specified in the argument list | |
| 934 | .\" | |
| 935 | . while \\n(.$ \{\ | |
| 936 | . \" | |
| 937 | . \" Initially, assume each subcommand will complete successfully | |
| 938 | . \" | |
| 939 | . nr pdf:href.ok 1 | |
| 940 | . \" | |
| 941 | . \" Initialise -E and -X flags in the OFF state | |
| 942 | . \" | |
| 943 | . nr pdf:href-E 0 | |
| 944 | . nr pdf:href-X 0 | |
| 945 | . \" | |
| 946 | . \" Handle the case where subcommand is specified as "-class", | |
| 947 | . \" setting up appropriate macro aliases for subcommand handlers. | |
| 948 | . \" | |
| 949 | . if dpdf*href\\$1 .als pdf*href pdf*href\\$1 | |
| 950 | . if dpdf*href\\$1.link .als pdf*href.link pdf*href\\$1.link | |
| 951 | . if dpdf*href\\$1.file .als pdf*href.file pdf*href\\$1.file | |
| 952 | . \" | |
| 953 | . \" Repeat macro alias setup | |
| 954 | . \" for the case where the subcommand is specified as "class", | |
| 955 | . \" (without a leading hyphen) | |
| 956 | . \" | |
| 957 | . if dpdf*href-\\$1 .als pdf*href pdf*href-\\$1 | |
| 958 | . if dpdf*href-\\$1.link .als pdf*href.link pdf*href-\\$1.link | |
| 959 | . if dpdf*href-\\$1.file .als pdf*href.file pdf*href-\\$1.file | |
| 960 | . \" | |
| 961 | . \" Process one subcommand ... | |
| 962 | . \" | |
| 963 | . ie dpdf*href \{\ | |
| 964 | . \" | |
| 965 | . \" Subcommand "class" is recognised ... | |
| 966 | . \" discard the "class" code from the argument list, | |
| 967 | . \" set the initial argument count to swallow all arguments, | |
| 968 | . \" and invoke the selected subcommand handler. | |
| 969 | . \" | |
| 970 | . shift | |
| 971 | . nr pdf:argc \\n(.$ | |
| 972 | . pdf*href \\$@ | |
| 973 | . \" | |
| 974 | . \" When done, | |
| 975 | . \" discard all arguments actually consumed by the handler, | |
| 976 | . \" before proceeding to the next subcommand (if any). | |
| 977 | . \" | |
| 978 | . shift \\n[pdf:argc] | |
| 979 | . \} | |
| 980 | . el \{\ | |
| 981 | . \" | |
| 982 | . \" Subcommand "class" is not recognised ... | |
| 983 | . \" issue a warning, and discard the entire argument list, | |
| 984 | . \" so aborting this "pdfhref" invocation | |
| 985 | . \" | |
| 986 | . pdf:warn \\$0: undefined reference class '\\$1' ignored | |
| 987 | . shift \\n(.$ | |
| 988 | . \} | |
| 989 | . \" | |
| 990 | . \" Clean up temporary reference data, | |
| 991 | . \" to ensure it doesn't propagate to any future reference | |
| 992 | . \" | |
| 993 | . rm pdf*href pdf:href.link pdf:href.files | |
| 994 | . rr pdf:href-E pdf:href-X | |
| 995 | . pdf:href.options.clear | |
| 996 | . \} | |
| 997 | . rr pdf:href.ok | |
| 998 | . \} | |
| 999 | .. | |
| 1000 | .\" | |
| 1001 | .\" Macros "pdf:href.flag" and "pdf:href.option" | |
| 1002 | .\" provide a generic mechanism for switching on flag type options, | |
| 1003 | .\" and for decoding options with arguments, respectively | |
| 1004 | .\" | |
| 1005 | .de pdf:href.flag | |
| 1006 | .\" ---------------------------------------------------------------------- | |
| 1007 | .\" ---------------------------------------------------------------------- | |
| 1008 | .nr pdf:href\\$1 1 | |
| 1009 | .nr pdf:href.argc 1 | |
| 1010 | .. | |
| 1011 | .de pdf:href.option | |
| 1012 | .\" ---------------------------------------------------------------------- | |
| 1013 | .\" ---------------------------------------------------------------------- | |
| 1014 | .ds pdf:href\\$1 \\$2 | |
| 1015 | .nr pdf:href.argc 2 | |
| 1016 | .. | |
| 1017 | .\" | |
| 1018 | .\" Valid PDFHREF options are simply declared | |
| 1019 | .\" by aliasing option handlers to "pdf:href.option", | |
| 1020 | .\" or to "pdf:href.flag", as appropriate | |
| 1021 | .\" | |
| 1022 | .als pdf:href.opt-A pdf:href.option \" affixed text | |
| 1023 | .als pdf:href.opt-D pdf:href.option \" destination name | |
| 1024 | .als pdf:href.opt-E pdf:href.flag \" echo link descriptor | |
| 1025 | .als pdf:href.opt-F pdf:href.option \" remote file specifier | |
| 1026 | .als pdf:href.opt-N pdf:href.option \" reference name | |
| 1027 | .als pdf:href.opt-P pdf:href.option \" prefixed text | |
| 1028 | .als pdf:href.opt-T pdf:href.option \" bookmark "tag" | |
| 1029 | .als pdf:href.opt-X pdf:href.flag \" cross reference | |
| 1030 | .\" | |
| 1031 | .\" For references to another document file | |
| 1032 | .\" we also need to support OS dependent file name specifiers | |
| 1033 | .\" | |
| 1034 | .als pdf:href.opt-DF pdf:href.option \" /DOSFile specifier | |
| 1035 | .als pdf:href.opt-MF pdf:href.option \" /MacFile specifier | |
| 1036 | .als pdf:href.opt-UF pdf:href.option \" /UnixFile specifier | |
| 1037 | .als pdf:href.opt-WF pdf:href.option \" /WinFile specifier | |
| 1038 | .\" | |
| 1039 | .\" Macro "pdf:href.options.clear" ensures that ALL option | |
| 1040 | .\" argument strings are deleted, after "pdfhref" has completed | |
| 1041 | .\" all processing which depends on them | |
| 1042 | .\" | |
| 1043 | .de pdf:href.options.clear | |
| 1044 | .\" ----------------------------------------------------------------- | |
| 1045 | .\" Usage: | |
| 1046 | .\" .pdf:href.options.clear [option ...] | |
| 1047 | .\" ----------------------------------------------------------------- | |
| 1048 | .\" | |
| 1049 | .\" When an option list is specified ... | |
| 1050 | .\" | |
| 1051 | .ie \\n(.$ \{\ | |
| 1052 | . \" | |
| 1053 | . \" then loop through the list, | |
| 1054 | . \" deleting each specified option argument string in turn | |
| 1055 | . \" | |
| 1056 | . while \\n(.$ \{\ | |
| 1057 | . if dpdf:href-\\$1 .rm pdf:href-\\$1 | |
| 1058 | . shift | |
| 1059 | . \} | |
| 1060 | . \} | |
| 1061 | .\" | |
| 1062 | .\" ... but when no list is specified, | |
| 1063 | .\" then recurse, to clear all known option argument strings | |
| 1064 | .\" | |
| 1065 | .el .pdf:href.options.clear A D F N P T DF MF UF WF | |
| 1066 | .. | |
| 1067 | .\" | |
| 1068 | .\" "PDFHREF.INFO" establishes the content of the cross reference | |
| 1069 | .\" data record, which is exported via the "stderr" stream, when a | |
| 1070 | .\" cross reference anchor is created using a "pdfhref" macro request | |
| 1071 | .\" of the form | |
| 1072 | .\" | |
| 1073 | .\" .pdfhref M -N name -X text ... | |
| 1074 | .\" | |
| 1075 | .\" .ds PDFHREF.INFO \\*[PDFHREF.NAME] reference data ... | |
| 1076 | .\" | |
| 1077 | .ds PDFHREF.INFO page \\n% \\$* | |
| 1078 | .\" | |
| 1079 | .\" Macro "pdf*href-M" is the handler invoked by "pdfhref", when | |
| 1080 | .\" called with the "M" reference class specifier, to create a | |
| 1081 | .\" named cross reference mark, and to emit a cross reference | |
| 1082 | .\" data record, as specified by "PDFHREF.INFO". | |
| 1083 | .\" | |
| 1084 | .de pdf*href-M | |
| 1085 | .\" ----------------------------------------------------------------- | |
| 1086 | .\" Usage: | |
| 1087 | .\" .pdfhref M [-X] [-N name | -D name] [-E] descriptive text ... | |
| 1088 | .\" ----------------------------------------------------------------- | |
| 1089 | .\" | |
| 1090 | .\" Initially, declare the -D and -N string options as empty, | |
| 1091 | .\" so we avoid warning messages when we try to use them, and find | |
| 1092 | .\" that they are undefined. | |
| 1093 | .\" | |
| 1094 | .ds pdf:href-D | |
| 1095 | .ds pdf:href-N | |
| 1096 | .\" | |
| 1097 | .\" Parse, interpret, and strip any specified options from the | |
| 1098 | .\" argument list. (Note that only options with a declared handler | |
| 1099 | .\" will be processed; there is no provision for detecting invalid | |
| 1100 | .\" options -- anything which is not recognised is assumed to start | |
| 1101 | .\" the "descriptive text" component of the argument list). | |
| 1102 | .\" | |
| 1103 | .while dpdf:href.opt\\$1 \{\ | |
| 1104 | . pdf:href.opt\\$1 \\$@ | |
| 1105 | . shift \\n[pdf:href.argc] | |
| 1106 | . \} | |
| 1107 | .\" | |
| 1108 | .\" If we found "--", to mark the end of the options, | |
| 1109 | .\" then we should discard it. | |
| 1110 | .\" | |
| 1111 | .if '\\$1'--' .shift | |
| 1112 | .\" | |
| 1113 | .\" All PDF reference markers MUST be named. The name may have been | |
| 1114 | .\" supplied using the "-N Name" option, (or the "-D Name" option); | |
| 1115 | .\" if not, deduce it from the first "word" in the "descriptive text", | |
| 1116 | .\" if any, and set the marker -- if we still can't identify the name | |
| 1117 | .\" for the destination, then this marker will not be created. | |
| 1118 | .\" | |
| 1119 | .pdf*href.set \\*[pdf:href-N] \\*[pdf:href-D] \\$1 | |
| 1120 | .\" | |
| 1121 | .\" If we specified a cross reference, with the "-X" option, and the | |
| 1122 | .\" reference mark has been sucessfully created, then we now need to | |
| 1123 | .\" write the cross reference info to the STDERR stream | |
| 1124 | .\" | |
| 1125 | .if \\n[pdf:href-X] .pdf*href.export \\*[PDFHREF.INFO] | |
| 1126 | .\" | |
| 1127 | .\" Irrespective of whether this marker is created, or not, | |
| 1128 | .\" the descriptive text will be copied to the groff output stream, | |
| 1129 | .\" provided the "-E" option was specified | |
| 1130 | .\" | |
| 1131 | .if \\n[pdf:href-E] \&\\$* | |
| 1132 | .. | |
| 1133 | .\" | |
| 1134 | .de pdf*href.set | |
| 1135 | .\" ---------------------------------------------------------------------- | |
| 1136 | .\" ---------------------------------------------------------------------- | |
| 1137 | .pdf*href.map.init | |
| 1138 | .ie \\n(.$ \{\ | |
| 1139 | . \" | |
| 1140 | . \" a marker name has been supplied ... | |
| 1141 | . \" if we are formatting for immediate output, | |
| 1142 | . \" emit PDFMARK code to establish the associated view | |
| 1143 | . \" | |
| 1144 | . ie '\\n(.z'' \{\ | |
| 1145 | . pdf:href.sety | |
| 1146 | . pdfmark /Dest /\\$1 /View [\\*[PDFHREF.VIEW]] /DEST | |
| 1147 | . ds PDFHREF.NAME \\$1 | |
| 1148 | . rr PDFPAGE.Y | |
| 1149 | . \} | |
| 1150 | . \" | |
| 1151 | . \" but, when formatting a diversion ... | |
| 1152 | . \" delay output of the PDFMARK code, until the diversion | |
| 1153 | . \" is eventually written out | |
| 1154 | . \" | |
| 1155 | . el \!.\\$0 \\$@ | |
| 1156 | . \" | |
| 1157 | . \" check if we also need to emit cross reference data | |
| 1158 | . \" (caller will do this if "pdf:href-X" is set, but it is | |
| 1159 | . \" not necessary, when "pdf:href.map" already exists) | |
| 1160 | . \" | |
| 1161 | . if dpdf:href.map .nr pdf:href-X 0 | |
| 1162 | . \} | |
| 1163 | .el \{\ | |
| 1164 | . \" marker is unnamed ... | |
| 1165 | . \" issue error message; do not emit reference data | |
| 1166 | . \" | |
| 1167 | . pdf:warn pdfhref destination marker must be named | |
| 1168 | . nr pdf:href-X 0 | |
| 1169 | . \} | |
| 1170 | .. | |
| 1171 | .de pdf*href.export | |
| 1172 | .\" | |
| 1173 | .\" Called ONLY by "pdf*href-M", | |
| 1174 | .\" this macro ensures that the emission of exported reference data | |
| 1175 | .\" is synchronised with the placement of the reference mark, | |
| 1176 | .\" especially when the mark is defined within a diversion. | |
| 1177 | .\" | |
| 1178 | .ie '\\n(.z'' .tm gropdf-info:href \\*[PDFHREF.NAME] \\$* | |
| 1179 | .el \!.\\$0 \\$@ | |
| 1180 | .. | |
| 1181 | .\" | |
| 1182 | .\" Macro "pdf*href-D" is invoked when "pdfhref" is called | |
| 1183 | .\" with the "D" reference class specifier; it provides a | |
| 1184 | .\" standardised mechanism for interpreting reference data | |
| 1185 | .\" exported by the "M" reference class, and may be used | |
| 1186 | .\" to directly define external reference data, without the | |
| 1187 | .\" use of "M" reference class designators in the source | |
| 1188 | .\" document. | |
| 1189 | .\" | |
| 1190 | .de pdf*href-D | |
| 1191 | .ds pdf:href-N | |
| 1192 | .\" | |
| 1193 | .\" Parse, interpret, and strip any specified options from the | |
| 1194 | .\" argument list. (Note that only options with a declared handler | |
| 1195 | .\" will be processed; there is no provision for detecting invalid | |
| 1196 | .\" options -- anything which is not recognised is assumed to start | |
| 1197 | .\" the "descriptive text" component of the argument list). | |
| 1198 | .\" | |
| 1199 | .while dpdf:href.opt\\$1 \{\ | |
| 1200 | . pdf:href.opt\\$1 \\$@ | |
| 1201 | . shift \\n[pdf:href.argc] | |
| 1202 | . \} | |
| 1203 | .\" | |
| 1204 | .\" If we found "--", to mark the end of the options, | |
| 1205 | .\" then we should discard it. | |
| 1206 | .\" | |
| 1207 | .if '\\$1'--' .shift | |
| 1208 | .\" | |
| 1209 | .ie '\\*[pdf:href-N]'' \{\ | |
| 1210 | . pdf:warn pdfhref defined reference requires a name | |
| 1211 | . \} | |
| 1212 | .el \{\ | |
| 1213 | . ds pdf:href(\\*[pdf:href-N]).info \\$* | |
| 1214 | . \} | |
| 1215 | .. | |
| 1216 | .\" | |
| 1217 | .\" Macro "pdf*href-F" is invoked when "pdfhref" is called | |
| 1218 | .\" with the "F" reference class specifier; it allows the user | |
| 1219 | .\" to provide an alternative interpreter macro, which will be | |
| 1220 | .\" called when a "PDFHREF.INFO" record is retrieved to define | |
| 1221 | .\" the text of a cross reference link "hot spot". | |
| 1222 | .\" | |
| 1223 | .de pdf*href-F | |
| 1224 | .\" ---------------------------------------------------------------- | |
| 1225 | .\" Usage: | |
| 1226 | .\" .pdfhref F [macro-name] | |
| 1227 | .\" ---------------------------------------------------------------- | |
| 1228 | .\" | |
| 1229 | .\" Set macro specified by "macro-name" as the format interpreter | |
| 1230 | .\" for parsing "PDFHREF.INFO" records; if "macro-name" is omitted, | |
| 1231 | .\" or is specified as the reserved name "default", then use the | |
| 1232 | .\" default format parser, "pdf*href.format", defined below. | |
| 1233 | .\" | |
| 1234 | .if '\\$1'default' .shift \\n(.$ | |
| 1235 | .ie \\n(.$ .als pdf*href.format \\$1 | |
| 1236 | .el .als pdf*href.format pdf*href.default | |
| 1237 | .nr pdf:argc 1 | |
| 1238 | .. | |
| 1239 | .\" The default reference formatting macro is defined below. | |
| 1240 | .\" It parses the "PDFHREF.INFO" record specific to each reference, | |
| 1241 | .\" recognising the keywords "file", "page" and "section", when they | |
| 1242 | .\" appear in initial key/value pairs, replacing the key/value pair | |
| 1243 | .\" with "PDFHREF.FILEREF", "PDFHREF.PAGEREF" or "PDFHREF.SECTREF" | |
| 1244 | .\" respectively; any additional data in the "PDFHREF.INFO" record | |
| 1245 | .\" is enclosed in typographic double quotes, and the parsed record | |
| 1246 | .\" is appended to "PDFHREF.PREFIX", to be returned as the formatted | |
| 1247 | .\" reference text. | |
| 1248 | .\" | |
| 1249 | .\" Default definitions for the reference strings "PDFHREF.PREFIX", | |
| 1250 | .\" "PDFHREF.FILEREF", "PDFHREF.PAGEREF" and "PDFHREF.SECTREF" are | |
| 1251 | .\" provided, in the English language. Users may substitute any | |
| 1252 | .\" desired alternative definitions, for example, when formatting | |
| 1253 | .\" documents in other languages. In each case, "\\$1" may be used | |
| 1254 | .\" in the substitution, to represent the "value" component of the | |
| 1255 | .\" respective key/value pair specified in the "PDFHREF.INFO" record. | |
| 1256 | .\" | |
| 1257 | .ds PDFHREF.PREFIX see | |
| 1258 | .ds PDFHREF.PAGEREF page \\$1, | |
| 1259 | .ds PDFHREF.SECTREF section \\$1, | |
| 1260 | .ds PDFHREF.FILEREF \\$1 | |
| 1261 | .\" | |
| 1262 | .de pdf*href.format | |
| 1263 | .\" ----------------------------------------------------------------- | |
| 1264 | .\" Usage: (to be called ONLY by "pdfhref") | |
| 1265 | .\" .pdf*href.format cross reference data ... | |
| 1266 | .\" ----------------------------------------------------------------- | |
| 1267 | .\" | |
| 1268 | .\" This macro is responsible for defining the strings "PDFHREF.TEXT" | |
| 1269 | .\" and "PDFHREF.DESC", which are used by the "pdfhref" macro, as the | |
| 1270 | .\" basis for generating the text content of a link "hot spot"; (any | |
| 1271 | .\" user specified alternate formatter MUST do likewise). | |
| 1272 | .\" | |
| 1273 | .\" Note that "PDFHREF.TEXT" defines the overall format for the "link | |
| 1274 | .\" text", while "PDFHREF.DESC" is the descriptive component thereof. | |
| 1275 | .\" | |
| 1276 | .\" This default implementation, subject to user customisation of the | |
| 1277 | .\" "internationalisation" strings defined above, formats "hot spots" | |
| 1278 | .\" of the style | |
| 1279 | .\" | |
| 1280 | .\" see page N, section S, "descriptive text ..." | |
| 1281 | .\" | |
| 1282 | .ds PDFHREF.TEXT \\*[PDFHREF.PREFIX] | |
| 1283 | .while d\\$0.\\$1 \{\ | |
| 1284 | . \\$0.\\$1 "\\$2" | |
| 1285 | . shift 2 | |
| 1286 | . \} | |
| 1287 | .\" | |
| 1288 | .\" Retrieve the descriptive text from the cross reference data, | |
| 1289 | .\" ONLY IF no overriding description has been set by the calling | |
| 1290 | .\" "pdfhref" macro invocation. | |
| 1291 | .\" | |
| 1292 | .if \\n(.$ .if !dPDFHREF.DESC .ds PDFHREF.DESC \\$* | |
| 1293 | .\" | |
| 1294 | .\" Augment "PDFHREF.TEXT" so the descriptive text will be included | |
| 1295 | .\" in the text of the formatted reference | |
| 1296 | .\" | |
| 1297 | .if dPDFHREF.DESC .as PDFHREF.TEXT " \(lq\\\\*[PDFHREF.DESC]\(rq | |
| 1298 | .\" | |
| 1299 | .\" Finally, suppress any leading spaces, | |
| 1300 | .\" which may have been included in the PDFHREF.TEXT definition. | |
| 1301 | .\" | |
| 1302 | .ds PDFHREF.TEXT \\*[PDFHREF.TEXT] | |
| 1303 | .. | |
| 1304 | .de pdf*href.format.file | |
| 1305 | .\" ---------------------------------------------------------------------- | |
| 1306 | .\" Include a file identifier in a formatted reference. | |
| 1307 | .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the | |
| 1308 | .\" reference data includes an initial file identifier tuple. | |
| 1309 | .\" ---------------------------------------------------------------------- | |
| 1310 | .\" | |
| 1311 | .as PDFHREF.TEXT " \\*[PDFHREF.FILEREF] | |
| 1312 | .. | |
| 1313 | .de pdf*href.format.page | |
| 1314 | .\" ---------------------------------------------------------------------- | |
| 1315 | .\" Include a page number in a formatted reference. | |
| 1316 | .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the | |
| 1317 | .\" reference data includes an initial page number tuple. | |
| 1318 | .\" ---------------------------------------------------------------------- | |
| 1319 | .\" | |
| 1320 | .as PDFHREF.TEXT " \\*[PDFHREF.PAGEREF] | |
| 1321 | .. | |
| 1322 | .de pdf*href.format.section | |
| 1323 | .\" ---------------------------------------------------------------------- | |
| 1324 | .\" Include a section number in a formatted reference. | |
| 1325 | .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the | |
| 1326 | .\" reference data includes an initial section number tuple. | |
| 1327 | .\" ---------------------------------------------------------------------- | |
| 1328 | .\" | |
| 1329 | .as PDFHREF.TEXT " \\*[PDFHREF.SECTREF] | |
| 1330 | .. | |
| 1331 | .\" | |
| 1332 | .\" Make "pdf*href.format" the default cross reference formatter | |
| 1333 | .\" | |
| 1334 | .als pdf*href.default pdf*href.format | |
| 1335 | .\" | |
| 1336 | .\" | |
| 1337 | .\" Macro "pdf*href" provides a generic mechanism for placing link | |
| 1338 | .\" "hot-spots" in a PDF document. ALL "pdfhref" class macros which | |
| 1339 | .\" create "hot-spots" are aliased to this macro; each must also have | |
| 1340 | .\" an appropriately aliased definition for "pdf*href.template". | |
| 1341 | .\" | |
| 1342 | .de pdf*href | |
| 1343 | .\" ------------------------------------------------------------------ | |
| 1344 | .\" Usage: | |
| 1345 | .\" .pdf*href class [options ...] [link text ...] | |
| 1346 | .\" ------------------------------------------------------------------ | |
| 1347 | .\" | |
| 1348 | .\" First, we initialise an empty string, which will be affixed to | |
| 1349 | .\" the end of the "link text". (This is needed to cancel the effect | |
| 1350 | .\" of a "\c" escape, which is placed at the end of the "link text" | |
| 1351 | .\" to support the "-A" option -- any text supplied by the user, when | |
| 1352 | .\" the "-A" option is specified, will replace this empty string). | |
| 1353 | .\" | |
| 1354 | .ds pdf:href-A | |
| 1355 | .\" | |
| 1356 | .\" Now we interpret, and remove any specified options from the | |
| 1357 | .\" argument list. (Note that only options with a declared handler | |
| 1358 | .\" will be processed; there is no provision for detecting invalid | |
| 1359 | .\" options -- anything which is not recognised is assumed to start | |
| 1360 | .\" the "link text" component of the argument list). | |
| 1361 | .\" | |
| 1362 | .while dpdf:href.opt\\$1 \{\ | |
| 1363 | . pdf:href.opt\\$1 \\$@ | |
| 1364 | . shift \\n[pdf:href.argc] | |
| 1365 | . \} | |
| 1366 | .\" | |
| 1367 | .\" If we found "--", to mark the end of the options, then we should | |
| 1368 | .\" discard it. | |
| 1369 | .\" | |
| 1370 | .if '\\$1'--' .shift | |
| 1371 | .\" | |
| 1372 | .\" All PDF link classes REQUIRE a named destination. This may have | |
| 1373 | .\" been supplied using the "-D Name" option, but, if not, deduce it | |
| 1374 | .\" from the first "word" in the "link text", if any -- if we still | |
| 1375 | .\" can't identify the destination, then set "pdf:href.ok" to zero, | |
| 1376 | .\" so this link will not be created. | |
| 1377 | .\" | |
| 1378 | .if !dpdf:href-D .pdf:href.option -D \\$1 | |
| 1379 | .if '\\*[pdf:href-D]'' \{\ | |
| 1380 | . pdf:error pdfhref has no destination | |
| 1381 | . nr pdf:href.ok 0 | |
| 1382 | . \} | |
| 1383 | .\" | |
| 1384 | .\" Some PDF link classes support a "/File (FilePathName)" argument. | |
| 1385 | .\" | |
| 1386 | .if dpdf*href.file \{\ | |
| 1387 | . \" | |
| 1388 | . \" When this is supported, it may be specified by supplying | |
| 1389 | . \" the "-F FileName" option, which is captured in "pdf:href-F". | |
| 1390 | . \" | |
| 1391 | . if dpdf:href-F \{\ | |
| 1392 | . \" | |
| 1393 | . \" the /File key is present, so set up the link specification | |
| 1394 | . \" to establish the reference to the specified file | |
| 1395 | . \" | |
| 1396 | . als pdf*href.link pdf*href.file | |
| 1397 | . ds pdf:href.files /File (\\*[pdf:href-F]) | |
| 1398 | . \" | |
| 1399 | . \" in addition to the /File key, | |
| 1400 | . \" there may also be platform dependent alternate file names | |
| 1401 | . \" | |
| 1402 | . if dpdf:href-DF .as pdf:href.files " /DOSFile (\\*[pdf:href-DF]) | |
| 1403 | . if dpdf:href-MF .as pdf:href.files " /MacFile (\\*[pdf:href-MF]) | |
| 1404 | . if dpdf:href-UF .as pdf:href.files " /UnixFile (\\*[pdf:href-UF]) | |
| 1405 | . if dpdf:href-WF .as pdf:href.files " /WinFile (\\*[pdf:href-WF]) | |
| 1406 | . \} | |
| 1407 | . \" In some cases, the "/File" key is REQUIRED. | |
| 1408 | . \" We will know it is missing, if "pdf*href.link" is not defined. | |
| 1409 | . \" | |
| 1410 | . if !dpdf*href.link \{\ | |
| 1411 | . \" | |
| 1412 | . \" When a REQUIRED "/File" key specification is not supplied, | |
| 1413 | . \" then complain, and set "pdf:href.ok" to abort the creation | |
| 1414 | . \" of the current reference. | |
| 1415 | . \" | |
| 1416 | . pdf:error pdfhref: required -F specification omitted | |
| 1417 | . nr pdf:href.ok 0 | |
| 1418 | . \} | |
| 1419 | . \" Now, we have no further use for "pdf*href.file". | |
| 1420 | . \" | |
| 1421 | . rm pdf*href.file | |
| 1422 | . \} | |
| 1423 | .\" | |
| 1424 | .\" Now, initialise a string, defining the PDFMARK code sequence | |
| 1425 | .\" to create the reference, using the appropriate type indicators. | |
| 1426 | .\" | |
| 1427 | .ds pdf:href.link /Subtype /Link \\*[pdf*href.link] | |
| 1428 | .\" | |
| 1429 | .\" And now, we have no further use for "pdf*href.link". | |
| 1430 | .\" | |
| 1431 | .rm pdf*href.link | |
| 1432 | .\" | |
| 1433 | .\" If the user specified any "link prefix" text, (using the "-P text" | |
| 1434 | .\" option), then emit it BEFORE processing the "link text" itself. | |
| 1435 | .\" | |
| 1436 | .if dpdf:href-P \&\\*[pdf:href-P]\c | |
| 1437 | .ie \\n[pdf:href.ok] \{\ | |
| 1438 | . \" | |
| 1439 | . \" This link is VALID (so far as we can determine) ... | |
| 1440 | . \" Modify the "link text" argument specification, as required, | |
| 1441 | . \" to include any pre-formatted cross reference information | |
| 1442 | . \" | |
| 1443 | . ie \\n(.$ \{\ | |
| 1444 | . \" | |
| 1445 | . \" One or more "link text" argument(s) are present, | |
| 1446 | . \" so, set the link description from the argument(s) ... | |
| 1447 | . \" | |
| 1448 | . ds PDFHREF.DESC \\\\$* | |
| 1449 | . ie \\n[pdf:href-X] \{\ | |
| 1450 | . \" | |
| 1451 | . \" ... and, when the "-X" flag is set, | |
| 1452 | . \" also include formatted location information, | |
| 1453 | . \" derived from the cross reference record. | |
| 1454 | . \" | |
| 1455 | . pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info] | |
| 1456 | . \} | |
| 1457 | . el \{\ | |
| 1458 | . \" ... but, when the "-X" flag is NOT set, | |
| 1459 | . \" use only the argument(s) as the entire content | |
| 1460 | . \" of the "link text" | |
| 1461 | . \" | |
| 1462 | . rn PDFHREF.DESC PDFHREF.TEXT | |
| 1463 | . \} | |
| 1464 | . \} | |
| 1465 | . el \{\ | |
| 1466 | . \" No "link text" arguments are present, | |
| 1467 | . \" so, format the cross reference record to define | |
| 1468 | . \" the content of the "link text". | |
| 1469 | . \" | |
| 1470 | . pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info] | |
| 1471 | . \} | |
| 1472 | . \" Apply border and colour specifications to the PDFMARK string | |
| 1473 | . \" definition, as required. | |
| 1474 | . \" | |
| 1475 | . if dPDFHREF.BORDER .as pdf:href.link " /Border [\\*[PDFHREF.BORDER]] | |
| 1476 | . if dPDFHREF.COLOUR .as pdf:href.link " /Color [\\*[PDFHREF.COLOUR]] | |
| 1477 | . \" | |
| 1478 | . \" Emit the "link text", in its appropriate colour, marking the | |
| 1479 | . \" limits of its bounding box(es), as the before and after output | |
| 1480 | . \" text positions. | |
| 1481 | . \" | |
| 1482 | . pdf*href.mark.begin "\\*[pdf:href.link]" | |
| 1483 | . if dPDFHREF.COLOUR .defcolor pdf:href.colour rgb \\*[PDFHREF.COLOUR] | |
| 1484 | . nop \&\m[\\*[PDFHREF.TEXT.COLOUR]]\\*[PDFHREF.TEXT]\m[]\c | |
| 1485 | . pdf*href.mark.end | |
| 1486 | . \" | |
| 1487 | . \" Clean up the temporary registers and strings, used to | |
| 1488 | . \" compute the "hot-spot" bounds, and format the reference, | |
| 1489 | . \" | |
| 1490 | . rm PDFHREF.DESC PDFHREF.TEXT | |
| 1491 | . \} | |
| 1492 | .\" | |
| 1493 | .\" But when we identify an INVALID link ... | |
| 1494 | .\" We simply emit the "link text", with no colour change, no border, | |
| 1495 | .\" and no associated "hot-spot". | |
| 1496 | .\" | |
| 1497 | .el \&\\$*\c | |
| 1498 | .\" | |
| 1499 | .\" And then, if the user specified any affixed text, (using the | |
| 1500 | .\" "-A text" option), we tack it on at the end. | |
| 1501 | .\" | |
| 1502 | .nop \&\\*[pdf:href-A] | |
| 1503 | .. | |
| 1504 | .de pdf*href.map.init | |
| 1505 | .\" ---------------------------------------------------------------------- | |
| 1506 | .\" ---------------------------------------------------------------------- | |
| 1507 | .\" | |
| 1508 | .if dpdf:href.map-1 \{\ | |
| 1509 | . \" | |
| 1510 | . \" We have a reference map, but we haven't started to parse it yet. | |
| 1511 | . \" This must be the first map reference in pass 2, so we need to | |
| 1512 | . \" "kick-start" the parsing process, by loading the first indexed | |
| 1513 | . \" sub-map into the global map. | |
| 1514 | . \" | |
| 1515 | . rn pdf:href.map-1 pdf:href.map | |
| 1516 | . als pdf:href.map.internal pdf:href.map | |
| 1517 | . nr pdf:href.map.index 1 1 | |
| 1518 | . \} | |
| 1519 | .als pdf*href.map.init pdf*href.mark.idle | |
| 1520 | .. | |
| 1521 | .\" | |
| 1522 | .\" "pdf*href-Z" is used to add link co-ordinate entries to the | |
| 1523 | .\" "pdf:href.map". Primarily, it is used by the "pdfroff" formatter, | |
| 1524 | .\" to pass link co-ordinate data from one "groff" formatting pass to | |
| 1525 | .\" the next, and is not generally useful to the end user. | |
| 1526 | .\" | |
| 1527 | .de pdf*href-Z | |
| 1528 | .\" ---------------------------------------------------------------------- | |
| 1529 | .\" Usage: | |
| 1530 | .\" .pdfhref Z page-index x-displacement y-displacement | |
| 1531 | .\" Where: | |
| 1532 | .\" page-index is the reference mark's page number | |
| 1533 | .\" x-displacement is its offset from the left edge of the page | |
| 1534 | .\" y-displacement is its offset from the top edge of the page | |
| 1535 | .\" ( both displacement values are expressed in basic groff units, ) | |
| 1536 | .\" ( and measured perpendicular to their respective page edges. ) | |
| 1537 | .\" ---------------------------------------------------------------------- | |
| 1538 | .\" | |
| 1539 | .ie \\n(.$=3 .ds pdf:href.map-\\n+[pdf*href-Z.index] \\$* | |
| 1540 | .el .pdf:error pdfhref Z operator expects exactly three arguments | |
| 1541 | .. | |
| 1542 | .\" Initialise the auto-incrementing "pdf*href-Z.index" register, | |
| 1543 | .\" to ensure that sub-map numbering starts at 1. | |
| 1544 | .\" | |
| 1545 | .nr pdf*href-Z.index 0 1 | |
| 1546 | .\" | |
| 1547 | .de pdf*href.map.read | |
| 1548 | .\" ---------------------------------------------------------------------- | |
| 1549 | .\" Usage: (internal use only): | |
| 1550 | .\" .pdf*href.map.read co-ordinate name list ... | |
| 1551 | .\" ---------------------------------------------------------------------- | |
| 1552 | .\" | |
| 1553 | .\" Reads values from "pdf:href.map" to each named register, in turn | |
| 1554 | .\" Reading to "null" discards the corresponding value in "pdf:href.map" | |
| 1555 | .\" | |
| 1556 | .while \\n(.$ \{\ | |
| 1557 | . \" | |
| 1558 | . \" Loop over all registers named in the argument list, | |
| 1559 | . \" assigning values from "pdf:href.map" to each in turn. | |
| 1560 | . \" | |
| 1561 | . pdf:pop nr pdf:\\$1 pdf:href.map.internal | |
| 1562 | . if !dpdf:href.map.internal \{\ | |
| 1563 | . \" | |
| 1564 | . \" We ran out of map references in the current sub-map, | |
| 1565 | . \" so move on to the next indexed sub-map, if any. | |
| 1566 | . \" | |
| 1567 | . if dpdf:href.map-\\n+[pdf:href.map.index] \{\ | |
| 1568 | . rn pdf:href.map-\\n[pdf:href.map.index] pdf:href.map | |
| 1569 | . als pdf:href.map.internal pdf:href.map | |
| 1570 | . \} | |
| 1571 | . \} | |
| 1572 | . \" | |
| 1573 | . \" Proceed to the next named co-ordinate, (if any), specified | |
| 1574 | . \" in the argument list. | |
| 1575 | . \" | |
| 1576 | . shift | |
| 1577 | . \} | |
| 1578 | .\" | |
| 1579 | .\" Discard any assignments to a register named "null" | |
| 1580 | .\" | |
| 1581 | .rr pdf:null | |
| 1582 | .. | |
| 1583 | .de pdf*href.mark.begin | |
| 1584 | .\" ---------------------------------------------------------------------- | |
| 1585 | .\" ---------------------------------------------------------------------- | |
| 1586 | .pdf*href.map.init | |
| 1587 | .ie dpdf:href.map \{\ | |
| 1588 | . \" | |
| 1589 | . \" Once we have established a document reference map, | |
| 1590 | . \" then this, and all subsequent calls to "pdf*href.mark.begin", | |
| 1591 | . \" may be redirected to the reference mark resolver, and the | |
| 1592 | . \" "pdf*href.mark.end" macro has nothing further to do. | |
| 1593 | . \" | |
| 1594 | . pdf*href.mark.resolve \\$@ | |
| 1595 | . rn pdf*href.mark.resolve pdf*href.mark.begin | |
| 1596 | . als pdf*href.mark.end pdf*href.mark.idle | |
| 1597 | . \} | |
| 1598 | .el \{\ | |
| 1599 | . \" Since we don't yet have a document reference map, the | |
| 1600 | . \" reference mark resolver will not work, in this pass of the | |
| 1601 | . \" formatter; this, and all subsequent calls to "pdf*href.mark.begin", | |
| 1602 | . \" may be redirected to "pdf*href.mark.end", which is responsible | |
| 1603 | . \" for emitting the reference mark data to be incorporated into | |
| 1604 | . \" the reference map in a subsequent formatting pass. | |
| 1605 | . \" | |
| 1606 | . pdf*href.mark.end | |
| 1607 | . als pdf*href.mark.begin pdf*href.mark.end | |
| 1608 | . \} | |
| 1609 | .. | |
| 1610 | .de pdf*href.mark.resolve | |
| 1611 | .\" ---------------------------------------------------------------------- | |
| 1612 | .\" ---------------------------------------------------------------------- | |
| 1613 | .ie '\\n(.z'' \{\ | |
| 1614 | . ds pdf:href.link \\$1 | |
| 1615 | . nr pdf:urx \\n(.o+\\n(.l | |
| 1616 | . pdf*href.map.read spg llx ury epg urx.end lly.end | |
| 1617 | . ie \\n[pdf:spg]=\\n[pdf:epg] \{\ | |
| 1618 | . \" | |
| 1619 | . \" This link is entirely contained on a single page ... | |
| 1620 | . \" emit the text, which defines the content of the link region, | |
| 1621 | . \" then make it active. | |
| 1622 | . \" | |
| 1623 | . pdf*href.mark.emit 1 \\n[pdf:urx.end] | |
| 1624 | . if \\n[pdf:lly]<\\n[pdf:lly.end] \{\ | |
| 1625 | . \" | |
| 1626 | . \" This link spans multiple output lines; we must save its | |
| 1627 | . \" original end co-ordinates, then define a new intermediate | |
| 1628 | . \" end point, to create a PDFMARK "hot-spot" extending from | |
| 1629 | . \" the start of the link to the end if its first line. | |
| 1630 | . \" | |
| 1631 | . nr pdf:ury +1v | |
| 1632 | . nr pdf:llx \\n(.o+\\n[.in] | |
| 1633 | . nr pdf:lly \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT] | |
| 1634 | . if \\n[pdf:ury]<\\n[pdf:lly] \{\ | |
| 1635 | . nr pdf:lly +\\*[PDFHREF.HEIGHT]-1v | |
| 1636 | . pdf*href.mark.emit 2 | |
| 1637 | . nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT] | |
| 1638 | . \} | |
| 1639 | . pdf*href.mark.emit 0 \\n[pdf:urx.end] | |
| 1640 | . \} | |
| 1641 | . pdf*href.mark.flush | |
| 1642 | . \} | |
| 1643 | . el \{\ | |
| 1644 | . \" This link is split across a page break, so ... | |
| 1645 | . \" We must mark the "hot-spot" region on the current page, | |
| 1646 | . \" BEFORE we emit the link text, as we will have moved off | |
| 1647 | . \" this page, by the time the text has been output. | |
| 1648 | . \" | |
| 1649 | . \" First step: define the region from the start of the link, | |
| 1650 | . \" to the end of its first line. | |
| 1651 | . \" | |
| 1652 | . pdf*href.mark.emit 1 \\n[pdf:urx] | |
| 1653 | . \" | |
| 1654 | . \" All additional regions MUST align with the left margin. | |
| 1655 | . \" | |
| 1656 | . nr pdf:llx \\n(.o+\\n[.in] | |
| 1657 | . \" | |
| 1658 | . \" If the current page can accomodate more than the current line, | |
| 1659 | . \" then it will include a second active region for this link; this | |
| 1660 | . \" will extend from just below the current line to the end of page | |
| 1661 | . \" trap, if any, or the bottom of the page otherwise, and occupy | |
| 1662 | . \" the full width of the page, between the margins. | |
| 1663 | . \" | |
| 1664 | . nr pdf:ury +1v | |
| 1665 | . pdf*href.mark.emit 3 | |
| 1666 | . \" | |
| 1667 | . \" We now need a page transition trap, to map the active link | |
| 1668 | . \" region(s), which overflow on to the following page(s); (the | |
| 1669 | . \" handler for this trap MUST have been previously installed). | |
| 1670 | . \" | |
| 1671 | . ie dpdf*href.mark.hook \{\ | |
| 1672 | . \" | |
| 1673 | . \" The page transition trap handler has been installed, | |
| 1674 | . \" so we may activate both it, and also the appropriate | |
| 1675 | . \" termination handler, to deactivate it when done. | |
| 1676 | . \" | |
| 1677 | . als pdf*href.mark.hook pdf*href.mark.trap | |
| 1678 | . \" | |
| 1679 | . \" Now we set up "pdf:epg" to count the number of page breaks | |
| 1680 | . \" which this link will span, and emit the link text, leaving | |
| 1681 | . \" the page trap macro to map active regions on intervening | |
| 1682 | . \" pages, which are included in the link. | |
| 1683 | . \" | |
| 1684 | . nr pdf:epg -\\n[pdf:spg] 1 | |
| 1685 | . \} | |
| 1686 | . el \{\ | |
| 1687 | . \" There was no handler initialised for the page trap, | |
| 1688 | . \" so we are unable to map the active regions for this link; | |
| 1689 | . \" we may discard the remaining map data for this link, | |
| 1690 | . \" and issue a diagnostic. | |
| 1691 | . \" | |
| 1692 | . pdf:error pdfhref: link dissociated at page break (trap not initialised) | |
| 1693 | . if dPDFHREF.BROKEN.COLOR \{\ | |
| 1694 | . \" | |
| 1695 | . \" The user may opt to have such broken links highlighted. | |
| 1696 | . \" We use "PDFHREF.BROKEN.COLOUR" to specify this requirement, | |
| 1697 | . \" but the user may prefer the American spelling, so we will | |
| 1698 | . \" handle both as equivalent. | |
| 1699 | . \" | |
| 1700 | . als PDFHREF.BROKEN.COLOUR PDFHREF.BROKEN.COLOR | |
| 1701 | . \} | |
| 1702 | . if dPDFHREF.BROKEN.COLOUR \{\ | |
| 1703 | . if dPDFHREF.COLOUR .als PDFHREF.COLOUR PDFHREF.BROKEN.COLOUR | |
| 1704 | . \} | |
| 1705 | . \} | |
| 1706 | . \} | |
| 1707 | . \} | |
| 1708 | .el \!.\\$0 \\$@ | |
| 1709 | .. | |
| 1710 | .\" | |
| 1711 | .\" Macro "pdf*href.mark.emit" is called only by "pdf*href". It is | |
| 1712 | .\" responsible for emitting the PDFMARK code, to establish the | |
| 1713 | .\" "hot-spot" region associated with a document or resource link. | |
| 1714 | .\" | |
| 1715 | .de pdf*href.mark.emit | |
| 1716 | .\" ---------------------------------------------------------------------- | |
| 1717 | .\" Usage: | |
| 1718 | .\" .pdf*href.mark.emit <action> [<end-urx>] | |
| 1719 | .\" <action> == 0 --> normal operation -- link height = 1 line | |
| 1720 | .\" <action> == 1 --> start of link -- add leading above text | |
| 1721 | .\" <action> == 2 --> overtall link -- set intermediate baseline | |
| 1722 | .\" <action> == 3 --> split link -- break at bottom of page | |
| 1723 | .\" ---------------------------------------------------------------------- | |
| 1724 | .\" | |
| 1725 | .if \\$1=1 \{\ | |
| 1726 | . \" | |
| 1727 | . \" Initialising a new link region ... | |
| 1728 | . \" Some different versions of "groff" disagree about the vertical | |
| 1729 | . \" displacement of "opminy", as emitted by "\O1|\h'-\w"|"u'\O2\c", | |
| 1730 | . \" relative to the current text baseline. Therefore, recompute | |
| 1731 | . \" the link displacement, independently of "opminy". | |
| 1732 | . \" | |
| 1733 | . mk pdf:ury.base | |
| 1734 | . while \\n[pdf:ury.base]<\\n[pdf:ury] .nr pdf:ury.base +1v | |
| 1735 | . nr pdf:ury.base -1m+\\n[PDFHREF.LEADING] | |
| 1736 | . \" | |
| 1737 | . \" adjust the end-point vertical displacement by the same offset, | |
| 1738 | . \" and then relocate the link starting point to its new displacement, | |
| 1739 | . \" as established by this base line relative computation. | |
| 1740 | . \" | |
| 1741 | . nr pdf:lly.end +\\n[pdf:ury.base]-\\n[pdf:ury]+\\*[PDFHREF.HEIGHT] | |
| 1742 | . rnn pdf:ury.base pdf:ury | |
| 1743 | . \} | |
| 1744 | .if \\$1<2 \{\ | |
| 1745 | . \" | |
| 1746 | . \" Link segment fits on a single line ... | |
| 1747 | . \" Set its height and end-point horizontal displacement accordingly. | |
| 1748 | . \" | |
| 1749 | . nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT] | |
| 1750 | . if \\n[pdf:lly]>=\\n[pdf:lly.end] .nr pdf:urx \\$2 | |
| 1751 | . \} | |
| 1752 | .ie \\$1=3 \{\ | |
| 1753 | . \" | |
| 1754 | . \" Link segment extends beyond the next page break ... | |
| 1755 | . \" Recompute truncated height, to just fit portion on current page, | |
| 1756 | . \" recursing to emit it, and leaving page trap mechanism to place | |
| 1757 | . \" continuation region(s) on following page(s). | |
| 1758 | . \" | |
| 1759 | . nr pdf:lly (\\n[.t]u-\\n[.V]u)/1v | |
| 1760 | . if \\n[pdf:lly]>0 \{\ | |
| 1761 | . nr pdf:lly \\n[pdf:ury]+\\n[pdf:lly]v-1v+\\*[PDFHREF.HEIGHT] | |
| 1762 | . pdf*href.mark.emit 2 | |
| 1763 | . \} | |
| 1764 | . \} | |
| 1765 | .el \{\ | |
| 1766 | . \" Link region size and placement has been fully specified ... | |
| 1767 | . \" Emit it. | |
| 1768 | . \" | |
| 1769 | . pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN | |
| 1770 | . \} | |
| 1771 | .. | |
| 1772 | .\" | |
| 1773 | .\" When "pdf*href" emits a link for which the "hot-spot" spans a | |
| 1774 | .\" page break, then we need to provide a "hook" in to the page break | |
| 1775 | .\" trap, so we can map the "hot-spot" regions which are to be placed | |
| 1776 | .\" on either side of the page break. | |
| 1777 | .\" | |
| 1778 | .\" Macro "pdf*href.mark.idle" is a dummy macro, which provide this | |
| 1779 | .\" "hook" for normal page breaks, where there is no link "hot-spot" | |
| 1780 | .\" crossing the break. | |
| 1781 | .\" | |
| 1782 | .de pdf*href.mark.idle | |
| 1783 | .\" ---------------------------------------------------------------------- | |
| 1784 | .\" Usage: | |
| 1785 | .\" Called only as an internal hook, by a page trap macro. | |
| 1786 | .\" Expects no arguments, and does nothing. | |
| 1787 | .\" ---------------------------------------------------------------------- | |
| 1788 | .. | |
| 1789 | .\" | |
| 1790 | .\" Macro "pdf*href.mark.trap" is the active "hook", which is substituted | |
| 1791 | .\" for "pdf*href,mark.idle" at those page breaks which are crossed by | |
| 1792 | .\" a link "hot-spot". | |
| 1793 | .\" | |
| 1794 | .de pdf*href.mark.trap | |
| 1795 | .\" ---------------------------------------------------------------------- | |
| 1796 | .\" Usage: | |
| 1797 | .\" Called only as an internal hook, by a page trap macro. | |
| 1798 | .\" Expects no arguments. Maps residual link "hot-spot" regions, | |
| 1799 | .\" which spill beyond any page break. Not to be invoked directly | |
| 1800 | .\" by the user, nor by any user supplied macro. | |
| 1801 | .\" ---------------------------------------------------------------------- | |
| 1802 | .\" | |
| 1803 | .mk pdf:ury | |
| 1804 | .nr pdf:ury +1v-1m-\\n[PDFHREF.LEADING] | |
| 1805 | .ie \\n-[pdf:epg] \{\ | |
| 1806 | . \" | |
| 1807 | . \" The link "hot-spot" extends across more than one page break, | |
| 1808 | . \" so, for each page which is completely contained within the | |
| 1809 | . \" extent of the link, simply mark the entire text area on the | |
| 1810 | . \" page as a "hot-spot". | |
| 1811 | . \" | |
| 1812 | . pdf*href.mark.emit 3 | |
| 1813 | . \} | |
| 1814 | .el \{\ | |
| 1815 | . \" The link "hot-spot" ends on the page which immediately follows | |
| 1816 | . \" the current page transition, so we may now finalise this link. | |
| 1817 | . \" | |
| 1818 | . nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT] | |
| 1819 | . if \\n[pdf:lly.end]>\\n[pdf:lly] \{\ | |
| 1820 | . \" | |
| 1821 | . \" The "hot-spot" extends beyond the first line of text, | |
| 1822 | . \" on its final page; compute and emit "hot-spot" region to cover | |
| 1823 | . \" the full with of the text area, including all but the last | |
| 1824 | . \" line of the link text. | |
| 1825 | . \" | |
| 1826 | . while \\n[pdf:lly.end]>\\n[pdf:lly] .nr pdf:lly +1v | |
| 1827 | . nr pdf:lly -1v | |
| 1828 | . pdf*href.mark.emit 2 | |
| 1829 | . \" | |
| 1830 | . \" Now, adjust the vertical "hot-spot" mapping reference, | |
| 1831 | . \" to identify the correct position for the the last line of | |
| 1832 | . \" text, over which the "hot-spot" extends. | |
| 1833 | . \" | |
| 1834 | . nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT] | |
| 1835 | . \} | |
| 1836 | . \" | |
| 1837 | . \" We now have exactly one final line of text, over which we must | |
| 1838 | . \" emit a "hot-spot" region; map it, terminate page trap processing | |
| 1839 | . \" for this "hot-spot", and clean up the "hot-spot" mapping context. | |
| 1840 | . \" | |
| 1841 | . pdf*href.mark.emit 0 \\n[pdf:urx.end] | |
| 1842 | . als pdf*href.mark.hook pdf*href.mark.idle | |
| 1843 | . pdf*href.mark.flush | |
| 1844 | . \} | |
| 1845 | .. | |
| 1846 | .de pdf*href.mark.flush | |
| 1847 | .\" ---------------------------------------------------------------------- | |
| 1848 | .\" ---------------------------------------------------------------------- | |
| 1849 | .rr pdf:spg pdf:epg | |
| 1850 | .rr pdf:llx pdf:lly pdf:urx pdf:ury | |
| 1851 | .if dPDFHREF.COLOR .als PDFHREF.COLOUR PDFHREF.COLOR | |
| 1852 | .rr pdf:urx.end pdf:lly.end | |
| 1853 | .. | |
| 1854 | .de pdf*href.mark.end | |
| 1855 | .\" ---------------------------------------------------------------------- | |
| 1856 | .\" ---------------------------------------------------------------------- | |
| 4d3e9548 | 1857 | \O1\Z'|'\O2\c |
| 465b256c JR |
1858 | .. |
| 1859 | .\" Macro "pdf*href-I" is used for one time initialisation of special | |
| 1860 | .\" "pdfhref" features; (currently, only the above page trap hook is | |
| 1861 | .\" supported, but it is implemented with one level of indirection, to | |
| 1862 | .\" accommodate possible future expansion). | |
| 1863 | . | |
| 1864 | .de pdf*href-I | |
| 1865 | .\" ---------------------------------------------------------------------- | |
| 1866 | .\" Usage: | |
| 1867 | .\" .pdfhref I -<option> <optarg> [-<option> <optarg>] ... | |
| 1868 | .\" ---------------------------------------------------------------------- | |
| 1869 | .\" | |
| 1870 | .\" Loop over all arguments, in pairs ... | |
| 1871 | . | |
| 1872 | .while \\n(.$ \{\ | |
| 1873 | . \" | |
| 1874 | . \" handing them off to their respective initialisers, | |
| 1875 | . \" when suitable initialisers exist, or complaining otherwise. | |
| 1876 | . \" | |
| 1877 | . ie dpdf*href\\$1.init .pdf*href\\$1.init \\$2 | |
| 1878 | . el .pdf*error pdfhref:init: unknown feature '\\$1' | |
| 1879 | . shift 2 | |
| 1880 | . \} | |
| 1881 | .. | |
| 1882 | .\" Before we can use the page break "hook", we need to initialise it | |
| 1883 | .\" as an addendum to a regular page break trap. To ensure that we don't | |
| 1884 | .\" compromise the user's page trap setup, we leave the onus for this | |
| 1885 | .\" initialisation with the user, but we provide the "pdf*href-PT.init" | |
| 1886 | .\" macro, (invoked by ".pdfhref I -PT <macro-name>"), to implement a | |
| 1887 | .\" suitable initialisation action. | |
| 1888 | . | |
| 1889 | .de pdf*href-PT.init | |
| 1890 | .\" ---------------------------------------------------------------------- | |
| 1891 | .\" Usage: | |
| 1892 | .\" .pdfhref I -PT <macro-name> | |
| 1893 | .\" <macro-name> == name of user's page break trap macro | |
| 1894 | .\" ---------------------------------------------------------------------- | |
| 1895 | .\" | |
| 1896 | .\" Initially, map the page break hook to its default, do nothing helper. | |
| 1897 | . | |
| 1898 | .als pdf*href.mark.hook pdf*href.mark.idle | |
| 1899 | .ie !\\n(.$ \{\ | |
| 1900 | . \" | |
| 1901 | . \" Don't have enough arguments to specify a page trap macro name, | |
| 1902 | . \" so simply plant "pdf*href.mark.hook" as a top of page trap. | |
| 1903 | . \" | |
| 1904 | . wh 0 pdf*href.mark.hook | |
| 1905 | . \} | |
| 1906 | .el \{\ | |
| 1907 | . \" Page trap macro name is specified in "\\$1" ... | |
| 1908 | . \" | |
| 1909 | . ie d\\$1 \{\ | |
| 1910 | . \" | |
| 1911 | . \" When this page trap macro already exists, then we simply | |
| 1912 | . \" append a call to "pdf*href.mark.hook" to it. | |
| 1913 | . \" | |
| 1914 | . am \\$1 pdf*href.mark.idle | |
| 1915 | . pdf*href.mark.hook | |
| 1916 | . pdf*href.mark.idle | |
| 1917 | . \} | |
| 1918 | . el \{\ | |
| 1919 | . \" However, when the specified page trap macro does not yet | |
| 1920 | . \" exist, then we create it, and plant it as a top of page | |
| 1921 | . \" trap. | |
| 1922 | . \" | |
| 1923 | . de \\$1 pdf*href.mark.idle | |
| 1924 | . pdf*href.mark.hook | |
| 1925 | . pdf*href.mark.idle | |
| 1926 | . wh 0 \\$1 | |
| 1927 | . \} | |
| 1928 | . \} | |
| 1929 | .. | |
| 1930 | . | |
| 1931 | .\" "pdf*href-L" is the generic handler for creating references to | |
| 1932 | .\" named destinations in PDF documents. It supports both local | |
| 1933 | .\" references, to locations within the same document, through its | |
| 1934 | .\" "pdf*href-L.link" attribute, and also references to locations | |
| 1935 | .\" in any other PDF document, through "pdf*href-L.file". | |
| 1936 | .\" | |
| 1937 | .als pdf*href-L pdf*href | |
| 1938 | .ds pdf*href-L.link /Dest /\\\\*[pdf:href-D] | |
| 1939 | .ds pdf*href-L.file /Action /GoToR \\\\*[pdf:href.files] \\*[pdf*href-L.link] | |
| 1940 | .\" | |
| 1941 | .\" "pdf*href-O" is the "official" handler for creating PDF | |
| 1942 | .\" document outlines. It is simply an alias to "pdfbookmark", | |
| 1943 | .\" which may also be invoked directly, if preferred. Neither | |
| 1944 | .\" a "pdf*href-O.link" nor a "pdf*href-O.file" attribute is | |
| 1945 | .\" required. | |
| 1946 | .\" | |
| 1947 | .als pdf*href-O pdfbookmark | |
| 1948 | .\" | |
| 1949 | .\" "pdf*href-W" is the generic handler for creating references to | |
| 1950 | .\" web resources, (or any resource specified by a uniform resource | |
| 1951 | .\" identifier). Such resource links are fully specified by the | |
| 1952 | .\" "pdf*href-W.link" attribute. | |
| 1953 | .\" | |
| 1954 | .als pdf*href-W pdf*href | |
| 1955 | .ds pdf*href-W.link /Action << /Subtype /URI /URI (\\\\*[pdf:href-D]) >> | |
| 1956 | .\" | |
| 1957 | .\" pdfmark.tmac: end of file / vim: ft=groff |