PageRenderTime 57ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/groff/contrib/pdfmark/pdfmark.tmac

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