/contrib/groff/contrib/pdfmark/pdfmark.tmac
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
- .\" -*- nroff -*-
- .ig
- pdfmark.tmac
- Copyright (C) 2004
- Free Software Foundation, Inc.
- Written by Keith Marshall (keith.d.marshall@ntlworld.com)
- This file is part of groff.
- groff is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 2, or (at your option) any later
- version.
- groff is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License along
- with groff; see the file COPYING. If not, write to the Free Software
- Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
- Author's Note
- =============
- While I have written this macro package from scratch, much of my
- inspiration has come from discussion on the groff mailing list
- (mailto:groff@gnu.org). I am particularly indebted to:
- Kees Zeelenberg, for an earlier macro package he posted,
- a study of which helped me to get started.
- Carlos J. G. Duarte and Werner Lemberg, whose discussion
- on computation of the bounding boxes for link "hot-spots"
- forms the basis of such computations in this package.
- ..
- .if !\n(.g .ab These pdfmark macros require groff.
- .\"
- .\" Check if we have already been loaded -- do not reload
- .if d pdfmark .nx
- .\"
- .\" ======================================================================
- .\" Module PDFMARK: Insert Arbitrary PDFMARK Code in the PostScript Stream
- .\" ======================================================================
- .\"
- .\" PDFMARK output may be disabled, by zeroing the PDFOPMODE register,
- .\" ( which mimics a more generic OPMODE, if it is defined ).
- .\"
- .if rOPMODE .aln PDFOPMODE OPMODE
- .\"
- .\" but if OPMODE wasn't defined,
- .\" then make the default PDFMARK mode ENABLED.
- .\"
- .if !rPDFOPMODE .nr PDFOPMODE 1
- .\"
- .\" The "pdfmark" macro is responsible for emitting the appropriate
- .\" PostScript code.
- .\"
- .de pdfmark
- .\" ----------------------------------------------------------------
- .\" Usage:
- .\" .pdfmark text of pdfmark instruction
- .\" Macro supplies the required opening "[" and closing "pdfmark"
- .\" operator; DO NOT include them in the instruction text!
- .\" ----------------------------------------------------------------
- .\"
- .if \\n[PDFOPMODE] \X'ps:exec [\\$* pdfmark'\c
- ..
- .\"
- .\" Some supporting macros defer actual pdfmark output until an
- .\" appropriate time for it to be written; the "pdfsync" macro
- .\" provides a mechanism for flushing such deferred output;
- .\" it should be called from an end macro, and at any other time
- .\" when it may be deemed necessary to flush pdfmark context.
- .\"
- .de pdfsync
- .\" ----------------------------------------------------------------
- .\" Usage:
- .\" .pdfsync buffer ...
- .\" Arguments indicate which "buffer(s)" to flush:
- .\" O -> bookmark (outline) cache
- .\" M -> document metadata diversion
- .\" If no argument, flush ALL buffers
- .\" ----------------------------------------------------------------
- .\"
- .ie \\n(.$ \{\
- . while \\n(.$ \{\
- . if '\\$1'O' .pdf:bm.sync 1
- . if '\\$1'M' \{\
- . if dpdf:metadata .pdf:metadata
- . rm pdf:metadata
- . \}
- . shift
- . \}
- . \}
- .el .pdfsync O M
- ..
- .\"
- .\" some helper functions ...
- .\"
- .\" "pdf:warn" and "pdf:error" write diagnostic messages to stderr
- .\"
- .de pdf:warn
- .\" ----------------------------------------------------------
- .\" Usage:
- .\" .pdf:warn text of message
- .\" ----------------------------------------------------------
- .\"
- .tm \\n(.F:\\n(.c: macro warning: \\$*
- ..
- .de pdf:error
- .\" ----------------------------------------------------------
- .\" Usage:
- .\" .pdf:error text of message
- .\" ----------------------------------------------------------
- .\"
- .tm \\n(.F:\\n(.c: macro error: \\$*
- ..
- .\" "pdf:pop", assisted by "pdf*pop", allows us to retrieve register,
- .\" or string values, from a string masquerading as a data queue,
- .\" or as a stack.
- .\"
- .de pdf:pop
- .\" ----------------------------------------------------------------
- .\" Usage:
- .\" .pdf:pop <type> <to-name> <from-name>
- .\" $1 = nr for numeric register, ds for string
- .\" $2 = name of register or string to be assigned
- .\" $3 = name of string, from which data is to be retrieved
- .\" ----------------------------------------------------------------
- .\"
- .pdf*pop \\$* \\*[\\$3]
- ..
- .de pdf*pop
- .ds pdf:stack \\$3
- .\\$1 \\$2 \\$4
- .shift 4
- .ie \\n(.$ .ds \\*[pdf:stack] \\$*
- .el .rm \\*[pdf:stack]
- .rm pdf:stack
- ..
- .\"
- .\"
- .\" ===========================================================
- .\" Module PDFINFO: Insert MetaData Entries into a PDF Document
- .\" ===========================================================
- .\"
- .\" N.B.
- .\" Output from the macros in this module is deferred, until
- .\" subsequent invocation of .pdfsync, or .pdfexit
- .\"
- .\" ."pdfinfo" provides a general purpose form of metadata entry ...
- .\" it allows arbitrary text to be associated with any specified
- .\" metadata field name.
- .\"
- .de pdfinfo
- .\" -------------------------------------------------------------------
- .\" Usage:
- .\" .pdfinfo /FieldName field content ...
- .\" Examples:
- .\" .pdfinfo /Title A PDF Document
- .\" .pdfinfo /Author Keith Marshall
- .\" -------------------------------------------------------------------
- .\"
- .ds pdf:meta.field \\$1
- .shift
- .da pdf:metadata
- \!.pdfmark \\*[pdf:meta.field] (\\$*) /DOCINFO
- .di
- .rm pdf:meta.field
- ..
- .\"
- .\" Macro "pdfview" defines a special form of metadata entry ...
- .\" it uses the /DOCVIEW pdfmark, to specify the initial (default) view,
- .\" when the document is opened.
- .\"
- .de pdfview
- .\" -------------------------------------------------------------------
- .\" Usage:
- .\" .pdfview view parameters ...
- .\" Examples:
- .\" .pdfview /PageMode /UseOutlines
- .\" .pdfview /Page 2 /View [/FitH \n(.p u]
- .\" -------------------------------------------------------------------
- .\"
- .da pdf:metadata
- \!.pdfmark \\$* /DOCVIEW
- .di
- ..
- .\"
- .\"
- .\" =====================================================================
- .\" Module PDFNOTE: Insert "Sticky Note" Style Comments in a PDF Document
- .\" =====================================================================
- .\"
- .\" "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" set the preferred size for
- .\" display of the "sticky note" pane, when opened. Acrobat Reader
- .\" seems not to honour these -- perhaps GhostScript doesn't encode
- .\" them correctly! Anyway, let's set some suitable default values,
- .\" in case the user has a set up which does work as advertised.
- .\"
- .nr PDFNOTE.WIDTH 3.5i
- .nr PDFNOTE.HEIGHT 2.0i
- .\"
- .\" "pdf:bbox" defines the expression used to set the size and location
- .\" of the bounding rectangle for display of notes and link "hot-spots".
- .\" This is defined, such that a note is placed at troff's current text
- .\" position on the current page, with its displayed image size defined
- .\" by the "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" registers, while the
- .\" bounds for a link "hot-spot" are matched to the text region which
- .\" defines the "hot-spot".
- .\"
- .ds pdf:bbox \\n[pdf:llx] u \\n[pdf:lly] u \\n[pdf:urx] u \\n[pdf:ury] u
- .\"
- .\" Getting line breaks into the text of a PDFNOTE is tricky -- we need
- .\" to get a "\n" into the PostScript stream, but three levels of "\" are
- .\" swallowed, when we invoke "pdfnote". The following definition of "PDFLB",
- .\" (for LineBreak), is rather ugly, but does allow us to use
- .\"
- .\" .pdfnote Some text.\*[PDFLB]Some more text, on a new line.
- .\"
- .ds PDFLB \\\\\\\\\\\\\\\\n
- .\"
- .de pdfnote
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" .pdfnote [-T "Text for Title"] Text of note ...
- .\" ----------------------------------------------------------------------
- .\"
- .if \\n[PDFOPMODE] \{\
- .\"
- .\" First, compute the bounding rectangle,
- .\" for this PDFNOTE instance
- .\"
- . mk pdf:ury
- . nr pdf:llx \\n(.k+\\n(.o+\\n[.in]
- . nr pdf:lly \\n[pdf:ury]-\\n[PDFNOTE.HEIGHT]
- . nr pdf:urx \\n[pdf:llx]+\\n[PDFNOTE.WIDTH]
- . ds pdf:note.instance /Rect [\\*[pdf:bbox]]
- .\"
- .\" Parse any specified (recognisable) PDFNOTE options
- .\"
- . while dpdf:note\\$1 \{\
- . pdf:note\\$1 \\$@
- . shift \\n[pdf:note.argc]
- . \}
- .\"
- .\" Emit the note, and clean up
- .\"
- . pdfmark \\*[pdf:note.instance] /Contents (\\$*) /ANN
- . rm pdf:note.instance
- . rr pdf:note.argc
- . \}
- ..
- .de pdf:note-T
- .nr pdf:note.argc 2
- .as pdf:note.instance " /Title (\\$2)
- ..
- .\"
- .\"
- .\" =====================================================================
- .\" Module PDFBOOKMARK: Add an Outline Reference in the PDF Bookmark Pane
- .\" =====================================================================
- .\"
- .\" "PDFBOOKMARK.VIEW" controls how the document will be displayed,
- .\" when the user selects a bookmark. This default setting will fit
- .\" the page width to the viewing window, with the bookmarked entry
- .\" located at the top of the viewable area.
- .\"
- .ds PDFBOOKMARK.VIEW /FitH \\n[PDFPAGE.Y] u
- .\"
- .\" "PDFOUTLINE.FOLDLEVEL" controls how the document outline will be
- .\" displayed. It is a number, defining the maximum heading level
- .\" which will be visible, without outline expansion by the user, in
- .\" the initial view of the document outline. Assuming that no sane
- .\" document will ever extend to 10,000 levels of nested headings,
- .\" this initial default value causes outlines to be fully expanded.
- .\"
- .nr PDFOUTLINE.FOLDLEVEL 10000
- .\"
- .\" The actual job of creating an outline reference
- .\" is performed by the "pdfbookmark" macro.
- .\"
- .de pdfbookmark
- .\" ------------------------------------------------------------------
- .\" Usage:
- .\" .pdfbookmark [-T tag] level "Text of Outline Entry"
- .\"
- .\" $1 = nesting level for bookmark (1 is top level)
- .\" $2 = text for bookmark, (in PDF viewer bookmarks list)
- .\" $3 = suffix for PDF internal bookmark name (optional)
- .\" ------------------------------------------------------------------
- .\"
- .if \\n[PDFOPMODE] \{\
- .\"
- .\" Make the bookmark name "untagged" by default,
- .\" then parse any specified options, to set a "tag", if required
- .\"
- . ds pdf:href-T
- . while dpdf:href.opt\\$1 \{\
- . pdf:href.opt\\$1 \\$@
- . shift \\n[pdf:href.argc]
- . \}
- . rr pdf:href.argc
- .\"
- .\" If we found "--" to mark the end of the options, discard it
- .\"
- . if '\\$1'--' .shift
- .\"
- .\" Synchronise the bookmark cache
- .\" to the requested bookmark nesting level
- .\"
- . pdf:bm.sync \\$1
- . shift
- .\"
- .\" Increment the bookmark serialisation index
- .\" in order to generate a uniquely serialised bookmark name,
- .\" ( which we return in the string "PDFBOOKMARK.NAME" ),
- .\" and insert this bookmark into the cache
- .\"
- . pdf:href.sety
- . nr pdf:bm.nr +1
- . ds PDFBOOKMARK.NAME pdf:bm\\n[pdf:bm.nr]\\*[pdf:href-T]
- . ds pdf:bm\\n[pdf:bm.nr] /Dest /\\*[PDFBOOKMARK.NAME]
- . pdfmark \\*[pdf:bm\\n[pdf:bm.nr]] /View [\\*[PDFBOOKMARK.VIEW]] /DEST
- . as pdf:bm\\n[pdf:bm.nr] " /Title (\\$*)
- . pdf:href.options.clear
- . rr PDFPAGE.Y
- . \}
- ..
- .\"
- .\" Macro "pdf:bm.sync" is called for each bookmark created,
- .\" to establish a cache entry at the appropriate nesting level.
- .\" It will flush ALL previous cache content, when called to
- .\" add a new bookmark at level 1, or if simply called at
- .\" level 1, without adding any bookmark.
- .\"
- .de pdf:bm.sync
- .\" ------------------------------------------------------------------
- .\" Usage:
- .\" .pdf:bm.sync level
- .\" $1 = nesting level of current bookmark, or 1 to flush cache
- .\" ------------------------------------------------------------------
- .\"
- .\" First validate the bookmark nesting level
- .\" adjusting it if required
- .\"
- .if \\$1>\\n[pdf:bm.nl] .nr pdf:bm.nl +1
- .ie \\$1>\\n[pdf:bm.nl] \{\
- . pdf:warn adjusted level \\$1 bookmark; should be <= \\n[pdf:bm.nl]
- . \}
- .el .nr pdf:bm.nl \\$1
- .if \\n[pdf:bm.nl]<1 \{\
- . pdf:warn bad arg (\\$1) in \\$0 \\$1; \\$0 1 forced
- . nr pdf:bm.nl 1
- . \}
- .\"
- .\" If reverting from a higher to a lower nesting level,
- .\" cyclicly adjust cache counts for each pending higher level
- .\"
- .if \\n[pdf:bm.lc]>=\\n[pdf:bm.nl] \{\
- . nr pdf:bm.lc +1
- . if !rpdf:bm.c\\n[pdf:bm.lc].c .nr pdf:bm.c\\n[pdf:bm.lc].c 0
- . while \\n[pdf:bm.lc]>\\n[pdf:bm.nl] \{\
- . as pdf:bm.c\\n[pdf:bm.lc] " \\n[pdf:bm.c\\n[pdf:bm.lc].c]
- . rr pdf:bm.c\\n[pdf:bm.lc].c
- . nr pdf:bm.lc -1
- . \}
- . \}
- .\"
- .\" Update the cache level,
- .\" flushing when we are at level 1
- .\"
- .nr pdf:bm.lc \\n[pdf:bm.nl]
- .ie \\n[pdf:bm.nl]=1 \{\
- . while \\n[pdf:bm.ic]<\\n[pdf:bm.nr] .pdf:bm.emit 0
- . rr pdf:bm.rc
- . \}
- .el .nr pdf:bm.c\\n[pdf:bm.nl].c +1
- ..
- .\" Macro "pdf:bm.emit" is called, when the cache is at level 1.
- .\" This flushes ALL pending bookmarks from the cache, i.e. the
- .\" preceding level 1 bookmark, and any nested dependents,
- .\" which it may have.
- .\"
- .de pdf:bm.emit
- .\" ------------------------------------------------------------------
- .\" Usage:
- .\" .pdf:bm.emit flag
- .\" $1 = reference counting flag, used to control recursion
- .\" ------------------------------------------------------------------
- .\"
- .\" First check for nested dependents,
- .\" and append the "dependent count" to the bookmark, as required.
- .\"
- .nr pdf:bm.ic +1
- .nr pdf:bm.lc +1
- .pdf:pop nr pdf:bm.rc pdf:bm.c\\n[pdf:bm.lc]
- .if \\n[pdf:bm.rc] \{\
- . ds pdf:bm.fold
- . if \\n[pdf:bm.lc]>\\n[PDFOUTLINE.FOLDLEVEL] .ds pdf:bm.fold -
- . as pdf:bm\\n[pdf:bm.ic] " /Count \\*[pdf:bm.fold]\\n[pdf:bm.rc]
- . rm pdf:bm.fold
- . \}
- .pdfmark \\*[pdf:bm\\n[pdf:bm.ic]] /OUT
- .rm pdf:bm\\n[pdf:bm.ic]
- .\"
- .\" For ALL dependents, if any,
- .\" recursively flush out any higher level dependents,
- .\" which they themselves may have
- .\"
- .while \\n[pdf:bm.rc] \{\
- . nr pdf:bm.rc -1
- . pdf:bm.emit \\n[pdf:bm.rc]
- . \}
- .\"
- .\" Finally,
- .\" unwind the recursive call stack, until we return to the top level.
- .\"
- .nr pdf:bm.rc \\$1
- .nr pdf:bm.lc -1
- ..
- .nr pdf:bm.nr 0
- .nr pdf:bm.nl 1
- .nr pdf:bm.lc 0
- .nr pdf:bm.ic 0
- .\"
- .\"
- .\" =============================================================
- .\" Module PDFHREF: Create Hypertext References in a PDF Document
- .\" =============================================================
- .\"
- .\" "PDFHREF.VIEW" controls how the document will be displayed,
- .\" when the user follows a link to a named reference.
- .\"
- .ds PDFHREF.VIEW /FitH \\n[PDFPAGE.Y] u
- .\"
- .\" This default setting will fit the page width to the viewing
- .\" window, with the bookmarked entry located close to the top
- .\" of the viewable area. "PDFHREF.VIEW.LEADING" controls the
- .\" actual distance below the top of the viewing window, where
- .\" the reference will be positioned; 5 points is a reasonable
- .\" default offset.
- .\"
- .nr PDFHREF.VIEW.LEADING 5.0p
- .\"
- .\" Yuk!!!
- .\" PDF view co-ordinates are mapped from the bottom left corner,
- .\" of the page, whereas page printing co-ordinates are mapped
- .\" conventionally, from top left.
- .\"
- .\" Macro "pdf:href.sety" transforms the vertical position of the
- .\" last printed baseline, from the printing co-ordinate domain to
- .\" the PDF view domain.
- .\"
- .de pdf:href.sety
- .\" ----------------------------------------------------------------
- .\" Usage:
- .\" .pdf:href.sety
- .\" ----------------------------------------------------------------
- .\"
- .\" This computation yields the vertical view co-ordinate
- .\" in groff's basic units; don't forget to append grops' "u"
- .\" conversion operator, when writing the pdfmark!
- .\"
- .nr PDFPAGE.Y \\n(.p-\\n(nl+\\n[PDFHREF.VIEW.LEADING]
- ..
- .\" When we create a link "hot-spot" ...
- .\" "PDFHREF.LEADING" sets the distance above the top of the glyph
- .\" bounding boxes, in each line of link text, over which the link
- .\" hot-spot will extend, while "PDFHREF.HEIGHT" sets the hot-spot
- .\" height, PER LINE of text occupied by the reference.
- .\"
- .\" Since most fonts specify some leading space within the bounding
- .\" boxes of their glyphs, a better appearance may be achieved when
- .\" NEGATIVE leading is specified for link hot-spots; indeed, when
- .\" the default 10pt Times font is used, -1.0 point seems to be a
- .\" reasonable default value for "PDFHREF.LEADING" -- it may be
- .\" changed, if desired.
- .\"
- .\" "PDFHREF.HEIGHT" is initially set as one vertical spacing unit;
- .\" note that it is defined as a string, so it will adapt to changes
- .\" in the vertical spacing. Changing it is NOT RECOMMENDED.
- .\"
- .nr PDFHREF.LEADING -1.0p
- .ds PDFHREF.HEIGHT 1.0v
- .\"
- .\" PDF readers generally place a rectangular border around link
- .\" "hot-spots". Within text, this looks rather ugly, so we set
- .\" "PDFHREF.BORDER" to suppress it -- the three zeroes represent
- .\" the border parameters in the "/Border [0 0 0]" PDFMARK string,
- .\" and may be changed to any valid form, as defined in Adobe's
- .\" PDFMARK Reference Manual.
- .\"
- .ds PDFHREF.BORDER 0 0 0
- .\"
- .\" "PDFHREF.COLOUR" (note British spelling) defines the colour to
- .\" be used for display of link "hot-spots". This will apply both
- .\" to borders, if used, and, by default to text; however, actual
- .\" text colour is set by "PDFHREF.TEXT.COLOUR", which may be reset
- .\" independently of "PDFHREF.COLOUR", to achieve contrasting text
- .\" and border colours.
- .\"
- .\" "PDFHREF.COLOUR" must be set to a sequence of three values,
- .\" each in the range 0.0 .. 1.0, representing the red, green, and
- .\" blue components of the colour specification in the RGB colour
- .\" domain, which is shared by "groff" and the PDF readers.
- .\"
- .ds PDFHREF.COLOUR 0.35 0.00 0.60
- .defcolor pdf:href.colour rgb \*[PDFHREF.COLOUR]
- .\"
- .\" "PDFHREF.TEXT.COLOUR", on the other hand, is simply defined
- .\" using any "groff" colour name -- this default maps it to the
- .\" same colour value as "PDFHREF.COLOUR".
- .\"
- .ds PDFHREF.TEXT.COLOUR pdf:href.colour
- .\"
- .\" Accommodate users who prefer the American spelling, COLOR, to
- .\" the British spelling, COLOUR.
- .\"
- .als PDFHREF.COLOR PDFHREF.COLOUR
- .als PDFHREF.TEXT.COLOR PDFHREF.TEXT.COLOUR
- .\"
- .\" All PDF "Hypertext" reference capabilities are accessed
- .\" through the "pdfhref" macro
- .\"
- .de pdfhref
- .\" -----------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref <subcommand [options ...] [parameters ...]> ...
- .\" -----------------------------------------------------------------
- .\"
- .if \\n[PDFOPMODE] \{\
- .\"
- .\" Loop over all subcommands specified in the argument list
- .\"
- . while \\n(.$ \{\
- . \"
- . \" Initially, assume each subcommand will complete successfully
- . \"
- . nr pdf:href.ok 1
- . \"
- . \" Initialise -E and -X flags in the OFF state
- . \"
- . nr pdf:href-E 0
- . nr pdf:href-X 0
- . \"
- . \" Handle the case where subcommand is specified as "-class",
- . \" setting up appropriate macro aliases for subcommand handlers.
- . \"
- . if dpdf*href\\$1 .als pdf*href pdf*href\\$1
- . if dpdf*href\\$1.link .als pdf*href.link pdf*href\\$1.link
- . if dpdf*href\\$1.file .als pdf*href.file pdf*href\\$1.file
- . \"
- . \" Repeat macro alias setup
- . \" for the case where the subcommand is specified as "class",
- . \" (without a leading hyphen)
- . \"
- . if dpdf*href-\\$1 .als pdf*href pdf*href-\\$1
- . if dpdf*href-\\$1.link .als pdf*href.link pdf*href-\\$1.link
- . if dpdf*href-\\$1.file .als pdf*href.file pdf*href-\\$1.file
- . \"
- . \" Process one subcommand ...
- . \"
- . ie dpdf*href \{\
- . \"
- . \" Subcommand "class" is recognised ...
- . \" discard the "class" code from the argument list,
- . \" set the initial argument count to swallow all arguments,
- . \" and invoke the selected subcommand handler.
- . \"
- . shift
- . nr pdf:argc \\n(.$
- . pdf*href \\$@
- . \"
- . \" When done,
- . \" discard all arguments actually consumed by the handler,
- . \" before proceeding to the next subcommand (if any).
- . \"
- . shift \\n[pdf:argc]
- . \}
- . el \{\
- . \"
- . \" Subcommand "class" is not recognised ...
- . \" issue a warning, and discard the entire argument list,
- . \" so aborting this "pdfhref" invocation
- . \"
- . pdf:warn \\$0: undefined reference class '\\$1' ignored
- . shift \\n(.$
- . \}
- . \"
- . \" Clean up temporary reference data,
- . \" to ensure it doesn't propagate to any future reference
- . \"
- . rm pdf*href pdf:href.link pdf:href.files
- . rr pdf:href-E pdf:href-X
- . pdf:href.options.clear
- . \}
- . rr pdf:href.ok
- . \}
- ..
- .\"
- .\" Macros "pdf:href.flag" and "pdf:href.option"
- .\" provide a generic mechanism for switching on flag type options,
- .\" and for decoding options with arguments, respectively
- .\"
- .de pdf:href.flag
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .nr pdf:href\\$1 1
- .nr pdf:href.argc 1
- ..
- .de pdf:href.option
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .ds pdf:href\\$1 \\$2
- .nr pdf:href.argc 2
- ..
- .\"
- .\" Valid PDFHREF options are simply declared
- .\" by aliasing option handlers to "pdf:href.option",
- .\" or to "pdf:href.flag", as appropriate
- .\"
- .als pdf:href.opt-A pdf:href.option \" affixed text
- .als pdf:href.opt-D pdf:href.option \" destination name
- .als pdf:href.opt-E pdf:href.flag \" echo link descriptor
- .als pdf:href.opt-F pdf:href.option \" remote file specifier
- .als pdf:href.opt-N pdf:href.option \" reference name
- .als pdf:href.opt-P pdf:href.option \" prefixed text
- .als pdf:href.opt-T pdf:href.option \" bookmark "tag"
- .als pdf:href.opt-X pdf:href.flag \" cross reference
- .\"
- .\" For references to another document file
- .\" we also need to support OS dependent file name specifiers
- .\"
- .als pdf:href.opt-DF pdf:href.option \" /DOSFile specifier
- .als pdf:href.opt-MF pdf:href.option \" /MacFile specifier
- .als pdf:href.opt-UF pdf:href.option \" /UnixFile specifier
- .als pdf:href.opt-WF pdf:href.option \" /WinFile specifier
- .\"
- .\" Macro "pdf:href.options.clear" ensures that ALL option
- .\" argument strings are deleted, after "pdfhref" has completed
- .\" all processing which depends on them
- .\"
- .de pdf:href.options.clear
- .\" -----------------------------------------------------------------
- .\" Usage:
- .\" .pdf:href.options.clear [option ...]
- .\" -----------------------------------------------------------------
- .\"
- .\" When an option list is specified ...
- .\"
- .ie \\n(.$ \{\
- . \"
- . \" then loop through the list,
- . \" deleting each specified option argument string in turn
- . \"
- . while \\n(.$ \{\
- . if dpdf:href-\\$1 .rm pdf:href-\\$1
- . shift
- . \}
- . \}
- .\"
- .\" ... but when no list is specified,
- .\" then recurse, to clear all known option argument strings
- .\"
- .el .pdf:href.options.clear A D F N P T DF MF UF WF
- ..
- .\"
- .\" "PDFHREF.INFO" establishes the content of the cross reference
- .\" data record, which is exported via the "stderr" stream, when a
- .\" cross reference anchor is created using a "pdfhref" macro request
- .\" of the form
- .\"
- .\" .pdfhref M -N name -X text ...
- .\"
- .\" .ds PDFHREF.INFO \\*[PDFHREF.NAME] reference data ...
- .\"
- .ds PDFHREF.INFO page \\n% \\$*
- .\"
- .\" Macro "pdf*href-M" is the handler invoked by "pdfhref", when
- .\" called with the "M" reference class specifier, to create a
- .\" named cross reference mark, and to emit a cross reference
- .\" data record, as specified by "PDFHREF.INFO".
- .\"
- .de pdf*href-M
- .\" -----------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref M [-X] [-N name | -D name] [-E] descriptive text ...
- .\" -----------------------------------------------------------------
- .\"
- .\" Initially, declare the -D and -N string options as empty,
- .\" so we avoid warning messages when we try to use them, and find
- .\" that they are undefined.
- .\"
- .ds pdf:href-D
- .ds pdf:href-N
- .\"
- .\" Parse, interpret, and strip any specified options from the
- .\" argument list. (Note that only options with a declared handler
- .\" will be processed; there is no provision for detecting invalid
- .\" options -- anything which is not recognised is assumed to start
- .\" the "descriptive text" component of the argument list).
- .\"
- .while dpdf:href.opt\\$1 \{\
- . pdf:href.opt\\$1 \\$@
- . shift \\n[pdf:href.argc]
- . \}
- .\"
- .\" If we found "--", to mark the end of the options,
- .\" then we should discard it.
- .\"
- .if '\\$1'--' .shift
- .\"
- .\" All PDF reference markers MUST be named. The name may have been
- .\" supplied using the "-N Name" option, (or the "-D Name" option);
- .\" if not, deduce it from the first "word" in the "descriptive text",
- .\" if any, and set the marker -- if we still can't identify the name
- .\" for the destination, then this marker will not be created.
- .\"
- .pdf*href.set \\*[pdf:href-N] \\*[pdf:href-D] \\$1
- .\"
- .\" If we specified a cross reference, with the "-X" option, and the
- .\" reference mark has been sucessfully created, then we now need to
- .\" write the cross reference info to the STDERR stream
- .\"
- .if \\n[pdf:href-X] .pdf*href.export \\*[PDFHREF.INFO]
- .\"
- .\" Irrespective of whether this marker is created, or not,
- .\" the descriptive text will be copied to the groff output stream,
- .\" provided the "-E" option was specified
- .\"
- .if \\n[pdf:href-E] \&\\$*
- ..
- .\"
- .de pdf*href.set
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .pdf*href.map.init
- .ie \\n(.$ \{\
- . \"
- . \" a marker name has been supplied ...
- . \" if we are formatting for immediate output,
- . \" emit PDFMARK code to establish the associated view
- . \"
- . ie '\\n(.z'' \{\
- . pdf:href.sety
- . pdfmark /Dest /\\$1 /View [\\*[PDFHREF.VIEW]] /DEST
- . ds PDFHREF.NAME \\$1
- . rr PDFPAGE.Y
- . \}
- . \"
- . \" but, when formatting a diversion ...
- . \" delay output of the PDFMARK code, until the diversion
- . \" is eventually written out
- . \"
- . el \!.\\$0 \\$@
- . \"
- . \" check if we also need to emit cross reference data
- . \" (caller will do this if "pdf:href-X" is set, but it is
- . \" not necessary, when "pdf:href.map" already exists)
- . \"
- . if dpdf:href.map .nr pdf:href-X 0
- . \}
- .el \{\
- . \" marker is unnamed ...
- . \" issue error message; do not emit reference data
- . \"
- . pdf:warn pdfhref destination marker must be named
- . nr pdf:href-X 0
- . \}
- ..
- .de pdf*href.export
- .\"
- .\" Called ONLY by "pdf*href-M",
- .\" this macro ensures that the emission of exported reference data
- .\" is synchronised with the placement of the reference mark,
- .\" especially when the mark is defined within a diversion.
- .\"
- .ie '\\n(.z'' .tm gropdf-info:href \\*[PDFHREF.NAME] \\$*
- .el \!.\\$0 \\$@
- ..
- .\"
- .\" Macro "pdf*href-D" is invoked when "pdfhref" is called
- .\" with the "D" reference class specifier; it provides a
- .\" standardised mechanism for interpreting reference data
- .\" exported by the "M" reference class, and may be used
- .\" to directly define external reference data, without the
- .\" use of "M" reference class designators in the source
- .\" document.
- .\"
- .de pdf*href-D
- .ds pdf:href-N
- .\"
- .\" Parse, interpret, and strip any specified options from the
- .\" argument list. (Note that only options with a declared handler
- .\" will be processed; there is no provision for detecting invalid
- .\" options -- anything which is not recognised is assumed to start
- .\" the "descriptive text" component of the argument list).
- .\"
- .while dpdf:href.opt\\$1 \{\
- . pdf:href.opt\\$1 \\$@
- . shift \\n[pdf:href.argc]
- . \}
- .\"
- .\" If we found "--", to mark the end of the options,
- .\" then we should discard it.
- .\"
- .if '\\$1'--' .shift
- .\"
- .ie '\\*[pdf:href-N]'' \{\
- . pdf:warn pdfhref defined reference requires a name
- . \}
- .el \{\
- . ds pdf:href(\\*[pdf:href-N]).info \\$*
- . \}
- ..
- .\"
- .\" Macro "pdf*href-F" is invoked when "pdfhref" is called
- .\" with the "F" reference class specifier; it allows the user
- .\" to provide an alternative interpreter macro, which will be
- .\" called when a "PDFHREF.INFO" record is retrieved to define
- .\" the text of a cross reference link "hot spot".
- .\"
- .de pdf*href-F
- .\" ----------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref F [macro-name]
- .\" ----------------------------------------------------------------
- .\"
- .\" Set macro specified by "macro-name" as the format interpreter
- .\" for parsing "PDFHREF.INFO" records; if "macro-name" is omitted,
- .\" or is specified as the reserved name "default", then use the
- .\" default format parser, "pdf*href.format", defined below.
- .\"
- .if '\\$1'default' .shift \\n(.$
- .ie \\n(.$ .als pdf*href.format \\$1
- .el .als pdf*href.format pdf*href.default
- .nr pdf:argc 1
- ..
- .\" The default reference formatting macro is defined below.
- .\" It parses the "PDFHREF.INFO" record specific to each reference,
- .\" recognising the keywords "file", "page" and "section", when they
- .\" appear in initial key/value pairs, replacing the key/value pair
- .\" with "PDFHREF.FILEREF", "PDFHREF.PAGEREF" or "PDFHREF.SECTREF"
- .\" respectively; any additional data in the "PDFHREF.INFO" record
- .\" is enclosed in typographic double quotes, and the parsed record
- .\" is appended to "PDFHREF.PREFIX", to be returned as the formatted
- .\" reference text.
- .\"
- .\" Default definitions for the reference strings "PDFHREF.PREFIX",
- .\" "PDFHREF.FILEREF", "PDFHREF.PAGEREF" and "PDFHREF.SECTREF" are
- .\" provided, in the English language. Users may substitute any
- .\" desired alternative definitions, for example, when formatting
- .\" documents in other languages. In each case, "\\$1" may be used
- .\" in the substitution, to represent the "value" component of the
- .\" respective key/value pair specified in the "PDFHREF.INFO" record.
- .\"
- .ds PDFHREF.PREFIX see
- .ds PDFHREF.PAGEREF page \\$1,
- .ds PDFHREF.SECTREF section \\$1,
- .ds PDFHREF.FILEREF \\$1
- .\"
- .de pdf*href.format
- .\" -----------------------------------------------------------------
- .\" Usage: (to be called ONLY by "pdfhref")
- .\" .pdf*href.format cross reference data ...
- .\" -----------------------------------------------------------------
- .\"
- .\" This macro is responsible for defining the strings "PDFHREF.TEXT"
- .\" and "PDFHREF.DESC", which are used by the "pdfhref" macro, as the
- .\" basis for generating the text content of a link "hot spot"; (any
- .\" user specified alternate formatter MUST do likewise).
- .\"
- .\" Note that "PDFHREF.TEXT" defines the overall format for the "link
- .\" text", while "PDFHREF.DESC" is the descriptive component thereof.
- .\"
- .\" This default implementation, subject to user customisation of the
- .\" "internationalisation" strings defined above, formats "hot spots"
- .\" of the style
- .\"
- .\" see page N, section S, "descriptive text ..."
- .\"
- .ds PDFHREF.TEXT \\*[PDFHREF.PREFIX]
- .while d\\$0.\\$1 \{\
- . \\$0.\\$1 "\\$2"
- . shift 2
- . \}
- .\"
- .\" Retrieve the descriptive text from the cross reference data,
- .\" ONLY IF no overriding description has been set by the calling
- .\" "pdfhref" macro invocation.
- .\"
- .if \\n(.$ .if !dPDFHREF.DESC .ds PDFHREF.DESC \\$*
- .\"
- .\" Augment "PDFHREF.TEXT" so the descriptive text will be included
- .\" in the text of the formatted reference
- .\"
- .if dPDFHREF.DESC .as PDFHREF.TEXT " \(lq\\\\*[PDFHREF.DESC]\(rq
- .\"
- .\" Finally, suppress any leading spaces,
- .\" which may have been included in the PDFHREF.TEXT definition.
- .\"
- .ds PDFHREF.TEXT \\*[PDFHREF.TEXT]
- ..
- .de pdf*href.format.file
- .\" ----------------------------------------------------------------------
- .\" Include a file identifier in a formatted reference.
- .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
- .\" reference data includes an initial file identifier tuple.
- .\" ----------------------------------------------------------------------
- .\"
- .as PDFHREF.TEXT " \\*[PDFHREF.FILEREF]
- ..
- .de pdf*href.format.page
- .\" ----------------------------------------------------------------------
- .\" Include a page number in a formatted reference.
- .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
- .\" reference data includes an initial page number tuple.
- .\" ----------------------------------------------------------------------
- .\"
- .as PDFHREF.TEXT " \\*[PDFHREF.PAGEREF]
- ..
- .de pdf*href.format.section
- .\" ----------------------------------------------------------------------
- .\" Include a section number in a formatted reference.
- .\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
- .\" reference data includes an initial section number tuple.
- .\" ----------------------------------------------------------------------
- .\"
- .as PDFHREF.TEXT " \\*[PDFHREF.SECTREF]
- ..
- .\"
- .\" Make "pdf*href.format" the default cross reference formatter
- .\"
- .als pdf*href.default pdf*href.format
- .\"
- .\"
- .\" Macro "pdf*href" provides a generic mechanism for placing link
- .\" "hot-spots" in a PDF document. ALL "pdfhref" class macros which
- .\" create "hot-spots" are aliased to this macro; each must also have
- .\" an appropriately aliased definition for "pdf*href.template".
- .\"
- .de pdf*href
- .\" ------------------------------------------------------------------
- .\" Usage:
- .\" .pdf*href class [options ...] [link text ...]
- .\" ------------------------------------------------------------------
- .\"
- .\" First, we initialise an empty string, which will be affixed to
- .\" the end of the "link text". (This is needed to cancel the effect
- .\" of a "\c" escape, which is placed at the end of the "link text"
- .\" to support the "-A" option -- any text supplied by the user, when
- .\" the "-A" option is specified, will replace this empty string).
- .\"
- .ds pdf:href-A
- .\"
- .\" Now we interpret, and remove any specified options from the
- .\" argument list. (Note that only options with a declared handler
- .\" will be processed; there is no provision for detecting invalid
- .\" options -- anything which is not recognised is assumed to start
- .\" the "link text" component of the argument list).
- .\"
- .while dpdf:href.opt\\$1 \{\
- . pdf:href.opt\\$1 \\$@
- . shift \\n[pdf:href.argc]
- . \}
- .\"
- .\" If we found "--", to mark the end of the options, then we should
- .\" discard it.
- .\"
- .if '\\$1'--' .shift
- .\"
- .\" All PDF link classes REQUIRE a named destination. This may have
- .\" been supplied using the "-D Name" option, but, if not, deduce it
- .\" from the first "word" in the "link text", if any -- if we still
- .\" can't identify the destination, then set "pdf:href.ok" to zero,
- .\" so this link will not be created.
- .\"
- .if !dpdf:href-D .pdf:href.option -D \\$1
- .if '\\*[pdf:href-D]'' \{\
- . pdf:error pdfhref has no destination
- . nr pdf:href.ok 0
- . \}
- .\"
- .\" Some PDF link classes support a "/File (FilePathName)" argument.
- .\"
- .if dpdf*href.file \{\
- . \"
- . \" When this is supported, it may be specified by supplying
- . \" the "-F FileName" option, which is captured in "pdf:href-F".
- . \"
- . if dpdf:href-F \{\
- . \"
- . \" the /File key is present, so set up the link specification
- . \" to establish the reference to the specified file
- . \"
- . als pdf*href.link pdf*href.file
- . ds pdf:href.files /File (\\*[pdf:href-F])
- . \"
- . \" in addition to the /File key,
- . \" there may also be platform dependent alternate file names
- . \"
- . if dpdf:href-DF .as pdf:href.files " /DOSFile (\\*[pdf:href-DF])
- . if dpdf:href-MF .as pdf:href.files " /MacFile (\\*[pdf:href-MF])
- . if dpdf:href-UF .as pdf:href.files " /UnixFile (\\*[pdf:href-UF])
- . if dpdf:href-WF .as pdf:href.files " /WinFile (\\*[pdf:href-WF])
- . \}
- . \" In some cases, the "/File" key is REQUIRED.
- . \" We will know it is missing, if "pdf*href.link" is not defined.
- . \"
- . if !dpdf*href.link \{\
- . \"
- . \" When a REQUIRED "/File" key specification is not supplied,
- . \" then complain, and set "pdf:href.ok" to abort the creation
- . \" of the current reference.
- . \"
- . pdf:error pdfhref: required -F specification omitted
- . nr pdf:href.ok 0
- . \}
- . \" Now, we have no further use for "pdf*href.file".
- . \"
- . rm pdf*href.file
- . \}
- .\"
- .\" Now, initialise a string, defining the PDFMARK code sequence
- .\" to create the reference, using the appropriate type indicators.
- .\"
- .ds pdf:href.link /Subtype /Link \\*[pdf*href.link]
- .\"
- .\" And now, we have no further use for "pdf*href.link".
- .\"
- .rm pdf*href.link
- .\"
- .\" If the user specified any "link prefix" text, (using the "-P text"
- .\" option), then emit it BEFORE processing the "link text" itself.
- .\"
- .if dpdf:href-P \&\\*[pdf:href-P]\c
- .ie \\n[pdf:href.ok] \{\
- . \"
- . \" This link is VALID (so far as we can determine) ...
- . \" Modify the "link text" argument specification, as required,
- . \" to include any pre-formatted cross reference information
- . \"
- . ie \\n(.$ \{\
- . \"
- . \" One or more "link text" argument(s) are present,
- . \" so, set the link description from the argument(s) ...
- . \"
- . ds PDFHREF.DESC \\\\$*
- . ie \\n[pdf:href-X] \{\
- . \"
- . \" ... and, when the "-X" flag is set,
- . \" also include formatted location information,
- . \" derived from the cross reference record.
- . \"
- . pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info]
- . \}
- . el \{\
- . \" ... but, when the "-X" flag is NOT set,
- . \" use only the argument(s) as the entire content
- . \" of the "link text"
- . \"
- . rn PDFHREF.DESC PDFHREF.TEXT
- . \}
- . \}
- . el \{\
- . \" No "link text" arguments are present,
- . \" so, format the cross reference record to define
- . \" the content of the "link text".
- . \"
- . pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info]
- . \}
- . \" Apply border and colour specifications to the PDFMARK string
- . \" definition, as required.
- . \"
- . if dPDFHREF.BORDER .as pdf:href.link " /Border [\\*[PDFHREF.BORDER]]
- . if dPDFHREF.COLOUR .as pdf:href.link " /Color [\\*[PDFHREF.COLOUR]]
- . \"
- . \" Emit the "link text", in its appropriate colour, marking the
- . \" limits of its bounding box(es), as the before and after output
- . \" text positions.
- . \"
- . pdf*href.mark.begin "\\*[pdf:href.link]"
- . if dPDFHREF.COLOUR .defcolor pdf:href.colour rgb \\*[PDFHREF.COLOUR]
- . nop \&\m[\\*[PDFHREF.TEXT.COLOUR]]\\*[PDFHREF.TEXT]\m[]\c
- . pdf*href.mark.end
- . \"
- . \" Clean up the temporary registers and strings, used to
- . \" compute the "hot-spot" bounds, and format the reference,
- . \"
- . rm PDFHREF.DESC PDFHREF.TEXT
- . \}
- .\"
- .\" But when we identify an INVALID link ...
- .\" We simply emit the "link text", with no colour change, no border,
- .\" and no associated "hot-spot".
- .\"
- .el \&\\$*\c
- .\"
- .\" And then, if the user specified any affixed text, (using the
- .\" "-A text" option), we tack it on at the end.
- .\"
- .nop \&\\*[pdf:href-A]
- ..
- .de pdf*href.map.init
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .\"
- .if dpdf:href.map-1 \{\
- . \"
- . \" We have a reference map, but we haven't started to parse it yet.
- . \" This must be the first map reference in pass 2, so we need to
- . \" "kick-start" the parsing process, by loading the first indexed
- . \" sub-map into the global map.
- . \"
- . rn pdf:href.map-1 pdf:href.map
- . als pdf:href.map.internal pdf:href.map
- . nr pdf:href.map.index 1 1
- . \}
- .als pdf*href.map.init pdf*href.mark.idle
- ..
- .\"
- .\" "pdf*href-Z" is used to add link co-ordinate entries to the
- .\" "pdf:href.map". Primarily, it is used by the "pdfroff" formatter,
- .\" to pass link co-ordinate data from one "groff" formatting pass to
- .\" the next, and is not generally useful to the end user.
- .\"
- .de pdf*href-Z
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref Z page-index x-displacement y-displacement
- .\" Where:
- .\" page-index is the reference mark's page number
- .\" x-displacement is its offset from the left edge of the page
- .\" y-displacement is its offset from the top edge of the page
- .\" ( both displacement values are expressed in basic groff units, )
- .\" ( and measured perpendicular to their respective page edges. )
- .\" ----------------------------------------------------------------------
- .\"
- .ie \\n(.$=3 .ds pdf:href.map-\\n+[pdf*href-Z.index] \\$*
- .el .pdf:error pdfhref Z operator expects exactly three arguments
- ..
- .\" Initialise the auto-incrementing "pdf*href-Z.index" register,
- .\" to ensure that sub-map numbering starts at 1.
- .\"
- .nr pdf*href-Z.index 0 1
- .\"
- .de pdf*href.map.read
- .\" ----------------------------------------------------------------------
- .\" Usage: (internal use only):
- .\" .pdf*href.map.read co-ordinate name list ...
- .\" ----------------------------------------------------------------------
- .\"
- .\" Reads values from "pdf:href.map" to each named register, in turn
- .\" Reading to "null" discards the corresponding value in "pdf:href.map"
- .\"
- .while \\n(.$ \{\
- . \"
- . \" Loop over all registers named in the argument list,
- . \" assigning values from "pdf:href.map" to each in turn.
- . \"
- . pdf:pop nr pdf:\\$1 pdf:href.map.internal
- . if !dpdf:href.map.internal \{\
- . \"
- . \" We ran out of map references in the current sub-map,
- . \" so move on to the next indexed sub-map, if any.
- . \"
- . if dpdf:href.map-\\n+[pdf:href.map.index] \{\
- . rn pdf:href.map-\\n[pdf:href.map.index] pdf:href.map
- . als pdf:href.map.internal pdf:href.map
- . \}
- . \}
- . \"
- . \" Proceed to the next named co-ordinate, (if any), specified
- . \" in the argument list.
- . \"
- . shift
- . \}
- .\"
- .\" Discard any assignments to a register named "null"
- .\"
- .rr pdf:null
- ..
- .de pdf*href.mark.begin
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .pdf*href.map.init
- .ie dpdf:href.map \{\
- . \"
- . \" Once we have established a document reference map,
- . \" then this, and all subsequent calls to "pdf*href.mark.begin",
- . \" may be redirected to the reference mark resolver, and the
- . \" "pdf*href.mark.end" macro has nothing further to do.
- . \"
- . pdf*href.mark.resolve \\$@
- . rn pdf*href.mark.resolve pdf*href.mark.begin
- . als pdf*href.mark.end pdf*href.mark.idle
- . \}
- .el \{\
- . \" Since we don't yet have a document reference map, the
- . \" reference mark resolver will not work, in this pass of the
- . \" formatter; this, and all subsequent calls to "pdf*href.mark.begin",
- . \" may be redirected to "pdf*href.mark.end", which is responsible
- . \" for emitting the reference mark data to be incorporated into
- . \" the reference map in a subsequent formatting pass.
- . \"
- . pdf*href.mark.end
- . als pdf*href.mark.begin pdf*href.mark.end
- . \}
- ..
- .de pdf*href.mark.resolve
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .ie '\\n(.z'' \{\
- . ds pdf:href.link \\$1
- . nr pdf:urx \\n(.o+\\n(.l
- . pdf*href.map.read spg llx ury epg urx.end lly.end
- . ie \\n[pdf:spg]=\\n[pdf:epg] \{\
- . \"
- . \" This link is entirely contained on a single page ...
- . \" emit the text, which defines the content of the link region,
- . \" then make it active.
- . \"
- . pdf*href.mark.emit 1 \\n[pdf:urx.end]
- . if \\n[pdf:lly]<\\n[pdf:lly.end] \{\
- . \"
- . \" This link spans multiple output lines; we must save its
- . \" original end co-ordinates, then define a new intermediate
- . \" end point, to create a PDFMARK "hot-spot" extending from
- . \" the start of the link to the end if its first line.
- . \"
- . nr pdf:ury +1v
- . nr pdf:llx \\n(.o+\\n[.in]
- . nr pdf:lly \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
- . if \\n[pdf:ury]<\\n[pdf:lly] \{\
- . nr pdf:lly +\\*[PDFHREF.HEIGHT]-1v
- . pdf*href.mark.emit 2
- . nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
- . \}
- . pdf*href.mark.emit 0 \\n[pdf:urx.end]
- . \}
- . pdf*href.mark.flush
- . \}
- . el \{\
- . \" This link is split across a page break, so ...
- . \" We must mark the "hot-spot" region on the current page,
- . \" BEFORE we emit the link text, as we will have moved off
- . \" this page, by the time the text has been output.
- . \"
- . \" First step: define the region from the start of the link,
- . \" to the end of its first line.
- . \"
- . pdf*href.mark.emit 1 \\n[pdf:urx]
- . \"
- . \" All additional regions MUST align with the left margin.
- . \"
- . nr pdf:llx \\n(.o+\\n[.in]
- . \"
- . \" If the current page can accomodate more than the current line,
- . \" then it will include a second active region for this link; this
- . \" will extend from just below the current line to the end of page
- . \" trap, if any, or the bottom of the page otherwise, and occupy
- . \" the full width of the page, between the margins.
- . \"
- . nr pdf:ury +1v
- . pdf*href.mark.emit 3
- . \"
- . \" We now need a page transition trap, to map the active link
- . \" region(s), which overflow on to the following page(s); (the
- . \" handler for this trap MUST have been previously installed).
- . \"
- . ie dpdf*href.mark.hook \{\
- . \"
- . \" The page transition trap handler has been installed,
- . \" so we may activate both it, and also the appropriate
- . \" termination handler, to deactivate it when done.
- . \"
- . als pdf*href.mark.hook pdf*href.mark.trap
- . \"
- . \" Now we set up "pdf:epg" to count the number of page breaks
- . \" which this link will span, and emit the link text, leaving
- . \" the page trap macro to map active regions on intervening
- . \" pages, which are included in the link.
- . \"
- . nr pdf:epg -\\n[pdf:spg] 1
- . \}
- . el \{\
- . \" There was no handler initialised for the page trap,
- . \" so we are unable to map the active regions for this link;
- . \" we may discard the remaining map data for this link,
- . \" and issue a diagnostic.
- . \"
- . pdf:error pdfhref: link dissociated at page break (trap not initialised)
- . if dPDFHREF.BROKEN.COLOR \{\
- . \"
- . \" The user may opt to have such broken links highlighted.
- . \" We use "PDFHREF.BROKEN.COLOUR" to specify this requirement,
- . \" but the user may prefer the American spelling, so we will
- . \" handle both as equivalent.
- . \"
- . als PDFHREF.BROKEN.COLOUR PDFHREF.BROKEN.COLOR
- . \}
- . if dPDFHREF.BROKEN.COLOUR \{\
- . if dPDFHREF.COLOUR .als PDFHREF.COLOUR PDFHREF.BROKEN.COLOUR
- . \}
- . \}
- . \}
- . \}
- .el \!.\\$0 \\$@
- ..
- .\"
- .\" Macro "pdf*href.mark.emit" is called only by "pdf*href". It is
- .\" responsible for emitting the PDFMARK code, to establish the
- .\" "hot-spot" region associated with a document or resource link.
- .\"
- .de pdf*href.mark.emit
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" .pdf*href.mark.emit <action> [<end-urx>]
- .\" <action> == 0 --> normal operation -- link height = 1 line
- .\" <action> == 1 --> start of link -- add leading above text
- .\" <action> == 2 --> overtall link -- set intermediate baseline
- .\" <action> == 3 --> split link -- break at bottom of page
- .\" ----------------------------------------------------------------------
- .\"
- .if \\$1=1 \{\
- . \"
- . \" Initialising a new link region ...
- . \" Some different versions of "groff" disagree about the vertical
- . \" displacement of "opminy", as emitted by "\O1|\h'-\w"|"u'\O2\c",
- . \" relative to the current text baseline. Therefore, recompute
- . \" the link displacement, independently of "opminy".
- . \"
- . mk pdf:ury.base
- . while \\n[pdf:ury.base]<\\n[pdf:ury] .nr pdf:ury.base +1v
- . nr pdf:ury.base -1m+\\n[PDFHREF.LEADING]
- . \"
- . \" adjust the end-point vertical displacement by the same offset,
- . \" and then relocate the link starting point to its new displacement,
- . \" as established by this base line relative computation.
- . \"
- . nr pdf:lly.end +\\n[pdf:ury.base]-\\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
- . rnn pdf:ury.base pdf:ury
- . \}
- .if \\$1<2 \{\
- . \"
- . \" Link segment fits on a single line ...
- . \" Set its height and end-point horizontal displacement accordingly.
- . \"
- . nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
- . if \\n[pdf:lly]>=\\n[pdf:lly.end] .nr pdf:urx \\$2
- . \}
- .ie \\$1=3 \{\
- . \"
- . \" Link segment extends beyond the next page break ...
- . \" Recompute truncated height, to just fit portion on current page,
- . \" recursing to emit it, and leaving page trap mechanism to place
- . \" continuation region(s) on following page(s).
- . \"
- . nr pdf:lly (\\n[.t]u-\\n[.V]u)/1v
- . if \\n[pdf:lly]>0 \{\
- . nr pdf:lly \\n[pdf:ury]+\\n[pdf:lly]v-1v+\\*[PDFHREF.HEIGHT]
- . pdf*href.mark.emit 2
- . \}
- . \}
- .el \{\
- . \" Link region size and placement has been fully specified ...
- . \" Emit it.
- . \"
- . pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN
- . \}
- ..
- .\"
- .\" When "pdf*href" emits a link for which the "hot-spot" spans a
- .\" page break, then we need to provide a "hook" in to the page break
- .\" trap, so we can map the "hot-spot" regions which are to be placed
- .\" on either side of the page break.
- .\"
- .\" Macro "pdf*href.mark.idle" is a dummy macro, which provide this
- .\" "hook" for normal page breaks, where there is no link "hot-spot"
- .\" crossing the break.
- .\"
- .de pdf*href.mark.idle
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" Called only as an internal hook, by a page trap macro.
- .\" Expects no arguments, and does nothing.
- .\" ----------------------------------------------------------------------
- ..
- .\"
- .\" Macro "pdf*href.mark.trap" is the active "hook", which is substituted
- .\" for "pdf*href,mark.idle" at those page breaks which are crossed by
- .\" a link "hot-spot".
- .\"
- .de pdf*href.mark.trap
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" Called only as an internal hook, by a page trap macro.
- .\" Expects no arguments. Maps residual link "hot-spot" regions,
- .\" which spill beyond any page break. Not to be invoked directly
- .\" by the user, nor by any user supplied macro.
- .\" ----------------------------------------------------------------------
- .\"
- .mk pdf:ury
- .nr pdf:ury +1v-1m-\\n[PDFHREF.LEADING]
- .ie \\n-[pdf:epg] \{\
- . \"
- . \" The link "hot-spot" extends across more than one page break,
- . \" so, for each page which is completely contained within the
- . \" extent of the link, simply mark the entire text area on the
- . \" page as a "hot-spot".
- . \"
- . pdf*href.mark.emit 3
- . \}
- .el \{\
- . \" The link "hot-spot" ends on the page which immediately follows
- . \" the current page transition, so we may now finalise this link.
- . \"
- . nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
- . if \\n[pdf:lly.end]>\\n[pdf:lly] \{\
- . \"
- . \" The "hot-spot" extends beyond the first line of text,
- . \" on its final page; compute and emit "hot-spot" region to cover
- . \" the full with of the text area, including all but the last
- . \" line of the link text.
- . \"
- . while \\n[pdf:lly.end]>\\n[pdf:lly] .nr pdf:lly +1v
- . nr pdf:lly -1v
- . pdf*href.mark.emit 2
- . \"
- . \" Now, adjust the vertical "hot-spot" mapping reference,
- . \" to identify the correct position for the the last line of
- . \" text, over which the "hot-spot" extends.
- . \"
- . nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
- . \}
- . \"
- . \" We now have exactly one final line of text, over which we must
- . \" emit a "hot-spot" region; map it, terminate page trap processing
- . \" for this "hot-spot", and clean up the "hot-spot" mapping context.
- . \"
- . pdf*href.mark.emit 0 \\n[pdf:urx.end]
- . als pdf*href.mark.hook pdf*href.mark.idle
- . pdf*href.mark.flush
- . \}
- ..
- .de pdf*href.mark.flush
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- .rr pdf:spg pdf:epg
- .rr pdf:llx pdf:lly pdf:urx pdf:ury
- .if dPDFHREF.COLOR .als PDFHREF.COLOUR PDFHREF.COLOR
- .rr pdf:urx.end pdf:lly.end
- ..
- .de pdf*href.mark.end
- .\" ----------------------------------------------------------------------
- .\" ----------------------------------------------------------------------
- \O1|\h'-\w"|"u'\O2\c
- ..
- .\" Macro "pdf*href-I" is used for one time initialisation of special
- .\" "pdfhref" features; (currently, only the above page trap hook is
- .\" supported, but it is implemented with one level of indirection, to
- .\" accommodate possible future expansion).
- .
- .de pdf*href-I
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref I -<option> <optarg> [-<option> <optarg>] ...
- .\" ----------------------------------------------------------------------
- .\"
- .\" Loop over all arguments, in pairs ...
- .
- .while \\n(.$ \{\
- . \"
- . \" handing them off to their respective initialisers,
- . \" when suitable initialisers exist, or complaining otherwise.
- . \"
- . ie dpdf*href\\$1.init .pdf*href\\$1.init \\$2
- . el .pdf*error pdfhref:init: unknown feature '\\$1'
- . shift 2
- . \}
- ..
- .\" Before we can use the page break "hook", we need to initialise it
- .\" as an addendum to a regular page break trap. To ensure that we don't
- .\" compromise the user's page trap setup, we leave the onus for this
- .\" initialisation with the user, but we provide the "pdf*href-PT.init"
- .\" macro, (invoked by ".pdfhref I -PT <macro-name>"), to implement a
- .\" suitable initialisation action.
- .
- .de pdf*href-PT.init
- .\" ----------------------------------------------------------------------
- .\" Usage:
- .\" .pdfhref I -PT <macro-name>
- .\" <macro-name> == name of user's page break trap macro
- .\" ----------------------------------------------------------------------
- .\"
- .\" Initially, map the page break hook to its default, do nothing helper.
- .
- .als pdf*href.mark.hook pdf*href.mark.idle
- .ie !\\n(.$ \{\
- . \"
- . \" Don't have enough arguments to specify a page trap macro name,
- . \" so simply plant "pdf*href.mark.hook" as a top of page trap.
- . \"
- . wh 0 pdf*href.mark.hook
- . \}
- .el \{\
- . \" Page trap macro name is specified in "\\$1" ...
- . \"
- . ie d\\$1 \{\
- . \"
- . \" When this page trap macro already exists, then we simply
- . \" append a call to "pdf*href.mark.hook" to it.
- . \"
- . am \\$1 pdf*href.mark.idle
- . pdf*href.mark.hook
- . pdf*href.mark.idle
- . \}
- . el \{\
- . \" However, when the specified page trap macro does not yet
- . \" exist, then we create it, and plant it as a top of page
- . \" trap.
- . \"
- . de \\$1 pdf*href.mark.idle
- . pdf*href.mark.hook
- . pdf*href.mark.idle
- . wh 0 \\$1
- . \}
- . \}
- ..
- .
- .\" "pdf*href-L" is the generic handler for creating references to
- .\" named destinations in PDF documents. It supports both local
- .\" references, to locations within the same document, through its
- .\" "pdf*href-L.link" attribute, and also references to locations
- .\" in any other PDF document, through "pdf*href-L.file".
- .\"
- .als pdf*href-L pdf*href
- .ds pdf*href-L.link /Dest /\\\\*[pdf:href-D]
- .ds pdf*href-L.file /Action /GoToR \\\\*[pdf:href.files] \\*[pdf*href-L.link]
- .\"
- .\" "pdf*href-O" is the "official" handler for creating PDF
- .\" document outlines. It is simply an alias to "pdfbookmark",
- .\" which may also be invoked directly, if preferred. Neither
- .\" a "pdf*href-O.link" nor a "pdf*href-O.file" attribute is
- .\" required.
- .\"
- .als pdf*href-O pdfbookmark
- .\"
- .\" "pdf*href-W" is the generic handler for creating references to
- .\" web resources, (or any resource specified by a uniform resource
- .\" identifier). Such resource links are fully specified by the
- .\" "pdf*href-W.link" attribute.
- .\"
- .als pdf*href-W pdf*href
- .ds pdf*href-W.link /Action << /Subtype /URI /URI (\\\\*[pdf:href-D]) >>
- .\"
- .\" pdfmark.tmac: end of file / vim: ft=groff