cae880a89a2403d4557dfc1f4112525a9b3f9556
[platform/upstream/groff.git] / tmac / pdf.tmac
1 .\" -*- nroff -*-
2 .
3 .ig
4
5 pdf.tmac
6
7  Copyright (C) 2011-2014 Free Software Foundation, Inc.
8       Written by Deri James <deri@chuzzlewit.myzen.co.uk>
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 Much of the code in this macro has come from the excellent original work by
29 Keith Marshall (see attribution in the pdfmark.tmac file). I, however,
30 am solely responsible for any bugs I may have introduced into this file.
31 ..
32 .mso ps.tmac
33 .
34 .de pdf:SS
35 .       char \\$1 \\S'16'\\$1\\S'0'
36 ..
37 .pdf:SS \[+h]
38 .pdf:SS \[ts]
39 .pdf:SS \[*a]
40 .pdf:SS \[*b]
41 .pdf:SS \[*x]
42 .pdf:SS \[*d]
43 .pdf:SS \[*e]
44 .pdf:SS \[*f]
45 .pdf:SS \[*g]
46 .pdf:SS \[*y]
47 .pdf:SS \[*i]
48 .pdf:SS \[+f]
49 .pdf:SS \[*k]
50 .pdf:SS \[*l]
51 .pdf:SS \[*m]
52 .pdf:SS \[*n]
53 .pdf:SS \[*o]
54 .pdf:SS \[*p]
55 .pdf:SS \[*h]
56 .pdf:SS \[*r]
57 .pdf:SS \[*s]
58 .pdf:SS \[*t]
59 .pdf:SS \[*u]
60 .pdf:SS \[+p]
61 .pdf:SS \[*w]
62 .pdf:SS \[*c]
63 .pdf:SS \[*q]
64 .pdf:SS \[*z]
65 .char \[lh] \X'pdf: xrev'\[rh]\X'pdf: xrev'
66 .nr pdf:bm.nl 1
67 .de pdfmark
68 . nop \!x X ps:exec [\\$* pdfmark
69 ..
70 .de pdf:warn
71 . tm \\n(.F:\\n(.c: macro warning: \\$*
72 ..
73 .de pdf:error
74 . tm \\n(.F:\\n(.c: macro error: \\$*
75 ..
76 .de pdfinfo
77 .\" -------------------------------------------------------------------
78 .\" Usage:
79 .\"   .pdfinfo /FieldName field content ...
80 .\" Examples:
81 .\"   .pdfinfo /Title   A PDF Document
82 .\"   .pdfinfo /Author  Keith Marshall
83 .\" -------------------------------------------------------------------
84 .\"
85 .ds pdf:meta.field \\$1
86 .shift
87 .ie '\\n(.z'' .pdfmark \\*[pdf:meta.field] (\\$*) /DOCINFO
88 .el \!.pdfmark \\*[pdf:meta.field] (\\$*) /DOCINFO
89 .rm pdf:meta.field
90 ..
91 .de pdfview
92 .\" -------------------------------------------------------------------
93 .\" Usage:
94 .\"   .pdfview view parameters ...
95 .\" Examples:
96 .\"   .pdfview /PageMode /UseOutlines
97 .\"   .pdfview /Page 2 /View [/FitH \n(.p u]
98 .\" -------------------------------------------------------------------
99 .\"
100 .ie '\\n(.z'' .pdfmark \\$* /DOCVIEW
101 .el \!.pdfmark \\$* /DOCVIEW
102 ..
103 .\" =====================================================================
104 .\" Module PDFNOTE: Insert "Sticky Note" Style Comments in a PDF Document
105 .\" =====================================================================
106 .\"
107 .\" "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" set the preferred size for
108 .\" display of the "sticky note" pane, when opened.  Acrobat Reader
109 .\" seems not to honour these -- perhaps GhostScript doesn't encode
110 .\" them correctly!  Anyway, let's set some suitable default values,
111 .\" in case the user has a set up which does work as advertised.
112 .\"
113 .nr PDFNOTE.WIDTH  3.5i
114 .nr PDFNOTE.HEIGHT 2.0i
115 .\"
116 .\" "pdf:bbox" defines the expression used to set the size and location
117 .\" of the bounding rectangle for display of notes and link "hot-spots".
118 .\" This is defined, such that a note is placed at troff's current text
119 .\" position on the current page, with its displayed image size defined
120 .\" by the "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" registers, while the
121 .\" bounds for a link "hot-spot" are matched to the text region which
122 .\" defines the "hot-spot".
123 .\"
124 .ds pdf:bbox \\n[pdf:llx] u \\n[pdf:lly] u \\n[pdf:urx] u \\n[pdf:ury] u
125 .\"
126 .\" Getting line breaks into the text of a PDFNOTE is tricky -- we need
127 .\" to get a "\n" into the Postscript stream, but three levels of "\" are
128 .\" swallowed, when we invoke "pdfnote".  The following definition of "PDFLB",
129 .\" (for LineBreak), is rather ugly, but does allow us to use
130 .\"
131 .\"    .pdfnote  Some text.\*[PDFLB]Some more text, on a new line.
132 .\"
133 .ds PDFLB \\\\\\\\\\\\\\\\n
134 .\"
135 .de pdfnote
136 .\" ----------------------------------------------------------------------
137 .\" Usage:
138 .\"   .pdfnote [-T "Text for Title"] Text of note ...
139 .\" ----------------------------------------------------------------------
140 .\"
141 .\" First, compute the bounding rectangle,
142 .\" for this PDFNOTE instance
143 .\"
144 .   mk pdf:ury
145 .   nr pdf:llx \\n(.k+\\n(.o+\\n[.in]
146 .   nr pdf:lly \\n[pdf:ury]-\\n[PDFNOTE.HEIGHT]
147 .   nr pdf:urx \\n[pdf:llx]+\\n[PDFNOTE.WIDTH]
148 .   ds pdf:note.instance /Rect [\\*[pdf:bbox]]
149 .\"
150 .\" Parse any specified (recognisable) PDFNOTE options
151 .\"
152 .   while dpdf:note\\$1 \{\
153 .      pdf:note\\$1 \\$@
154 .      shift \\n[pdf:note.argc]
155 .      \}
156 .\"
157 .\" Emit the note, and clean up
158 .\"
159 .   pdfmark \\*[pdf:note.instance] /Subtype /Text /Contents (\\$*) /ANN
160 .   rm pdf:note.instance
161 .   rr pdf:note.argc
162 ..
163 .de pdf:note-T
164 .nr pdf:note.argc 2
165 .as pdf:note.instance " /Title (\\$2)
166 ..
167 .\" =====================================================================
168 .\" Module PDFBOOKMARK: Add an Outline Reference in the PDF Bookmark Pane
169 .\" =====================================================================
170 .\"
171 .\" "PDFBOOKMARK.VIEW" controls how the document will be displayed,
172 .\" when the user selects a bookmark.  This default setting will fit
173 .\" the page width to the viewing window, with the bookmarked entry
174 .\" located at the top of the viewable area.
175 .\"
176 .ds PDFBOOKMARK.VIEW /FitH \\n[PDFPAGE.Y] u
177 .\"
178 .\" "PDFOUTLINE.FOLDLEVEL" controls how the document outline will be
179 .\" displayed.  It is a number, defining the maximum heading level
180 .\" which will be visible, without outline expansion by the user, in
181 .\" the initial view of the document outline.  Assuming that no sane
182 .\" document will ever extend to 10,000 levels of nested headings,
183 .\" this initial default value causes outlines to be fully expanded.
184 .\"
185 .nr PDFOUTLINE.FOLDLEVEL 10000
186 .\"
187 .\" The actual job of creating an outline reference
188 .\" is performed by the "pdfbookmark" macro.
189 .\"
190 .de pdfbookmark
191 .\" ------------------------------------------------------------------
192 .\" Usage:
193 .\"   .pdfbookmark [-T tag] level "Text of Outline Entry"
194 .\"
195 .\"   $1 = nesting level for bookmark (1 is top level)
196 .\"   $2 = text for bookmark, (in PDF viewer bookmarks list)
197 .\" ------------------------------------------------------------------
198 .\"
199 .ie '\\n(.z'' \{\
200 .\"
201 .\" When we are at the top diversion level, i.e. actually emitting text
202 .\" to the output device stream, then we compute the location of, and
203 .\" plant this bookmark immediately.
204 .\"
205 .   \" Make the bookmark name "untagged" by default,
206 .   \" then parse any specified options, to set a "tag", if required
207 .   \"
208 .      ds pdf:href-T
209 .      while dpdf:href.opt\\$1 \{\
210 .         pdf:href.opt\\$1 \\$@
211 .         shift \\n[pdf:href.argc]
212 .         \}
213 .      rr pdf:href.argc
214 .   \"
215 .   \" If we found "--" to mark the end of the options, discard it
216 .   \"
217 .      if '\\$1'--' .shift
218 .   \"
219 .      nr pdf:bm.lev 0+\\$1
220 .      if \\n[pdf:bm.lev]==0 .nr pdf:bm.lev 1
221 .      if \\n[pdf:bm.lev]-1==\\n[PDFOUTLINE.FOLDLEVEL] .nr pdf:bm.lev \\n[pdf:bm.lev]*-1
222 .      nr pdf:bm.abslev 0+\\n[pdf:bm.lev]
223 .      if \\n[pdf:bm.lev]<0 .nr pdf:bm.abslev 0+\\n[pdf:bm.abslev]*-1
224 .      if \\n[pdf:bm.abslev]>\\n[pdf:bm.nl] .nr pdf:bm.nl \\n[pdf:bm.nl]+1
225 .      ie \\n[pdf:bm.abslev]>\\n[pdf:bm.nl] \{\
226 .        pdf:warn adjusted level \\n[pdf:bm.abslev] bookmark; should be <= \\n[pdf:bm.nl]
227 .        nr pdf:bm.abslev 0+\\n[pdf:bm.nl]
228 .        if \\n[pdf:bm.abslev]-1==\\n[PDFOUTLINE.FOLDLEVEL] .nr pdf:bm.lev \\n[pdf:bm.abslev]*-1
229 .      \}
230 .      el .nr pdf:bm.nl \\n[pdf:bm.abslev]
231 .      if \\n[pdf:bm.lev]<0 .nr pdf:bm.abslev \\n[pdf:bm.abslev]*-1
232 .      nr pdf:bm.lev 0+\\n[pdf:bm.abslev]
233 .      rr pdf:bm.abslev
234 .      shift
235 .   \"
236 .   \" Increment the bookmark serialisation index
237 .   \" in order to generate a uniquely serialised bookmark name,
238 .   \" ( which we return in the string "PDFBOOKMARK.NAME" ),
239 .   \"
240 .      nr pdf:bm.nr +1
241 .      ie '\\*[pdf:href-T]'' .ds PDFBOOKMARK.NAME pdf:bm\\n[pdf:bm.nr]
242 .      el .ds PDFBOOKMARK.NAME \\*[pdf:href-T]
243 .      pdf:href.sety
244 .         ds pdf:cleaned \\$*
245 .         ev pdfcln
246 .         tr \[em]-
247 .         nf
248 .         box pdf:clean
249 .         nop \\$*
250 .         fl
251 .         box
252 .         chop pdf:clean
253 .         asciify pdf:clean
254 .         length pdf:clean:len \\*[pdf:clean]
255 .         ds pdf:cleaned \\*[pdf:clean]
256 .         rm pdf:clean
257 .         ev
258 .         tr \[em]\[em]
259 .      ds pdf:look(\\*[PDFBOOKMARK.NAME]) \\*[pdf:cleaned]
260 .      if dPDF.EXPORT .tm .ds pdf:look(\\*[PDFBOOKMARK.NAME]) \\*[pdf:cleaned]
261 .      pdfmark /Dest /\\*[PDFBOOKMARK.NAME] /View [\\*[PDFBOOKMARK.VIEW]] /DEST
262 .      nop \!x X ps:exec [/Dest /\\*[PDFBOOKMARK.NAME] /Title (\\*[pdf:cleaned]) /Level \\n[pdf:bm.lev] /OUT pdfmark
263 .\".      pdfmark /Dest /\\*[PDFBOOKMARK.NAME] /Title "(\\*[pdf:cleaned])" /Level \\n[pdf:bm.lev] /OUT
264 .      pdf:href.options.clear
265 .      rr PDFPAGE.Y
266 .      rm pdf:cleaned
267 .      rm pdf:clean
268 .      \}
269 .   \}
270 .el \{\
271 .\"
272 .\" But when we are collecting a diversion which will be written out later,
273 .\" then we must defer bookmark placement, until we emit the diversion.
274 .\" (don't rely on $0 == pdfbookmark here; it may be a volatile alias).
275 .\"
276 .   nop \!.pdfbookmark \\$@
277 .   \}
278 ..
279 .
280 .de pdfclean
281 .  ie '\\n(.z'' \{\
282 .         ds pdfcleaned \\$*
283 .         ev pdfcln
284 .         tr \[em]-
285 .         nf
286 .         box pdf:clean
287 .         nop \\*[\\*[pdfcleaned]]
288 .         fl
289 .         box
290 .         chop pdf:clean
291 .         asciify pdf:clean
292 .         ev
293 .         ds \\*[pdfcleaned] "\\*[pdf:clean]
294 .         rm pdf:clean
295 .         tr \[em]\[em]
296 .  el .nop \!.pdfclean \\$@
297 ..
298 .\"
299 .\" =============================================================
300 .\" Module PDFHREF: Create Hypertext References in a PDF Document
301 .\" =============================================================
302 .\"
303 .\" "PDFHREF.VIEW" controls how the document will be displayed,
304 .\" when the user follows a link to a named reference.
305 .\"
306 .ds PDFHREF.VIEW     /FitH \\n[PDFPAGE.Y] u
307 .\"
308 .\" This default setting will fit the page width to the viewing
309 .\" window, with the bookmarked entry located close to the top
310 .\" of the viewable area.  "PDFHREF.VIEW.LEADING" controls the
311 .\" actual distance below the top of the viewing window, where
312 .\" the reference will be positioned; 5 points is a reasonable
313 .\" default offset.
314 .\"
315 .nr PDFHREF.VIEW.LEADING  5.0p
316 .\"
317 .\" Yuk!!!
318 .\" PDF view co-ordinates are mapped from the bottom left corner,
319 .\" of the page, whereas page printing co-ordinates are mapped
320 .\" conventionally, from top left.
321 .\"
322 .\" Macro "pdf:href.sety" transforms the vertical position of the
323 .\" last printed baseline, from the printing co-ordinate domain to
324 .\" the PDF view domain.
325 .\"
326 .de pdf:href.sety
327 .\" ----------------------------------------------------------------
328 .\" Usage:
329 .\"   .pdf:href.sety
330 .\" ----------------------------------------------------------------
331 .\"
332 .\" This computation yields the vertical view co-ordinate
333 .\" in groff's basic units; don't forget to append grops' "u"
334 .\" conversion operator, when writing the pdfmark!
335 .\"
336 .nr PDFPAGE.Y (\\n[PDFHREF.VIEW.LEADING]-\\n(nl)
337 ..
338 .\" When we create a link "hot-spot" ...
339 .\" "PDFHREF.LEADING" sets the distance above the top of the glyph
340 .\" bounding boxes, in each line of link text, over which the link
341 .\" hot-spot will extend, while "PDFHREF.HEIGHT" sets the hot-spot
342 .\" height, PER LINE of text occupied by the reference.
343 .\"
344 .\" Since most fonts specify some leading space within the bounding
345 .\" boxes of their glyphs, a better appearance may be achieved when
346 .\" NEGATIVE leading is specified for link hot-spots;  indeed, when
347 .\" the default 10pt Times font is used, -1.0 point seems to be a
348 .\" reasonable default value for "PDFHREF.LEADING" -- it may be
349 .\" changed, if desired.
350 .\"
351 .\" "PDFHREF.HEIGHT" is initially set as one vertical spacing unit;
352 .\" note that it is defined as a string, so it will adapt to changes
353 .\" in the vertical spacing.  Changing it is NOT RECOMMENDED.
354 .\"
355 .nr PDFHREF.LEADING  2.0p
356 .ds PDFHREF.HEIGHT   1.0v
357 .\"
358 .\" PDF readers generally place a rectangular border around link
359 .\" "hot-spots".  Within text, this looks rather ugly, so we set
360 .\" "PDFHREF.BORDER" to suppress it -- the three zeroes represent
361 .\" the border parameters in the "/Border [0 0 0]" PDFMARK string,
362 .\" and may be changed to any valid form, as defined in Adobe's
363 .\" PDFMARK Reference Manual.
364 .\"
365 .ds PDFHREF.BORDER   0 0 0
366 .\"
367 .\" "PDFHREF.COLOUR" (note British spelling) defines the colour to
368 .\" be used for display of link "hot-spots".  This will apply both
369 .\" to borders, if used, and, by default to text; however, actual
370 .\" text colour is set by "PDFHREF.TEXT.COLOUR", which may be reset
371 .\" independently of "PDFHREF.COLOUR", to achieve contrasting text
372 .\" and border colours.
373 .\"
374 .\" "PDFHREF.COLOUR" must be set to a sequence of three values,
375 .\" each in the range 0.0 .. 1.0, representing the red, green, and
376 .\" blue components of the colour specification in the RGB colour
377 .\" domain, which is shared by "groff" and the PDF readers.
378 .\"
379 .ds PDFHREF.COLOUR   0.35 0.00 0.60
380 .defcolor pdf:href.colour rgb \*[PDFHREF.COLOUR]
381 .\"
382 .\" "PDFHREF.TEXT.COLOUR", on the other hand, is simply defined
383 .\" using any "groff" colour name -- this default maps it to the
384 .\" same colour value as "PDFHREF.COLOUR".
385 .\"
386 .ds PDFHREF.TEXT.COLOUR  pdf:href.colour
387 .\"
388 .\" Accommodate users who prefer the American spelling, COLOR, to
389 .\" the British spelling, COLOUR.
390 .\"
391 .als PDFHREF.COLOR       PDFHREF.COLOUR
392 .als PDFHREF.TEXT.COLOR  PDFHREF.TEXT.COLOUR
393 .\"
394 .\" All PDF "Hypertext" reference capabilities are accessed
395 .\" through the "pdfhref" macro
396 .\"
397 .de pdfhref
398 .\" -----------------------------------------------------------------
399 .\" Usage:
400 .\"   .pdfhref <subcommand [options ...] [parameters ...]> ...
401 .\" -----------------------------------------------------------------
402 .\"
403 .\"
404 .\" Loop over all subcommands specified in the argument list
405 .\"
406 .   while \\n(.$ \{\
407 .   \"
408 .   \" Initially, assume each subcommand will complete successfully
409 .   \"
410 .      nr pdf:href.ok 1
411 .   \"
412 .   \" Initialise -E and -X flags in the OFF state
413 .   \"
414 .      nr pdf:href-E 0
415 .      nr pdf:href-X 0
416 .   \"
417 .   \" Handle the case where subcommand is specified as "-class",
418 .   \" setting up appropriate macro aliases for subcommand handlers.
419 .   \"
420 .      if dpdf*href\\$1       .als pdf*href      pdf*href\\$1
421 .      if dpdf*href\\$1.link  .als pdf*href.link pdf*href\\$1.link
422 .      if dpdf*href\\$1.file  .als pdf*href.file pdf*href\\$1.file
423 .   \"
424 .   \" Repeat macro alias setup
425 .   \" for the case where the subcommand is specified as "class",
426 .   \" (without a leading hyphen)
427 .   \"
428 .      if dpdf*href-\\$1      .als pdf*href      pdf*href-\\$1
429 .      if dpdf*href-\\$1.link .als pdf*href.link pdf*href-\\$1.link
430 .      if dpdf*href-\\$1.file .als pdf*href.file pdf*href-\\$1.file
431 .   \"
432 .   \" Process one subcommand ...
433 .   \"
434 .      ds pdf*href.class \\$1
435 .      ie dpdf*href \{\
436 .      \"
437 .      \" Subcommand "class" is recognised ...
438 .      \" discard the "class" code from the argument list,
439 .      \" set the initial argument count to swallow all arguments,
440 .      \" and invoke the selected subcommand handler.
441 .      \"
442 .         shift
443 .         nr pdf:argc \\n(.$
444 .         pdf*href \\$@
445 .      \"
446 .      \" When done,
447 .      \" discard all arguments actually consumed by the handler,
448 .      \" before proceeding to the next subcommand (if any).
449 .      \"
450 .         shift \\n[pdf:argc]
451 .      \}
452 .      el \{\
453 .      \"
454 .      \" Subcommand "class" is not recognised ...
455 .      \" issue a warning, and discard the entire argument list,
456 .      \" so aborting this "pdfhref" invocation
457 .      \"
458 .         pdf:warn \\$0: undefined reference class '\\$1' ignored
459 .         shift \\n(.$
460 .         \}
461 .   \"
462 .   \" Clean up temporary reference data,
463 .   \" to ensure it doesn't propagate to any future reference
464 .   \"
465 .      rm pdf*href pdf:href.link pdf:href.files
466 .      rr pdf:href-E
467 .      pdf:href.options.clear
468 .      \}
469 .   rr pdf:href.ok
470 ..
471 .\"
472 .\" Macros "pdf:href.flag" and "pdf:href.option"
473 .\" provide a generic mechanism for switching on flag type options,
474 .\" and for decoding options with arguments, respectively
475 .\"
476 .de pdf:href.flag
477 .\" ----------------------------------------------------------------------
478 .\" ----------------------------------------------------------------------
479 .nr pdf:href\\$1 1
480 .nr pdf:href.argc 1
481 ..
482 .de pdf:href.option
483 .\" ----------------------------------------------------------------------
484 .\" ----------------------------------------------------------------------
485 .ds pdf:href\\$1 \\$2
486 .nr pdf:href.argc 2
487 ..
488 .\"
489 .\" Valid PDFHREF options are simply declared
490 .\" by aliasing option handlers to "pdf:href.option",
491 .\" or to "pdf:href.flag", as appropriate
492 .\"
493 .als pdf:href.opt-A pdf:href.option   \" affixed text
494 .als pdf:href.opt-D pdf:href.option   \" destination name
495 .als pdf:href.opt-E pdf:href.flag     \" echo link descriptor
496 .als pdf:href.opt-F pdf:href.option   \" remote file specifier
497 .als pdf:href.opt-N pdf:href.option   \" reference name
498 .als pdf:href.opt-P pdf:href.option   \" prefixed text
499 .als pdf:href.opt-T pdf:href.option   \" bookmark "tag"
500 .als pdf:href.opt-X pdf:href.flag     \" cross reference
501 .\"
502 .\" For references to another document file
503 .\" we also need to support OS dependent file name specifiers
504 .\"
505 .als pdf:href.opt-DF pdf:href.option  \" /DOSFile specifier
506 .als pdf:href.opt-MF pdf:href.option  \" /MacFile specifier
507 .als pdf:href.opt-UF pdf:href.option  \" /UnixFile specifier
508 .als pdf:href.opt-WF pdf:href.option  \" /WinFile specifier
509 .\"
510 .\" Macro "pdf:href.options.clear" ensures that ALL option
511 .\" argument strings are deleted, after "pdfhref" has completed
512 .\" all processing which depends on them
513 .\"
514 .de pdf:href.options.clear
515 .\" -----------------------------------------------------------------
516 .\" Usage:
517 .\"   .pdf:href.options.clear [option ...]
518 .\" -----------------------------------------------------------------
519 .\"
520 .\" When an option list is specified ...
521 .\"
522 .ie \\n(.$ \{\
523 .   \"
524 .   \" then loop through the list,
525 .   \" deleting each specified option argument string in turn
526 .   \"
527 .   while \\n(.$ \{\
528 .      if dpdf:href-\\$1 .rm pdf:href-\\$1
529 .      shift
530 .      \}
531 .   \}
532 .\"
533 .\" ... but when no list is specified,
534 .\" then recurse, to clear all known option argument strings
535 .\"
536 .el .pdf:href.options.clear A D F N P T DF MF UF WF
537 ..
538 .\"
539 .\" Macro "pdf*href-M" is the handler invoked by "pdfhref", when
540 .\" called with the "M" reference class specifier, to create a
541 .\" named cross reference mark, and to emit a cross reference
542 .\" data record, as specified by "PDFHREF.INFO".
543 .\"
544 .de pdf*href-M
545 .\" -----------------------------------------------------------------
546 .\" Usage:
547 .\"   .pdfhref M [-N name | -D name] [-E] descriptive text ...
548 .\" -----------------------------------------------------------------
549 .\"
550 .\" Initially, declare the -D and -N string options as empty,
551 .\" so we avoid warning messages when we try to use them, and find
552 .\" that they are undefined.
553 .\"
554 .ds pdf:href-D
555 .ds pdf:href-N
556 .\"
557 .\" Parse, interpret, and strip any specified options from the
558 .\" argument list.  (Note that only options with a declared handler
559 .\" will be processed; there is no provision for detecting invalid
560 .\" options -- anything which is not recognised is assumed to start
561 .\" the "descriptive text" component of the argument list).
562 .\"
563 .while dpdf:href.opt\\$1 \{\
564 .   pdf:href.opt\\$1 \\$@
565 .   shift \\n[pdf:href.argc]
566 .   \}
567 .\"
568 .\" If we found "--", to mark the end of the options,
569 .\" then we should discard it.
570 .\"
571 .if '\\$1'--' .shift
572 .\"
573 .\" All PDF reference markers MUST be named. The name may have been
574 .\" supplied using the "-N Name" option, (or the "-D Name" option);
575 .\" if not, deduce it from the first "word" in the "descriptive text",
576 .\" if any, and set the marker -- if we still can't identify the name
577 .\" for the destination, then this marker will not be created.
578 .\"
579 .ds PDFBOOKMARK.NAME "\\*[pdf:href-N]\\*[pdf:href-D]
580 .pdf*href.set \\*[PDFBOOKMARK.NAME] \\$1
581 .ds pdf:look(\\*[PDFBOOKMARK.NAME]) \\$*
582 .if dPDF.EXPORT .tm .ds pdf:look(\\*[PDFBOOKMARK.NAME]) \\$*
583 .\"
584 .\"
585 .\" Irrespective of whether this marker is created, or not,
586 .\" the descriptive text will be copied to the groff output stream,
587 .\" provided the "-E" option was specified
588 .\"
589 .if \\n[pdf:href-E] \&\\$*
590 ..
591 .de pdf*href-F
592 .\"do nothing
593 ..
594 .\"
595 .de pdf*href.set
596 .\" ----------------------------------------------------------------------
597 .\" ----------------------------------------------------------------------
598 .ie \\n(.$ \{\
599 .   \"
600 .   \" a marker name has been supplied ...
601 .   \" if we are formatting for immediate output,
602 .   \" emit PDFMARK code to establish the associated view
603 .   \"
604 .   ie '\\n(.z'' \{\
605 .      pdf:href.sety
606 .      pdfmark /Dest /\\$1 /View [\\*[PDFHREF.VIEW]] /DEST
607 .      ds PDFHREF.NAME \\$1
608 .      rr PDFPAGE.Y
609 .      \}
610 .   \"
611 .   \" but, when formatting a diversion ...
612 .   \" delay output of the PDFMARK code, until the diversion
613 .   \" is eventually written out
614 .   \"
615 .   el \!.\\$0 \\$@
616 .   \"
617 .   \}
618 .el \{\
619 .   \" marker is unnamed ...
620 .   \" issue error message; do not emit reference data
621 .   \"
622 .   pdf:warn pdfhref destination marker must be named
623 .   \}
624 ..
625 .\"
626 .de pdf*href
627 .\" ------------------------------------------------------------------
628 .\" Usage:
629 .\"   .pdf*href class [options ...] [link text ...]
630 .\" ------------------------------------------------------------------
631 .\"
632 .\" First, we initialise an empty string, which will be affixed to
633 .\" the end of the "link text".  (This is needed to cancel the effect
634 .\" of a "\c" escape, which is placed at the end of the "link text"
635 .\" to support the "-A" option -- any text supplied by the user, when
636 .\" the "-A" option is specified, will replace this empty string).
637 .\"
638 .ds pdf:href-A
639 .\"
640 .\" Now we interpret, and remove any specified options from the
641 .\" argument list.  (Note that only options with a declared handler
642 .\" will be processed;  there is no provision for detecting invalid
643 .\" options -- anything which is not recognised is assumed to start
644 .\" the "link text" component of the argument list).
645 .\"
646 .while dpdf:href.opt\\$1 \{\
647 .   pdf:href.opt\\$1 \\$@
648 .   shift \\n[pdf:href.argc]
649 .   \}
650 .\"
651 .\" If we found "--", to mark the end of the options, then we should
652 .\" discard it.
653 .\"
654 .if '\\$1'--' .shift
655 .\"
656 .\" All PDF link classes REQUIRE a named destination.  This may have
657 .\" been supplied using the "-D Name" option, but, if not, deduce it
658 .\" from the first "word" in the "link text", if any -- if we still
659 .\" can't identify the destination, then set "pdf:href.ok" to zero,
660 .\" so this link will not be created.
661 .\"
662 .if !dpdf:href-D .pdf:href.option -D \\$1
663 .if '\\*[pdf:href-D]'' \{\
664 .   pdf:error pdfhref has no destination
665 .   nr pdf:href.ok 0
666 .   \}
667 .\"
668 .\" Now, initialise a string, defining the PDFMARK code sequence
669 .\" to create the reference, using the appropriate type indicators.
670 .\"
671 .ds pdf:href.link /Subtype /Link \\*[pdf*href.link]
672 .\"
673 .\" And now, we have no further use for "pdf*href.link".
674 .\"
675 .rm pdf*href.link
676 .\"
677 .\" If the user specified any "link prefix" text, (using the "-P text"
678 .\" option), then emit it BEFORE processing the "link text" itself.
679 .\"
680 .if dpdf:href-P \&\\*[pdf:href-P]\c
681 .ie \\n[pdf:href.ok] \{\
682 .   \"
683 .   \" This link is VALID (so far as we can determine) ...
684 .   \" Modify the "link text" argument specification, as required,
685 .   \" to include any pre-formatted cross reference information
686 .   \"
687 .   ie \\n(.$ \{\
688 .      \"
689 .      \" One or more "link text" argument(s) are present,
690 .      \" so, set the link description from the argument(s) ...
691 .      \"
692 .      ds PDFHREF.DESC \\\\$*
693 .      \}
694 .   el \{\
695 .      ie dpdf:look(\\*[pdf:href-D]) .ds PDFHREF.DESC \\*[pdf:look(\\*[pdf:href-D])]
696 .      el .ds PDFHREF.DESC Unknown
697 .      \}
698 .   \" Apply border and colour specifications to the PDFMARK string
699 .   \" definition, as required.
700 .   \"
701 .   if dPDFHREF.BORDER .as pdf:href.link " /Border [\\*[PDFHREF.BORDER]]
702 .   if dPDFHREF.COLOUR .as pdf:href.link " /Color  [\\*[PDFHREF.COLOUR]]
703 .   \"
704 .   \" Emit the "link text", in its appropriate colour, marking the
705 .   \" limits of its bounding box(es), as the before and after output
706 .   \" text positions.
707 .   \"
708 \#.   if dPDFHREF.COLOUR .defcolor pdf:href.colour rgb \\*[PDFHREF.COLOUR]
709 .   nr pdf:bm.width \\w'\\*[PDFHREF.DESC]'
710 .   nop \&\m[\\*[PDFHREF.TEXT.COLOUR]]\c
711 .   device pdf: markstart \\n[rst] \\n[rsb] \\n[PDFHREF.LEADING] \\*[pdf:href.link]
712 .   nop \&\\*[PDFHREF.DESC]\X'pdf: markend'\m[]\c
713 .   \"
714 .   \" Clean up the temporary registers and strings, used to
715 .   \" compute the "hot-spot" bounds, and format the reference,
716 .   \"
717 .   rm PDFHREF.DESC PDFHREF.TEXT
718 .   \}
719 .\"
720 .\" But when we identify an INVALID link ...
721 .\" We simply emit the "link text", with no colour change, no border,
722 .\" and no associated "hot-spot".
723 .\"
724 .el \&\\$*\c
725 .\"
726 .\" And then, if the user specified any affixed text, (using the
727 .\" "-A text" option), we tack it on at the end.
728 .\"
729 .nop \&\\*[pdf:href-A]
730 ..
731 .\" Macro "pdf*href-I" is used for one time initialisation of special
732 .\" "pdfhref" features; (currently, only the above page trap hook is
733 .\" supported, but it is implemented with one level of indirection, to
734 .\" accommodate possible future expansion).
735 .
736 .de pdf*href-I
737 .\" ----------------------------------------------------------------------
738 .\" Usage:
739 .\"   .pdfhref I -<option> <optarg> [-<option> <optarg>] ...
740 .\" ----------------------------------------------------------------------
741 .\"
742 .\" Loop over all arguments, in pairs ...
743 .
744 .while \\n(.$ \{\
745 .   \"
746 .   \" handing them off to their respective initialisers,
747 .   \" when suitable initialisers exist, or complaining otherwise.
748 .   \"
749 .   ie dpdf*href\\$1.init .pdf*href\\$1.init \\$2
750 .   el .pdf*error pdfhref:init: unknown feature '\\$1'
751 .   shift 2
752 .   \}
753 ..
754 .\" Before we can use the page break "hook", we need to initialise it
755 .\" as an addendum to a regular page break trap. To ensure that we don't
756 .\" compromise the user's page trap setup, we leave the onus for this
757 .\" initialisation with the user, but we provide the "pdf*href-PT.init"
758 .\" macro, (invoked by ".pdfhref I -PT <macro-name>"), to implement a
759 .\" suitable initialisation action.
760 .\"
761 .\"
762 .\" "pdf*href-L" is the generic handler for creating references to
763 .\" named destinations in PDF documents.  It supports both local
764 .\" references, to locations within the same document, through its
765 .\" "pdf*href-L.link" attribute, and also references to locations
766 .\" in any other PDF document, through "pdf*href-L.file".
767 .\"
768 .als pdf*href-L      pdf*href
769 .ds  pdf*href-L.link /Dest /\\\\*[pdf:href-D]
770 .ds  pdf*href-L.file /Action /GoToR \\\\*[pdf:href.files] \\*[pdf*href-L.link]
771 .\"
772 .\" "pdf*href-O" is the "official" handler for creating PDF
773 .\" document outlines.  It is simply an alias to "pdfbookmark",
774 .\" which may also be invoked directly, if preferred.  Neither
775 .\" a "pdf*href-O.link" nor a "pdf*href-O.file" attribute is
776 .\" required.
777 .\"
778 .als pdf*href-O      pdfbookmark
779 .\"
780 .\" "pdf*href-W" is the generic handler for creating references to
781 .\" web resources, (or any resource specified by a uniform resource
782 .\" identifier).  Such resource links are fully specified by the
783 .\" "pdf*href-W.link" attribute.
784 .\"
785 .als pdf*href-W      pdf*href
786 .ds  pdf*href-W.link /Action << /Subtype /URI /URI (\\\\*[pdf:href-D]) >>
787 .nr pdf:bm.nl 0
788 .\"
789 .\" "pdfmarksuspend" and "pdfmarkrestart" should be used in any page trap
790 .\" macros to prevent output from the page trap macro being considered part
791 .\" of a 'hot spot' when it crosses a page boundary.
792 .de pdfmarksuspend
793 .nop \!x X pdf: marksuspend
794 ..
795 .de pdfmarkrestart
796 .nop \!x X pdf: markrestart
797 ..
798 .de pdfpagename
799 .nop \!x X pdf: pagename \\$1
800 ..
801 .de pdfswitchtopage
802 .nop \!x X pdf: switchtopage \\$*
803 ..
804 .\"
805 .\" pdf.tmac: end of file / vim: ft=groff