Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / groff / contrib / pdfmark / pdfmark.tmac
1 .\" -*- nroff -*-
2 .ig
3
4 pdfmark.tmac
5
6 Copyright (C) 2004, 2005, 2006, 2007, 2009
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
14 Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
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
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/>.
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 .\" ======================================================================
45 .\" Module PDFMARK: Insert Arbitrary PDFMARK Code in the Postscript Stream
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 .\"
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 ..
81 .\" The "pdfmark" macro is responsible for emitting the appropriate
82 .\" Postscript code.
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 .\"
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
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
599 .\" to get a "\n" into the Postscript stream, but three levels of "\" are
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 .\"
677 .ie '\\n(.z'' \{\
678 .\"
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.
682 .\"
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
718 .      \}
719 .   \}
720 .el \{\
721 .\"
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).
725 .\"
726 .   nop \!.pdfbookmark \\$@
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 .\" ----------------------------------------------------------------------
1857 \O1\Z'|'\O2\c
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