summaryrefslogtreecommitdiff
path: root/contrib/pdfmark
diff options
context:
space:
mode:
authorwl <wl>2004-12-08 08:31:17 +0000
committerwl <wl>2004-12-08 08:31:17 +0000
commit19027907767d699e44966b54ab8990ab8f920486 (patch)
tree0c332e9fb189bc8e9fe7a79c2b0bf7b0ff52e5c8 /contrib/pdfmark
parent9196ca232f9fb7576000cea7090f55088bd41f1b (diff)
downloadgroff-19027907767d699e44966b54ab8990ab8f920486.tar.gz
Import Keith's `pdfmark' package. Integration is very preliminary.
* contrib/pdfmark/*: New files. * Makefile.in (OTHERDIRS): Add contrib/pdfmark. * NEWS: Updated.
Diffstat (limited to 'contrib/pdfmark')
-rw-r--r--contrib/pdfmark/Makefile258
-rw-r--r--contrib/pdfmark/Makefile.sub10
-rw-r--r--contrib/pdfmark/PROBLEMS25
-rw-r--r--contrib/pdfmark/README50
-rw-r--r--contrib/pdfmark/TODO34
-rw-r--r--contrib/pdfmark/cover.ms57
-rw-r--r--contrib/pdfmark/pdfmark.ms2357
-rw-r--r--contrib/pdfmark/pdfmark.tmac1494
-rw-r--r--contrib/pdfmark/spdf.tmac225
9 files changed, 4510 insertions, 0 deletions
diff --git a/contrib/pdfmark/Makefile b/contrib/pdfmark/Makefile
new file mode 100644
index 00000000..a7df24a0
--- /dev/null
+++ b/contrib/pdfmark/Makefile
@@ -0,0 +1,258 @@
+#!/usr/bin/make -f
+# ------------------------------------------------------------------------------
+#
+# 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ------------------------------------------------------------------------------
+#
+PAPERSIZE = a4
+#
+# We use GhostScript as our PDF writer -- here's how we will run it
+#
+GS = gs
+PDFWRITE = $(GS) $(GSFLAGS) -dQUIET -dNOPAUSE -dBATCH -sDEVICE=pdfwrite
+#
+# When generating Tables of Contents, we may need to split the document
+# into separate TOC and BODY components, so that we can rearrange these
+# into the correct order, when we assemble the final PDF document.
+#
+# To achieve this split, we run two groff passes, with different "phase"
+# indices in each of the passes.
+#
+PDF_TOC_ONLY = 1
+PDF_BODY_TEXT = 2
+#
+# In order to choose a groff macro package, to format the document, we need
+# a value for TMACTYPE to be set on the command line. This should name ONE
+# of groff's principal macro packages, e.g. ms, mm, or me.
+#
+ifdef TMACTYPE
+#
+# When TMACTYPE has been appropriately set up, then we may establish the
+# proper settings for groff, to format the document. Notice that we do not
+# specify the principal macro package name directly, but rather, we use a
+# wrapper macro package, which adds the appropriate PDF extensions to the
+# base set; the name of this wrapper package matches its corresponding base
+# package name, with "pdf" appended, e.g. for the ms macros, implemented in
+# "s.tmac", and selected by setting "TMACTYPE=ms", the corresponding wrapper
+# is "spdf.tmac", and the "-ms" option to groff is replaced by "-mspdf",
+# ( which is actually constructed as "-$(TMACTYPE)pdf" ).
+#
+GROFF_SETUP = -Tps $(GROFF_FLAGS) -M. -$(TMACTYPE)pdf $(GROFF_LAYOUT)
+#
+# We also need to communicate the selected paper size to groff, by setting
+# flags to pass it BOTH to troff, and to the postprocessor, grops.
+#
+GROFF_LAYOUT = -dpaper=$(PAPERSIZE) -P-p$(PAPERSIZE)
+#
+# The final output file SHOULD be named with a ".pdf" suffix, but
+# we allow the user to specify the target name without the ".pdf" suffix,
+# and automically append it, silently, when required.
+#
+%: %.$(TMACTYPE)
+ @$(REMAKE) $@.pdf
+#
+else
+#
+# When the TMACTYPE definition has not been supplied, we may deduce it,
+# assuming the input file is named with the macro package name as a suffix,
+# for an input file named to match "%.ms", select the ms macro package ...
+#
+%: %.ms ; @$(REMAKE) TMACTYPE=ms $@
+%.ref: %.ms ; @$(REMAKE) TMACTYPE=ms $@
+%.map: %.ms ; @$(REMAKE) TMACTYPE=ms $@
+%.pdf: %.ms ; @$(REMAKE) TMACTYPE=ms $@
+#
+# Similarly, for the mm, me and mom packages, with input file names matching
+# "%.mm", "%.me" and "%.mom" respectively ...
+#
+%: %.mm ; @$(REMAKE) TMACTYPE=mm $@
+%.ref: %.mm ; @$(REMAKE) TMACTYPE=mm $@
+%.map: %.mm ; @$(REMAKE) TMACTYPE=mm $@
+%.pdf: %.mm ; @$(REMAKE) TMACTYPE=mm $@
+#
+%: %.me ; @$(REMAKE) TMACTYPE=me $@
+%.ref: %.me ; @$(REMAKE) TMACTYPE=me $@
+%.map: %.me ; @$(REMAKE) TMACTYPE=me $@
+%.pdf: %.me ; @$(REMAKE) TMACTYPE=me $@
+#
+%: %.mom ; @$(REMAKE) TMACTYPE=mom $@
+%.ref: %.mom ; @$(REMAKE) TMACTYPE=mom $@
+%.map: %.mom ; @$(REMAKE) TMACTYPE=mom $@
+%.pdf: %.mom ; @$(REMAKE) TMACTYPE=mom $@
+#
+# FIXME: each of the above four rule sets requires an appropriate package of
+# binding macros, to add the PDF extensions to the corresponding base package;
+# until someone provides "mpdf.tmac", "epdf.tmac" and "ompdf.tmac", only the
+# TMACTYPE=ms option will actually work!
+#
+endif
+#
+# Define an awk script to extract cross reference data from the groff stderr
+# stream, and format as a cross reference definitions file, of type "%.ref",
+# to be merged with the groff input stream, in a later formatting pass
+#
+XREF_MARKER = /^gropdf-info:href/
+XREF_FORMAT = { $$1 = ".ds"; $$2 = "pdf:href(" $$2 ").info"; print }
+XREF_SCRIPT = $(XREF_MARKER) $(XREF_FORMAT)
+#
+# Define the awk command, which uses the above script to create a cross
+# reference filter, and specify the groff flags to be applied when piping
+# the groff stderr stream through this filter.
+#
+XREF_FILTER = awk '$(XREF_SCRIPT)'
+XREF_FLAGS = $(GROFF_SETUP) -Z 2>&1 1>/dev/null
+#
+# To kick start the cross referencing process, we create an intermediate
+# file, of type "%.xrf", initialised with the "first pass" cross reference
+# definitions file content.
+#
+%.xrf : %.$(TMACTYPE)
+ groff $(XREF_FLAGS) $^ | $(XREF_FILTER) > $@
+#
+# The final cross reference definitions file is created by recurrently
+# processing the original groff input stream, including the definitions
+# from the preceding pass, (starting with the "%.xrf" file from above),
+# until two consecutive passes create identical output, capturing the
+# final cross reference definitions in the "%.ref" file.
+#
+REMAKE = $(MAKE) --no-print-directory
+#
+%.ref : %.xrf %.$(TMACTYPE)
+ groff $(XREF_FLAGS) $^ | $(XREF_FILTER) > $@
+ diff $< $@ 1>/dev/null 2>&1 || mv -f $@ $<
+ test -f $@ || $(REMAKE) $@
+#
+# Define a second awk script, which will be used to reprocess the fully
+# cross referenced groff input stream, adding "hot-spot" mapping information
+# to the cross reference definitions.
+#
+XMAP_MARKER = /^grohtml-info/
+XMAP_PREFIX = BEGIN { mapref = 0 }
+#MAP_FORMAT = ".ds pdf:href.map-%d %d %d %d\n"
+#MAP_FORMAT = ".ds pdf:href.map-%d %d %d %d %d %d\n"
+#MAP_APPEND = { printf $(XMAP_FORMAT), ++mapref, $$2, $$3, $$6, $$7, $$4 }
+#MAP_APPEND = { printf $(XMAP_FORMAT), ++mapref, $$2, $$3, $$4 }
+#MAP_SCRIPT = $(XMAP_PREFIX) $(XMAP_MARKER) $(XMAP_APPEND)
+XMAP_FORMAT = { print ".ds pdf:href.map-" ++mapref, $$2, $$3, $$4 }
+XMAP_SCRIPT = $(XMAP_PREFIX) $(XMAP_MARKER) $(XMAP_FORMAT)
+#
+# The awk command, which invokes this script as the final cross reference
+# mapping filter, must also reproduce the output of the earlier filter,
+# used to create the "%.ref" file.
+#
+XMAP_FILTER = awk '$(XMAP_SCRIPT) $(XREF_SCRIPT)'
+#
+# The "hot-spot" mapping data is merged with the original "%.ref" cross
+# reference definitions, with the final cross reference mapping definitions
+# being captured in a "%.map" file.
+#
+%.map : %.ref %.$(TMACTYPE)
+ groff $(XREF_FLAGS) $^ | $(XMAP_FILTER) > $@
+#
+# Assuming a cover page title block is defined in the groff document source,
+# with its content bracketed by ".CS" .. ".CE" macro pairs, we can use sed
+# to extract it.
+#
+SET_TITLE = sed -n '/^\.CS/,/^\.CE/p'
+#
+# The extracted title block may then be merged into a standard cover page
+# layout template, and processed by groff, to generate a cover page.
+#
+%-fp.ps: %.$(TMACTYPE)
+ $(SET_TITLE) $< | groff $(GROFF_SETUP) cover.$(TMACTYPE) - > $@
+#
+# Define the "phase" codes, passed to groff, for separating tables of
+# contents and body text into distinct document parts.
+#
+TOC_ONLY = -rPHASE=$(PDF_TOC_ONLY)
+BODY_ONLY = -rPHASE=$(PDF_BODY_TEXT)
+#
+# Identify the document parts to be assembled, by examining the "PARTSLIST"
+# file, if any, specified on the command line as "PARTSLIST=filename".
+#
+ifdef PARTSLIST
+include $(PARTSLIST)
+endif
+#
+# When we are assembling a multipart document, each individual part may
+# include redundant blank pages, inherited from a groff processing phase
+# for an alternative part, reprocessed in its own phase, with "pen up".
+# The following sed script will discard such pages.
+#
+KILL_BLANK_PAGES = \
+ sed -e ':again' \
+ -e ' /%%EndPageSetup/b finish' \
+ -e ' /%%Page:/{' \
+ -e ' N' \
+ -e ' b again' \
+ -e ' }' \
+ -e 'b' \
+ -e ':finish' \
+ -e ' N' \
+ -e ' /^%%Page:.*0 *Cg *EP/d'
+#
+# Define the "multipart" rules for each of the Table of Contents, and
+# the "Body Text" document parts.
+#
+%-toc.ps: %.map %.$(TMACTYPE)
+ groff $(GROFF_SETUP) $(TOC_ONLY) $^ | $(KILL_BLANK_PAGES) > $@
+#
+%-body.ps: %.map %.$(TMACTYPE)
+ groff $(GROFF_SETUP) $(BODY_ONLY) $^ | $(KILL_BLANK_PAGES) > $@
+#
+# The "PARTSLIST" file tells us which parts to assemble, by defining a
+# prototype list, in the "PARTNAMES" variable.
+#
+ifdef PARTNAMES
+#
+# When "PARTNAMES" has been defined, then we may proceed to assemble the
+# specified document parts.
+#
+%.pdf: $(PARTNAMES)
+ $(PDFWRITE) -sOutputFile=$@ $^
+#
+else
+#
+# ... but when, "PARTNAMES" is not yet specified, then we must examine the
+# groff input file, to deduce which parts are required ..
+#
+INCLUDE_TOC = egrep "^[.']"'[ ]*TC( .*)*[ ]*$$'
+#
+%-parts.txt: %.$(TMACTYPE)
+ echo "PARTNAMES =" > $@
+ test -z "`$(SET_TITLE) $<`" || echo "%-fp.ps" >> $@
+ test -z "`$(INCLUDE_TOC) $<`" || echo "%-toc.ps" >> $@
+ echo "%-body.ps" >> $@
+#
+# ... assembling the identified "PARTNAMES" in to a "PARTSLIST" file ...
+#
+%-parts.mk: %-parts.txt
+ echo `tr '\012\014' '\040\040' < $<` > $@
+#
+# ... which we then reprocess, to generate the output document.
+#
+%.pdf: %-parts.mk
+ $(REMAKE) PARTSLIST=$< $@
+#
+endif
+#
+# ------------------------------------------------------------------------------
+# pdfmake: end of file
diff --git a/contrib/pdfmark/Makefile.sub b/contrib/pdfmark/Makefile.sub
new file mode 100644
index 00000000..3f7212a3
--- /dev/null
+++ b/contrib/pdfmark/Makefile.sub
@@ -0,0 +1,10 @@
+all: prepare_examples
+
+prepare_examples:
+ if test ! -f gnu.eps; then \
+ if test -f $(top_srcdir)/doc/gnu.eps; then \
+ cp $(top_srcdir)/doc/gnu.eps . ; \
+ else \
+ cp $(top_builddir)/doc/gnu.eps . ; \
+ fi ; \
+ fi
diff --git a/contrib/pdfmark/PROBLEMS b/contrib/pdfmark/PROBLEMS
new file mode 100644
index 00000000..2fa848bd
--- /dev/null
+++ b/contrib/pdfmark/PROBLEMS
@@ -0,0 +1,25 @@
+Known PROBLEMS in pdfmark.tmac
+==============================
+
+Bounding boxes for link hot-spots which straddle a page break
+are not computed correctly.
+
+*** Resolved: 06-Dec-2004 (KDM): pdfmark.tmac.patch-20041206 ***
+
+--------
+
+Documents including a large number of cross references may fail,
+with an 'input stack limit exceeded' error.
+
+*** Resolved: 27-Sep-2004 (KDM): pdfmark.tmac.patch-20040927 ***
+
+--------
+
+Links placed in diversions, such as footnotes or floating keeps,
+resolve to the wrong destinations; (mapping order becomes confused
+between links in diversion, and links in running text following
+the diversion).
+
+--------
+
+Annotations placed by .pdfnote cannot exceed about 200 chars.
diff --git a/contrib/pdfmark/README b/contrib/pdfmark/README
new file mode 100644
index 00000000..276d610f
--- /dev/null
+++ b/contrib/pdfmark/README
@@ -0,0 +1,50 @@
+README for pdfmark.tmac
+=======================
+
+Copyright (C) 2004, Free Software Foundation Inc.
+Contributed by Keith Marshall (keith.d.marshall@ntlworld.com)
+
+This is free software. See file COPYING, for copying permissions,
+and warranty disclaimer.
+
+This is a preview release of a proposed pdfmark.tmac macro package,
+for use with GNU troff (groff). It is not yet complete, and should
+be considered as an alpha release; there are a few problems to be
+resolved (see file PROBLEMS).
+
+Partial documentation is provided, in groff-ms format. To convert
+this to PDF format, you will require a working groff installation,
+a working ghostscript installation, with the gs command in your PATH,
+and a GNU-compatible make. The tarball should be unpacked in the
+top directory of your groff source tree, then:
+
+ cd <groff-current>/contrib/pdfmark
+ make pdfmark
+
+where <groff-current> is the top directory of your current groff
+source tree.
+
+Included in this package, are:
+
+ pdfmark.tmac -- the core pdfmark macro set
+ spdf.tmac -- a rudimentary set of bindings for ms macros
+ pdfmark.ms -- preliminary documentation
+ cover.ms -- a template for the documentation cover sheet
+ gnu.eps -- the groff logo, copied from the groff distribution
+ Makefile -- makefile, for formatting the documentation
+ README -- this file
+ PROBLEMS -- a list of known problems
+ TODO -- a list of planned features, not yet implemented
+
+To make the pdfmark macros generally usable, copy pdfmark.tmac to the
+'site-tmac' directory appropriate to your groff installation; (ms users
+may also wish to copy spdf.tmac). The macros may then be accessed, by
+including the '-mpdfmark' option on the groff command line; (for ms
+users, '-mspdf' is equivalent to '-ms -mpdfmark', with some extra
+macros 'thrown in').
+
+Comments, and bug reports are welcomed. Please post to the groff
+mailing list, groff@gnu.org; (you must be subscribed to this list to
+post mails). To subscribe, visit
+
+ http://lists.gnu.org/mailman/listinfo/groff
diff --git a/contrib/pdfmark/TODO b/contrib/pdfmark/TODO
new file mode 100644
index 00000000..b006220d
--- /dev/null
+++ b/contrib/pdfmark/TODO
@@ -0,0 +1,34 @@
+TODO items for pdfmark.tmac
+===========================
+
+Add copyright information to PDF documentation.
+
+--------
+
+Add acknowledgements and trade mark ownership notifications
+to PDF documentation.
+
+--------
+
+Provide documentation in man page and texinfo formats.
+
+--------
+
+Add comments in spdf.tmac, to clarify its operation.
+Also add commentary in pdfmark.tmac, to clarify operation of
+recent changes.
+
+--------
+
+Make Makefile generic, so 'configure' can resolve target
+system dependencies.
+
+--------
+
+Provide Makefile.sub, to integrate pdfmark.tmac installation
+into a regular groff build. Add it to groff's Makefile.in
+
+--------
+
+Remove gnu.eps; get it from groff's own 'doc' directory, during
+Makefile.sub execution.
diff --git a/contrib/pdfmark/cover.ms b/contrib/pdfmark/cover.ms
new file mode 100644
index 00000000..1fe7e542
--- /dev/null
+++ b/contrib/pdfmark/cover.ms
@@ -0,0 +1,57 @@
+.de CS
+.if !rCO .nr CO 0
+.if !rTL .nr TL 0
+.\".nr PO*SAVED \\n[PO]
+.nr LL*SAVED \\n[LL]
+.nr HM*SAVED \\n[HM]
+.nr HM 0
+.nr PO (2.1c+\\n[CO]u)
+.nr LL 17.1c
+\&
+.nr PS*SAVED \\n[PS]
+.nr VS*SAVED \\n[VS]
+.nr PS 24
+.nr VS 30
+.CD
+.fam T
+.sp |(5.9c+\\n[TL]u)
+.als AU au@first
+..
+.de au@first
+.sp 1.5v
+.als AU au@next
+.AU \\$@
+..
+.de au@next
+.DE
+.nr PS 18
+.nr VS 18
+.CD
+.sp 0.5v
+\\$*
+..
+.de AI
+\H'-4z'\\$*\H'0'
+..
+.de CE
+.DE
+.sp |17.5c
+.PSPIC gnu.eps
+.nr PS 19
+.CD
+.fam H
+.tkf HR 10z 2p 20z 4p
+\H'-4z'A GNU MANUAL\H'0'
+.DE
+.\".nr PO \\n[PO*SAVED]
+.nr LL \\n[LL*SAVED]
+.nr PS \\n[PS*SAVED]
+.nr VS \\n[VS*SAVED]
+.nr HM \\n[HM*SAVED]
+.\".rr PO*SAVED
+.rr LL*SAVED
+.rr PS*SAVED
+.rr VS*SAVED
+.rr HM*SAVED
+.fam
+..
diff --git a/contrib/pdfmark/pdfmark.ms b/contrib/pdfmark/pdfmark.ms
new file mode 100644
index 00000000..936972c4
--- /dev/null
+++ b/contrib/pdfmark/pdfmark.ms
@@ -0,0 +1,2357 @@
+.\" vim: ft=groff
+.CS
+Portable Document Format
+Publishing with GNU Troff
+.AU Keith Marshall
+.AI <keith.d.marshall@ntlworld.com>
+.CE
+.\" Set the PDF default document view attribute, to ensure that the document
+.\" outline is visible, each time the document is opened in Acrobat Reader.
+.\"
+.pdfview /PageMode /UseOutlines
+.\"
+.\" Add document identification meta-data
+.\"
+.pdfinfo /Title Portable Document Format Publishing with GNU Troff
+.pdfinfo /Author Keith Marshall
+.pdfinfo /Subject Tips and Techniques for Exploiting PDF Features with GNU Troff
+.pdfinfo /Keywords groff troff PDF pdfmark
+.\"
+.\" Set the default cross reference format to indicate section numbers,
+.\" rather than page numbers, when we insert a reference pointer.
+.\"
+.ds PDFHREF.INFO section \\*[SN-NO-DOT] \\$*
+.\"
+.\" Define a macro, to print reference links WITHOUT the usual "see" prefix.
+.\"
+.de XR-NO-PREFIX
+.rn PDFHREF.PREFIX xx
+.ds PDFHREF.PREFIX
+.XR \\$@
+.rn xx PDFHREF.PREFIX
+..
+.\"
+.\" Define a string,
+.\" to insert a Registered Trade Mark symbol as a superscript.
+.\"
+.ds rg \*{\(rg\*}
+.\"
+.\" Establish the page layout.
+.\"
+.nr PO 2.5c
+.nr LL 17.0c
+.nr LT 17.0c
+.nr HY 0
+.nr FF 3
+.nr DI 5n
+.\"
+.\" Generate headers in larger point sizes, for NH levels < 4,
+.\" with point size increasing by 1.5p, for each lesser NH level.
+.\"
+.nr GROWPS 4
+.nr PSINCR 1.5p
+.\"
+.de EM
+.\".I "\s'+0.3'\\$1\s0" "\\$2" "\\$3"
+.I \\$@
+..
+.de CWB
+\\$5\fC\\$3\fP\f(CB\\$1\fP\fC\\$2\fP\\$4
+..
+.de CWI
+\\$5\fC\\$3\fP\f(CI\\$1\fP\fC\\$2\fP\\$4
+..
+.de CWBI
+\\$5\fC\\$3\fP\f[CBI]\\$1\fP\fC\\$2\fP\\$4
+..
+.ds = \f(CB\\$1\f(CR\\$4\f[CBI]\\$2\f(CR\\$3
+.\"
+.NH 1
+.\" When we use numbered section headings, we might like to automatically
+.\" insert a table of contents entry, using the text of the heading itself.
+.\" The "ms" macros don't provide any standard mechanism for doing this,
+.\" but "spdf.tmac" adds the "XN" macro, which will do it for us.
+.\"
+.\" Here's a simple example of how we might use it. In this case, the word
+.\" "Introduction" will appear both in the body of the document, as the text
+.\" of the heading, and it will be added to the table of contents, which is
+.\" subsequently "printed" using the "TC" macro; in both locations, it will
+.\" be prefixed by the section number.
+.\"
+.\" As an additional side effect, any use of "XN" will cause the table of
+.\" contents entry to be automatically reproduced, with the exception of its
+.\" page number reference, as a PDF document outline entry. Thus, the use
+.\" of "XN" to specify numbered section headings results in the automatic
+.\" creation of a numbered PDF document outline. This automatic creation
+.\" of the outline is completely transparent, and will occur regardless
+.\" of whether the "TC" macro is subsequently invoked, or not.
+.\"
+.XN Introduction
+.\"
+.\" If using an old s.tmac, without the SN-NO-DOT extension,
+.\" make sure we get SOMETHING in section number references.
+.\"
+.if !dSN-NO-DOT .als SN-NO-DOT SN
+.LP
+It might appear that it is a fairly simple matter to
+produce documents in Adobe\*(rg\~\(lqPortable\~Document\~Format\(rq,
+commonly known as PDF, using
+.CW groff ) GNU\~Troff\~(
+as the document formatter.
+Indeed,
+.CW groff 's
+default output format is the native Adobe\*(rg\~PostScript\*(rg format,
+which PDF producers such as Adobe\*(rg Acrobat\*(rg Distiller\*(rg,
+or GhostScript, expect as their input format.
+Thus, the PDF production process would seem to entail simply
+formatting the document source with
+.CW groff ,
+to produce a PostScript\*(rg version of the document,
+which can subsequently be processed by Acrobat\*(rg Distiller\*(rg
+or GhostScript, to generate the final PDF document.
+.LP
+For many PDF production requirements,
+the production cycle described above may be sufficient.
+However, this is a limited PDF production method,
+in which the resultant PDF document represents no more than
+an on screen image of the printed form of the document, if
+.CW groff 's
+PostScript\*(rg output were printed directly.
+.LP
+The Portable Document Format provides a number of features,
+which significantly enhance the experience of reading a document on screen,
+but which are of little or no value to a document which is merely printed.
+It
+.EM is
+possible to exploit these PDF features, which are described in the Adobe\*(rg
+.\"
+.de pdfmark-manual
+.\" This is an example of a resource reference specified by URI ...
+.\" We may need to refer often to the Adobe pdfmark Reference Manual,
+.\" so we create the internet link definition using a macro, to make
+.\" it reusable.
+.\"
+.\" Note also, that we protect the description of the reference by
+.\" preceding it with "--", to avoid "invalid character in name" type
+.\" error messages from groff (caused by the use of "\~").
+.\"
+.pdfhref W -D http://partners.adobe.com/asn/acrobat/docs/pdfmark.pdf \
+ -P \(lq -A \(rq\\$1 -- pdfmark\~Reference\~Manual
+..
+.pdfmark-manual ,
+with some refinement of the simple PDF production method, provided
+appropriate \(lqfeature implementing\(rq instructions can be embedded into
+.CW groff 's
+PostScript\*(rg rendering of the document.
+This, of course, implies that the original document source, which
+.CW groff
+will process to generate the PostScript\*(rg description of the document,
+must include appropriate markup to exploit the desired PDF features.
+It is this preparation of the
+.CW groff
+document source to exploit a number of these features,
+which provides the principal focus of this document.
+.LP
+The markup techniques to be described have been utilised in the production of
+the PDF version of this document itself.
+This has been formatted using
+.CW groff 's
+.CW ms
+macro package;
+thus, usage examples may be found in the document source file,
+.CW \n(.F ,
+to which comments have been added,
+to help identify appropriate markup examples for implementing PDF features,
+such as:\(en
+.QS
+.IP \(bu
+Selecting a default document view, which defines how the document will appear
+when opened in the reader application; for example, when this document is
+opened in Acrobat\*(rg\~Reader, it should display the top of the cover sheet,
+in the document view pane, while a document outline should appear to the left,
+in the \(lqBookmarks\(rq pane.
+.IP \(bu
+Adding document identification \(lqmeta\(hydata\(rq,
+which can be accessed, in Acrobat\*(rg\~Reader,
+by inspecting the \(lqFile\^/\^Document\~Properties\^/\^Summary\(rq.
+.IP \(bu
+Creating a document outline, which will be displayed in the \(lqBookmarks\(rq
+pane of Acrobat\*(rg\~Reader, such that readers may quickly navigate to any
+section of the document, simply by clicking on the associated heading
+in the outline view.
+.IP \(bu
+Embedding active links in the body of the document, such that readers may
+quickly navigate to related material at another location within the same
+document, or in another PDF document, or even to a related Internet resource,
+specified by its URI.
+.IP \(bu
+Adding annotations, in the form of \(lqsticky notes\(rq, at strategic
+points within the PDF document.
+.QE
+.LP
+All of the techniques described have been tested on
+.EM both
+GNU/Linux, and on Microsoft\*(rg Windows\(tm2000 operating platforms, using
+.CW groff
+.CW 1.19.1 ,\c
+.pdfhref L -D footnote1 -- \**
+.FS
+.pdfhref M footnote1
+Later versions should, and some earlier versions may, be equally suitable.
+See
+.pdfhref W http://groff.ffii.org
+for information and availability of the latest version.
+.FE
+in association with
+.CW AFPL
+.CW GhostScript
+.CW 8.14 .\c
+.pdfhref L -D footnote2 -- \**
+.FS
+.pdfhref M footnote2
+Again, other versions may be suitable.
+See
+.pdfhref W http://ghostscript.com
+for information and availability.
+.FE
+Other tools employed, which should be readily available on
+.EM any
+.SM
+UNIX\(tm
+.LG
+or GNU/Linux system, are
+.CW sed ,
+.CW awk
+and
+.CW make ,
+together with an appropriate text editor, for creating and marking up the
+.CW groff
+input files.
+These additional utilities are not provided, as standard,
+on the Microsoft\*(rg Windows\(tm platform,
+but several third party implementations are available.
+Some worth considering include the MKS\*(rg\~Toolkit,\**
+.FS
+A commercial offering; see
+.pdfhref W http://mkssoftware.com/products/tk/default.asp
+for information.
+.FE
+Cygwin,\**
+.FS
+A
+.EM free
+but comprehensive
+.SM
+POSIX
+.LG
+emulation environment and
+.SM
+UNIX\(tm
+.LG
+toolkit for 32\(hybit Microsoft\*(rg Windows\(tm platforms; see
+.pdfhref W http://cygwin.com
+for information and download.
+.FE
+or MSYS.\**
+.FS
+Another free, but minimal suite of common
+.SM
+UNIX\(tm
+.LG
+tools for 32\(hybit Microsoft\*(rg Windows\(tm, available for download from
+.pdfhref W -A ; http://www.mingw.org
+it
+.EM does
+include those tools listed above,
+and is the package which was actually used when performing the Windows\(tm2000
+platform tests referred to in the text.
+.FE
+This list is by no means exhaustive, and should in no way be construed as an
+endorsement of any of these packages, nor to imply that other similar packages,
+which may be available, are in any way inferior to them.
+.bp
+.NH 1
+.\" We may wish a section heading to represent a named destination,
+.\" so that we can create a linked reference to it, from some other
+.\" part of the PDF document, (or even from another PDF document).
+.\"
+.\" Here we use the "-N" option of the "XN" macro, to create a named
+.\" PDF link destination, at the location of the heading. Notice that
+.\" we also use the "--" marker to separate the heading text from the
+.\" preceding option specification; it is not strictly necessary in
+.\" this case, but it does help to set off the heading text from the
+.\" option specification.
+.\"
+.XN -N pdf-features -- Exploiting PDF Document Features
+.LP
+To establish a consistent framework for adding PDF features, a
+.CW groff
+macro package, named
+.CW pdfmark.tmac ,
+has been provided.
+Thus, to incorporate PDF features in a document,
+the appropriate macro calls, as described below, may be placed in the
+.CW groff
+document source, which should then be processed with a
+.CW groff
+command of the form
+.QP
+.fam C
+groff -Tps [-m
+.I name "] -m"
+.B pdfmark
+.I options \& [-
+.I "file ..." \& "...] "
+.LP
+It may be noted that the
+.CW pdfmark
+macros have no dependencies on, and no known conflicts with,
+any other
+.CW groff
+macro package; thus, users are free to use any other macro package,
+of their choice, to format their documents, while also using the
+.CW pdfmark
+macros to add PDF features.
+.NH 2
+.XN -N pdfmark-operator -- The \F[C]pdfmark\F[] Operator
+.LP
+All PDF features are implemented by embedding instances of the
+.B \F[C]pdfmark\F[]
+operator, as described in the Adobe\*(rg
+.pdfmark-manual ,
+into
+.CW groff 's
+PostScript\*(rg output stream.
+To facilitate the use of this operator, the
+.CW pdfmark
+macro package defines the primitive
+.CW pdfmark
+macro; it simply emits its argument list,
+as arguments to a
+.CW pdfmark
+operator, in the PostScript\*(rg output stream.
+.LP
+.pdfhref M -N pdfmark-example
+To illustrate the use of the
+.CW pdfmark
+macro, the following is a much simplified example of how a bookmark
+may be added to a PDF document outline
+.QP
+.CW ".pdfmark \e"
+.RS 4
+.nf
+.fam C
+/Count 2 \e
+/Title (An Example of a Bookmark with Two Children) \e
+/View [/FitH \en[PDFPAGE.Y]] \e
+/OUT
+.RE
+.LP
+In general, users should rarely need to use the
+.CW pdfmark
+macro directly.
+In particular, the above example is too simple for general use; it
+.EM will
+create a bookmark, but it does
+.EM not
+address the issues of setting the proper value for the
+.CW /Count
+key, nor of computing the
+.CW PDFPAGE.Y
+value used in the
+.CW /View
+key. The
+.CW pdfmark
+macro package includes a more robust mechanism for creating bookmarks,
+.\"
+.\" Here is an example of how a local reference may be planted,
+.\" using the automatic formatting feature of the "pdfhref" macro.
+.\"
+.\" This is a forward reference to the named destination "add-outline",
+.\" which is defined below, using the "XN" wrapper macro, from the
+.\" "spdf.tmac" macro package. The automatically formatted reference
+.\" will be enclosed in parentheses, as specified by the use of
+.\" "-P" and "-A" options.
+.\"
+.pdfhref L -P ( -A ), -D add-outline
+.\"
+which addresses these issues automatically.
+Nevertheless, the
+.CW pdfmark
+macro may be useful to users wishing to implement more advanced PDF features,
+than those currently supported directly by the
+.CW pdfmark
+macro package.
+.NH 2
+.XN -N docview -- Selecting an Initial Document View
+.LP
+By default,
+when a PDF document is opened,
+the first page will be displayed,
+at the default magnification set for the reader,
+and outline and thumbnail views will be hidden.
+When using a PDF reader,
+such as Acrobat\*(rg\~Reader,
+which supports the
+.CW /DOCVIEW
+class of the
+.CW pdfmark
+operator,
+these default initial view settings may be overridden,
+using the
+.CW pdfview
+macro.
+For example
+.QP
+.CW ".pdfview /PageMode /UseOutlines"
+.LP
+will cause Acrobat\*(rg\~Reader to open the document outline view,
+to the left of the normal page view,
+while
+.QP
+.CW ".pdfview /PageMode /UseThumbs"
+.LP
+will open the thumbnail view instead.
+.LP
+Note that the two
+.CW /PageMode
+examples, above, are mutually exclusive \(em it is not possible to have
+.EM both
+outline and thumbnail views open simultaneously.
+However, it
+.EM is
+permitted to add
+.CW /Page
+and
+.CW /View
+keys, to force the document to open at a page other than the first,
+or to change the magnification at which the document is initially displayed;
+see the
+.pdfmark-manual
+for more information.
+.LP
+It should be noted that the view controlling meta\(hydata, defined by the
+.CW pdfview
+macro, is not written immediately to the PostScript\*(rg output stream,
+but is stored in an internal meta\(hydata \(lqcache\(rq,
+(simply implemented as a
+.CW groff
+diversion).
+This \(lqcached\(lq meta\(hydata must be written out later, by invoking the
+.CW pdfsync
+macro,
+.\"
+.\" Here is another example of how we may introduce a forward reference.
+.\" This time we are using the shorter notation afforded by the "XR" macro
+.\" provided by "spdf.tmac"; this example is equivalent to the native
+.\" "pdfmark.tmac" form
+.\" .pdfhref L -D pdfsync -P ( -A ).
+.\"
+.XR pdfsync ). (
+.\"
+.NH 2
+.XN -N docinfo -- Adding Document Identification Meta-Data
+.LP
+In addition to the
+.CW /DOCVIEW
+class of meta\(hydata described above,
+.XR docview ), (
+we may also wish to include document identification meta\(hydata,
+which belongs to the PDF
+.CW /DOCINFO
+class.
+.LP
+To do this, we use the
+.CW pdfinfo
+macro.
+As an example of how it is used,
+the identification meta\(hydata attached to this document
+was specified using a macro sequence similar to:\(en
+.RS
+.LD
+.fam C
+\&.pdfinfo /Title PDF Document Publishing with GNU Troff
+\&.pdfinfo /Author Keith Marshall
+\&.pdfinfo /Subject How to Exploit PDF Features with GNU Troff
+\&.pdfinfo /Keywords groff troff PDF pdfmark
+.DE
+.RE
+Notice that the
+.CW pdfinfo
+macro is repeated, once for each
+.CW /DOCINFO
+record to be placed in the document.
+In each case, the first argument is the name of the applicable
+.CW /DOCINFO
+key, which
+.EM must
+be named with an initial solidus character;
+all additional arguments are collected together,
+to define the value to be associated with the specified key.
+.LP
+As is the case with the
+.CW pdfview
+macro,
+.XR docview ), (
+the
+.CW /DOCINFO
+records specified with the
+.CW pdfinfo
+macro are not immediately written to the PostScript\*(rg output stream;
+they are stored in the same meta\(hydata cache as
+.CW /DOCVIEW
+specifications, until this cache is explicitly flushed,
+by invoking the
+.CW pdfsync
+macro,
+.XR pdfsync ). (
+.NH 2
+.XN -N add-outline -- Creating a Document Outline
+.LP
+A PDF document outline comprises a table of references,
+to \(lqbookmarked\(rq locations within the document.
+When the document is viewed in an \(lqoutline\~aware\(rq PDF document reader,
+such as Adobe\*(rg Acrobat\*(rg Reader,
+this table of \(lqbookmarks\(rq may be displayed in a document outline pane,
+or \(lqBookmarks\(rq pane, to the left of the main document view.
+Individual references in the outline view may then be selected,
+by clicking with the mouse,
+to jump directly to the associated marked location in the document view.
+.LP
+The document outline may be considered as a collection of \(lqhypertext\(rq
+references to \(lqbookmarked\(rq locations within the document.
+The
+.CW pdfmark
+macro package provides a single generalised macro,
+.CW pdfhref ,
+for creating and linking to \(lqhypertext\(rq reference marks.
+This macro will be described more comprehensively in a later section,
+.XR pdfhref ); (
+the description here is restricted to its use for defining document outline entries.
+.NH 3
+.XN -N basic-outline -- A Basic Document Outline
+.LP
+In its most basic form, the document outline comprises a structured list of headings,
+each associated with a marked location, or \(lqbookmark\(rq, in the document text,
+and a specification for how that marked location should be displayed,
+when this bookmark is selected.
+.LP
+To create a PDF bookmark, the
+.CW pdfhref
+macro is used,
+at the point in the document where the bookmark is to be placed,
+in the form
+.QP
+.fam C
+.B ".pdfhref O"
+.I level > <
+.I "descriptive text ..."
+.LP
+in which the reference class
+.CWB O \& \& \(rq \(lq
+stipulates that this is an outline reference.
+.LP
+Alternatively, for those users who may prefer to think of a document outline
+simply as a collection of bookmarks, the
+.CW pdfbookmark
+macro is also provided \(em indeed,
+.CW pdfhref
+invokes it, when processing the
+.CWB O \& \& \(rq \(lq
+reference class operator.
+It may be invoked directly, in the form
+.QP
+.fam C
+.B .pdfbookmark
+.I level > <
+.I "descriptive text ..."
+.LP
+Irrespective of which of the above macro forms is employed, the
+.CWI level > <
+argument is required.
+It is a numeric argument, defining the nesting level of the \(lqbookmark\(rq
+in the outline hierarchy, with one being the topmost level.
+Its function may be considered analagous to the
+.EM "heading level"
+of the document's section headings,
+for example, as specified with the
+.CW NH
+macro, if using the
+.CW ms
+macros to format the document.
+.LP
+All further arguments, following the
+.CWI level > <
+argument, are collected together, to specify the heading text which will appear
+in the document's outline view.
+Thus, the outline entry for this section of this document,
+which has a level three heading,
+might be specified as
+.QP
+.CW
+\&.pdfhref O 3 \*(SN A Basic Document Outline
+.LP
+or, in the alternative form using the
+.CW pdfbookmark
+macro, as
+.QP
+.CW
+\&.pdfbookmark 3 \*(SN A Basic Document Outline
+.NH 3
+.XN Hierarchical Structure in a Document Outline
+.LP
+When a document outline is created, using the
+.CW pdfhref
+macro as described in
+.\"
+.\" Here is an example of how we can temporarily modify the format of
+.\" a reference link, in this case to indicate only the section number
+.\" of the link target, in the form "section #", (or, if we define
+.\" "SECREF.BEGIN" before the call, its content followed by the
+.\" section number).
+.\"
+.\" We first define a macro, which will get the reference data from
+.\" pdfhref, as arguments, and will return the formatted output, as we
+.\" require it, the string "PDFHREF.TEXT".
+.\"
+.de SECREF
+.while \\n(.$ \{\
+. ie '\\$1'section' \{\
+. if !dSECREF.BEGIN .ds SECREF.BEGIN \\$1
+. ds PDFHREF.TEXT \\*[SECREF.BEGIN]\~\\$2
+. rm SECREF.BEGIN
+. shift \\n(.$
+. \}
+. el .shift
+. \}
+..
+.\" We now tell "pdfhref" to use our formatting macro, in place of
+.\" its builtin default formatter, before we specify the reference.
+.\"
+.pdfhref F SECREF
+.pdfhref L -A , -D basic-outline
+.\"
+.\" At this point, we would normally revert the "pdfhref" formatter
+.\" to use its default, built in macro. However, in this particular
+.\" case, we want to use our custom format one more time, before we
+.\" revert it, so we will omit the reversion step this time.
+.\"
+and any entry is added at a nesting level greater than one,
+then a hierarchical structure is automatically defined for the outline.
+However, as was noted in the simplified
+.pdfhref L -D pdfmark-example -- example
+in
+.pdfhref L -A , -D pdfmark-operator
+.\"
+.\" And now, we revert to default "pdfhref" formatting behaviour,
+.\" by completing the call we delayed above.
+.\"
+.pdfhref F
+.\"
+the data required by the
+.CW pdfmark
+operator to create the outline entry may not be fully defined,
+when the outline reference is defined in the
+.CW groff
+document source.
+Specifically, when the outline entry is created, its
+.CW /Count
+key must be assigned a value equal to the number of its subordinate entries,
+at the next inner level of the outline hierarchy;
+typically however,
+these subordinate entries will be defined
+.EM later
+in the document source, and the appropriate
+.CW /Count
+value will be unknown, when defining the parent entry.
+.LP
+To resolve this paradox, the
+.CW pdfhref
+macro creates the outline entry in two distinct phases \(em
+a destination marker is placed in the PostScript\*(rg output stream immediately,
+when the outline reference is defined,
+but the actual outline entry is stored in an internal \(lqoutline cache\(rq,
+until its subordinate hierarchy has been fully defined;
+it can then be inserted in the output stream, with its
+.CW /Count
+value correctly assigned.
+Effectively, to ensure integrity of the document outline structure,
+this means that each top level outline entry, and
+.EM all
+of its subordinates, are retained in the cache, until the
+.EM next
+top level entry is defined.
+.LP
+One potential problem, which arises from the use of the \(lqoutline cache\(rq,
+is that, at the end of any document formatting run, the last top level outline entry,
+and any subordinates defined after it, will remain in the cache, and will
+.EM not
+be automatically written to the output stream.
+To avoid this problem, the user should follow the guidelines given in
+.\"
+.\" Here is a more conventional example of how to temporarily change
+.\" to the format used to display reference links. We will again use
+.\" the "SECREF" format, which we defined above, but on this occasion
+.\" we will immediately revert to the default format, after the link
+.\" has been placed.
+.\"
+.pdfhref F SECREF
+.pdfhref L -D pdfsync -A ,
+.pdfhref F
+.\"
+to synchronise the output state with the cache state,
+.XR pdfsync ), (
+at the end of the
+.CW groff
+formatting run.
+.NH 3
+.XN -N outline-view -- Associating a Document View with an Outline Reference
+.LP
+Each \(lqbookmark\(rq entry, in a PDF document outline,
+is associated with a specific document view.
+When the reader selects any outline entry,
+the document view changes to display the document context
+associated with that entry.
+.LP
+The document view specification,
+to be associated with any document outline entry,
+is established at the time when the outline entry is created.
+However, rather than requiring that each individual use of the
+.CW pdhref
+macro, to create an outline entry,
+should include its own view specification,
+the actual specification assigned to each entry is derived from
+a generalised specification defined in the string
+.CW PDFBOOKMARK.VIEW ,
+together with the setting of the numeric register
+.CW PDFHREF.VIEW.LEADING ,
+which determine the effective view specification as follows:\(en
+.QS
+.IP \*[= PDFBOOKMARK.VIEW]
+Establishes the magnification at which the document will be viewed,
+at the location of the \(lqbookmark\(rq; by default, it is defined by
+.RS
+.QP
+.CW ".ds PDFBOOKMARK.VIEW /FitH \e\en[PDFPAGE.Y] u"
+.RE
+.IP
+which displays the associated document view,
+with the \(lqbookmark\(rq location positioned at the top of the display window,
+and with the magnification set to fit the page width to the width of the window.
+.IP \*[= PDFHREF.VIEW.LEADING]
+Specifies additional spacing,
+to be placed between the top of the display window
+and the actual location of the \(lqbookmark\(rq on the displayed page view.
+By default, it is set as
+.RS
+.QP
+.CW ".nr PDFHREF.VIEW.LEADING 5.0p"
+.RE
+.IP
+Note that
+.CW PDFHREF.VIEW.LEADING
+does not represent true \(lqleading\(rq, in the typographical sense,
+since any preceding text, set in the specified display space,
+will be visible at the top of the document viewing window,
+when the reference is selected.
+.IP
+Also note that the specification of
+.CW PDFHREF.VIEW.LEADING
+is shared by
+.EM all
+reference views defined by the
+.CW pdfhref
+macro; whereas
+.CW PDFBOOKMARK.VIEW
+is applied exclusively to outline references,
+there is no independent
+.CW PDFBOOKMARK.VIEW.LEADING
+specification.
+.QE
+.LP
+If desired, the view specification may be changed, by redefining the string
+.CW PDFBOOKMARK.VIEW ,
+and possibly also the numeric register
+.CW PDFHREF.VIEW.LEADING .
+Any alternative definition for
+.CW PDFBOOKMARK.VIEW
+.EM must
+be specified in terms of valid view specification parameters,
+as described in the Adobe\*(rg
+.pdfmark-manual .
+.LP
+Note the use of the register
+.CW PDFPAGE.Y ,
+in the default definition of
+.CW PDFBOOKMARK.VIEW
+above.
+This register is computed by
+.CW pdfhref ,
+when creating an outline entry;
+it specifies the vertical position of the \(lqbookmark\(rq,
+in basic
+.CW groff
+units, relative to the
+.EM bottom
+edge of the document page on which it is defined,
+and is followed, in the
+.CW PDFBOOKMARK.VIEW
+definition, by the
+.CW grops
+.CW u \(rq \(lq
+operator, to convert it to PostScript\*(rg units on output.
+It may be used in any redefined specification for
+.CW PDFBOOKMARK.VIEW ,
+(or in the analogous definition of
+.CW PDFHREF.VIEW ,
+described in
+.XR-NO-PREFIX pdfhref-view ),
+but
+.EM not
+in any other context,
+since its value is undefined outside the scope of the
+.CW pdfhref
+macro.
+.LP
+Since
+.CW PDFPAGE.Y
+is computed relative to the
+.EM bottom
+of the PDF output page,
+it is important to ensure that the page length specified to
+.CW troff
+correctly matches the size of the logical PDF page.
+This is most effectively ensured,
+by providing
+.EM identical
+page size specifications to
+.CW groff ,
+.CW grops
+and to the PostScript\*(rg to PDF converter employed,
+and avoiding any page length changes within the document source.
+.LP
+Also note that
+.CW PDFPAGE.Y
+is the only automatically computed \(lqbookmark\(rq location parameter;
+if the user redefines
+.CW PDFBOOKMARK.VIEW ,
+and the modified view specification requires any other positional parameters,
+then the user
+.EM must
+ensure that these are computed
+.EM before
+invoking the
+.CW pdfhref
+macro.
+.NH 3
+.XN -N multipart-outline -- Outlines for Multipart Documents
+.LP
+When a document outline is created, using the
+.CW pdfhref
+macro, each reference mark is automatically assigned a name,
+composed of a fixed stem followed by a serially generated numeric qualifier.
+This ensures that, for each single part document, every outline reference
+has a uniquely named destination.
+.LP
+As the overall size of the PDF document increases,
+it may become convenient to divide it into smaller,
+individually formatted PostScript\*(rg components,
+which are then assembled, in the appropriate order,
+to create a composite PDF document.
+While this strategy may simplify the overall process of creating and
+editing larger documents, it does introduce a problem in creating
+an overall document outline,
+since each individual PostScript\*(rg component will be assigned
+duplicated sequences of \(lqbookmark\(rq names,
+with each name ultimately referring to multiple locations in the composite document.
+To avoid such reference naming conflicts, the
+.CW pdfhref
+macro allows the user to specify a \(lqtag\(rq,
+which is appended to the automatically generated \(lqbookmark\(rq name;
+this may be used as a discriminating mark, to distinguish otherwise
+similarly named destinations, in different sections of the composite document.
+.LP
+To create a \(lqtagged\(rq document outline,
+the syntax for invocation of the
+.CW pdfhref
+macro is modified, by the inclusion of an optional \(lqtag\(rq specification,
+.EM before
+the nesting level argument, i.e.
+.QP
+.fam C
+.B ".pdfhref O"
+.B -T \& [
+.I tag >] <
+.I level > <
+.I "descriptive text ..."
+.LP
+The optional
+.CWI tag > <
+argument may be composed of any characters of the user's choice;
+however, its initial character
+.EM "must not"
+be any decimal digit, and ideally it should be kept short
+\(em one or two characters at most.
+.LP
+By employing a different tag in each section,
+the user can ensure that \(lqbookmark\(rq names remain unique,
+throughout all the sections of a composite document.
+For example, when using the
+.CW spdf.tmac
+macro package, which adds
+.CW pdfmark
+capabilities to the standard
+.CW ms
+package,
+.XR using-spdf ), (
+the table of contents is collected into a separate PostScript\*(rg section
+from the main body of the document.
+In the \(lqbody\(rq section, the document outline is \(lquntagged\(rq,
+but in the \(lqTable\~of\~Contents\(rq section, a modified version of the
+.CW TC
+macro adds an outline entry for the start of the \(lqTable\~of\~Contents\(rq,
+invoking the
+.CW pdfhref
+macro as
+.QP
+.CW ".pdfhref O -T T 1 \e\e*[TOC]"
+.LP
+to tag the associated outline destination name with the single character suffix,
+.CW T \(rq. \(lq
+Alternatively, as in the case of the basic outline,
+.XR basic-outline ), (
+this may equally well be specified as
+.QP
+.CW ".pdfbookmark -T T 1 \e\e*[TOC]"
+.NH 3
+.XN Delegation of the Outline Definition
+.LP
+Since the most common use of a document outline
+is to provide a quick method of navigating through a document,
+using active \(lqhypertext\(rq links to chapter and section headings,
+it may be convenient to delegate the responsibility of creating the outline
+to a higher level macro, which is itself used to
+define and format the section headings.
+This approach has been adopted in the
+.CW spdf.tmac
+package, to be described later,
+.XR using-spdf ). (
+.LP
+When such an approach is adopted,
+the user will rarely, if ever, invoke the
+.CW pdfhref
+macro directly, to create a document outline.
+For example, the structure and content of the outline for this document
+has been exclusively defined, using a combination of the
+.CW NH
+macro, from the
+.CW ms
+package, to establish the structure, and the
+.CW XN
+macro from
+.CW spdf.tmac ,
+to define the content.
+In this case,
+the responsibility for invoking the
+.CW pdfhref
+macro, to create the document outline,
+is delegated to the
+.CW XN
+macro.
+.NH 2
+.XN -N pdfhref -- Adding Reference Marks and Links
+.LP
+.pdfhref F SECREF
+.ds SECREF.BEGIN Section
+.pdfhref L -D add-outline
+.pdfhref F
+has shown how the
+.CW pdfhref
+macro may be used to create a PDF document outline.
+While this is undoubtedly a powerful capability,
+it is by no means the only trick in the repertoire of this versatile macro.
+.LP
+The macro name,
+.CW pdfhref ,
+which is a contraction of \(lqPDF HyperText Reference\(rq,
+indicates that the general purpose of this macro is to define
+.EM any
+type of dynamic reference mark, within a PDF document.
+Its generalised usage syntax takes the form
+.QP
+.fam C
+.B .pdfhref
+.BI class > <
+.I "-options ...\&" ] [
+[--]
+.I "descriptive text ...\&" ] [
+.LP
+where
+.CW <\f(CIclass\fP>
+represents a required single character argument,
+which defines the specific reference operation to be performed,
+and may be selected from:\(en
+.QS
+.IP \*[= O]
+Add an entry to the document outline.
+This operation has been described earlier,
+.XR add-outline ). (
+.IP \*[= M]
+Place a \(lqnamed destination\(rq reference mark at the current output position,
+in the current PDF document,
+.XR mark-dest ). (
+.IP \*[= L]
+Insert an active link to a named destination,
+.XR link-named ), (
+at the current output position in the current PDF document,
+such that when the reader clicks on the link text,
+the document view changes to show the location of the named destination.
+.IP \*[= W]
+Insert an active link to a \(lqweb\(rq resource,
+.XR add-weblink ), (
+at the current output position in the current PDF document.
+This is effectively the same as using the
+.CWB L \& \& \(rq \(lq
+operator to establish a link to a named destination in another PDF document,
+.XR link-extern ), (
+except that in this case, the destination is specified by a
+\(lquniform resource identifier\(rq, or
+.CW URI ;
+this may represent any Internet or local resource
+which can be specified in this manner.
+.IP \*[= F]
+Specify a user defined macro, to be called by
+.CW pdfhref ,
+when formatting the text in the active region of a link,
+.XR set-format ). (
+.IP \*[= I]
+Initialise support for
+.CW pdfhref
+features.
+The current
+.CW pdfhref
+implementation provides only one such feature which requires initialisation
+\(em a helper macro which must be attached to a user supplied page trap handler,
+in order to support mapping of reference \(lqhot\(hyspots\(rq
+which extend through a page transition;
+.XR page-trap ). (
+.QE
+.NH 3
+.XN Optional Features of the \F[C]pdfhref\F[] Macro
+.LP
+The behaviour of a number of the
+.CW pdfhref
+macro operations can be modified,
+by including
+.EM "option specifiers" \(rq \(lq
+after the operation specifying argument,
+but
+.EM before
+any other arguments normally associated with the operation.
+In
+.EM all
+cases, an option is specified by an
+.EM "option flag" \(rq, \(lq
+comprising an initial hyphen,
+followed by one or two option identifying characters.
+Additionally,
+.EM some
+options require
+.EM "exactly one"
+option argument;
+for these options, the argument
+.EM must
+be specified, and it
+.EM must
+be separated from the preceding option flag by one or more
+.EM spaces ,
+(tabs
+.EM "must not"
+be used).
+It may be noted that this paradigm for specifying options
+is reminiscent of most
+.SM
+UNIX\(tm
+.LG
+shells; however, in the case of the
+.CW pdfhref
+macro, omission of the space separating an option flag from its argument is
+.EM never
+permitted.
+.LP
+A list of
+.EM all
+general purpose options supported by the
+.CW pdfhref
+macro is given below.
+Note that not all options are supported for all
+.CW pdfhref
+operations; the operations affected by each option are noted in the list.
+For
+.EM most
+operations, if an unsupported option is specified,
+it will be silently ignored; however, this behaviour should
+not be relied upon.
+.LP
+The general purpose options, supported by the
+.CW pdfhref
+macro, are:\(en
+.QS
+.IP \*[= -N\0 name > <]
+Allows the
+.CWI name > <
+associated with a PDF reference destination
+to be defined independently from the following text,
+which describes the reference.
+This option affects only the
+.CWB M \& \& \(rq \(lq
+operation of the
+.CW pdfhref
+macro,
+.XR mark-dest ). (
+.IP \*[= -E]
+Also used exclusively with the
+.CWB M \& \& \(rq \(lq
+operator, the
+.CWB -E
+option causes any specified
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments,
+.XR mark-dest ), (
+to be copied, or
+.EM echoed ,
+in the body text of the document,
+at the point where the reference mark is defined;
+(without the
+.CWB -E
+option, such
+.CWI descriptive \& \& \~\c
+.CWI text
+will appear
+.EM only
+at points where links to the reference mark are placed,
+and where the standard reference display format,
+.XR set-format ), (
+is used).
+.IP \*[= -D\0 dest > <]
+Specifies the
+.CW URI ,
+or the destination name associated with a PDF active link,
+independently of the following text,
+which describes the link and demarcates the link \(lqhot\(hyspot\(rq.
+This option affects the behaviour of the
+.CW pdfhref
+macro's
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+operations.
+.IP
+When used with the
+.CWB L \& \& \(rq \(lq
+operator, the
+.CWI dest > <
+argument must specify a PDF \(lqnamed destination\(rq,
+as defined using
+.CW pdfhref
+with the
+.CWB M \& \& \(rq \(lq
+operator.
+.IP
+When used with the
+.CWB W \& \& \(rq \(lq
+operator,
+.CWI dest > <
+must specify a link destination in the form of a
+\(lquniform resource identifier\(rq, or
+.CW URI ,
+.XR add-weblink ). (
+.IP \*[= -F\0 file > <]
+When used with the
+.CWB L \& \& \(rq \(lq
+.CW pdfhref
+operator,
+.CWI file > <
+specifies an external PDF file in which the named destination
+for the link reference is defined.
+This option
+.EM must
+be specified with the
+.CWB L \& \& \(rq \(lq
+operator,
+to create a link to a destination in a different PDF document;
+when the
+.CWB L \& \& \(rq \(lq
+operator is used
+.EM without
+this option, the link destination is assumed to be defined
+within the same document.
+.IP \*[= -P\0 \(dqprefix\(hytext\(dq > <]
+Specifies
+.CWI \(dqprefix\(hytext\(dq > <
+to be attached to the
+.EM start
+of the text describing an active PDF document link,
+with no intervening space, but without itself being included in the
+active area of the link \(lqhot\(hyspot\(rq;
+it is effective with the
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+.CW pdfhref
+operators.
+.IP
+Typically, this option would be used to insert punctuation before
+the link \(lqhot\(hyspot\(rq.
+Thus, there is little reason for the inclusion of spaces in
+.CWI \(dqprefix\(hytext\(dq > < ;
+however, if such space is required, then the enclosing double quotes
+.EM must
+be specified, as indicated.
+.IP \*[= -A\0 \(dqaffixed\(hytext\(dq > <]
+Specifies
+.CWI \(dqaffixed\(hytext\(dq > <
+to be attached to the
+.EM end
+of the text describing an active PDF document link,
+with no intervening space, but without itself being included in the
+active area of the link \(lqhot\(hyspot\(rq;
+it is effective with the
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+.CW pdfhref
+operators.
+.IP
+Typically, this option would be used to insert punctuation after
+the link \(lqhot\(hyspot\(rq.
+Thus, there is little reason for the inclusion of spaces in
+.CWI \(dqaffixed\(hytext\(dq > < ;
+however, if such space is required, then the enclosing double quotes
+.EM must
+be specified, as indicated.
+.IP \*[= -T\0 tag > <]
+When specified with the
+.CWB O \& \& \(rq \(lq
+operator,
+.CWI tag > <
+is appended to the \(lqbookmark\(rq name assigned to the generated outline entry.
+This option is
+.EM required ,
+to distinguish between the series of \(lqbookmark\(rq names generated in
+individual passes of the
+.CW groff
+formatter, when the final PDF document is to be assembled
+from a number of separately formatted components;
+.XR multipart-outline ). (
+.IP \*[= -X]
+This
+.CW pdfhref
+option is used with either the
+.CWB M \& \& \(rq \(lq
+operator, or with the
+.CWB L \& \& \(rq \(lq
+operator.
+.IP
+When used with the
+.CWB M \& \& \(rq \(lq
+operator,
+.XR mark-dest ), (
+it ensures that a cross reference record for the marked destination
+will be included in the document reference map,
+.XR export-map ). (
+.IP
+When used with the
+.CWB L \& \& \(rq \(lq
+operator,
+.XR link-named ), (
+it causes the reference to be displayed in the standard cross reference format,
+.XR set-format ), (
+but substituting the
+.CWI descriptive \& \& \~\c
+.CWI text
+specified in the
+.CW pdfhref \& \(lq
+.CW L \(rq
+argument list,
+for the description specified in the document reference map.
+.IP \*[= --]
+Marks the end of the option specifiers.
+This may be used with all
+.CW pdfhref
+operations which accept options, to prevent
+.CW pdfhref
+from interpreting any following arguments as option specifiers,
+even if they would otherwise be interpreted as such.
+It is also useful when the argument list to
+.CW pdfhref
+contains special characters \(em any special character,
+which is not legal in a
+.CW groff
+macro name, will cause a parsing error, if
+.CW pdfhref
+attempts to match it as a possible option flag;
+using the
+.CW -- \(rq \(lq
+flag prevents this, so suppressing the
+.CW groff
+warning message, which would otherwise ensue.
+.IP
+Using this flag after
+.EM all
+sequences of macro options is recommended,
+even when it is not strictly necessary,
+if only for the entirely cosmetic benefit of visually separating
+the main argument list from the sequence of preceding options.
+.QE
+.LP
+In addition to the
+.CW pdfhref
+options listed above, a supplementary set of two character options are defined.
+These supplementary options, listed below, are intended for use with the
+.CWB L \& \& \(rq \(lq
+operator, in conjunction with the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, to specify alternate file names,
+in formats compatible with the file naming conventions
+of alternate operating systems;
+they will be silently ignored, if used in any other context.
+.LP
+The supported alternate file name options,
+which are ignored if the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option is not specified, are:\(en
+.QS
+.IP \*[= -DF\0 dos\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW MS\(hyDOS \*(rg
+operating system.
+When the PDF document is read on a machine
+where the operating system uses the
+.CW MS\(hyDOS \*(rg
+file system, then
+.CWI dos\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -MF\0 mac\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW Apple \*(rg
+.CW Macintosh \*(rg
+operating system.
+When the PDF document is read on a machine
+where the operating system uses the
+.CW Macintosh \*(rg
+file system, then
+.CWI mac\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -UF\0 unix\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW UNIX \(tm
+operating system.
+When the PDF document is read on a machine
+where the operating system uses
+.CW POSIX
+file naming semantics, then
+.CWI unix\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -WF\0 win\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW MS\(hyWindows \*(rg
+32\(hybit operating system.
+When the PDF document is read on a machine
+where the operating system uses any of the
+.CW MS\(hyWindows \*(rg
+file systems, with long file name support, then
+.CWI win\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.QE
+.NH 3
+.XN -N mark-dest -- Marking a Reference Destination
+.LP
+The
+.CW pdfhref
+macro may be used to create active links to any Internet resource,
+specified by its
+.CW URI ,
+or to any \(lqnamed destination\(rq,
+either within the same document, or in another PDF document.
+Although the PDF specification allows link destinations to be defined
+in terms of a page number, and an associated view specification,
+this style of reference is not currently supported by the
+.CW pdfhref
+macro, because it is not possible to adequately bind the specification
+for the destination with the intended reference context.
+.LP
+References to Internet resources are interpreted in accordance with the
+.CW W3C
+standard for defining a
+.CW URI ;
+hence the only prerequisite, for creating a link to any Internet resource,
+is that the
+.CW URI
+be properly specified, when declaring the reference;
+.XR add-weblink ). (
+In the case of references to \(lqnamed destinations\(rq in PDF documents,
+however, it is necessary to provide a mechanism for creating such
+\(lqnamed destinations\(rq.
+This may be accomplished, by invoking the
+.CW pdfhref
+macro in the form
+.QP
+.fam C
+.B ".pdfhref M"
+.B -N \& [
+.I name >] <
+.B -X ] [
+.B -E ] [
+.I "descriptive text ...\&" ] [
+.LP
+This creates a \(lqnamed destination\(rq reference mark, with its name specified by
+.CWI name > < ,
+or, if the
+.CWB -N
+option is not specified, by the first word of
+.CWI descriptive \& \& \~\c
+.CWI text \& \& ;
+(note that this imposes the restriction that,
+if the
+.CWB -N
+option is omitted, then
+.EM "at least"
+one word of
+.CWI descriptive \& \& \~\c
+.CWI text
+.EM must
+be specified).
+Additionally, a reference view will be automatically defined,
+and associated with the reference mark,
+.XR pdfhref-view ), (
+.\" and, if any
+.\" .CWI descriptive
+.\" .CWI text
+.\" is specified, or the
+and, if the
+.CWB -X
+option is specified, and no document cross reference map has been imported,
+.XR import-map ), (
+then a cross reference mapping record,
+.XR export-map ), (
+will be written to the
+.CW stdout
+stream;
+this may be captured, and subsequently used to generate a cross reference map
+for the document,
+.XR create-map ). (
+.LP
+When a \(lqnamed destination\(rq reference mark is created, using the
+.CW pdfhref
+macro's
+.CWB M \& \& \(rq \(lq
+operator, there is normally no visible effect in the formatted document; any
+.CWI descriptive \& \& \~\c
+.CWI text
+which is specified will simply be stored in the cross reference map,
+for use when a link to the reference mark is created.
+This default behaviour may be changed, by specifying the
+.CWB -E
+option, which causes any specified
+.CWI descriptive \& \& \~\c
+.CWI text
+to be \(lqechoed\(rq in the document text,
+at the point where the reference mark is placed,
+in addition to its inclusion in the cross reference map.
+.NH 4
+.XN -N export-map -- Mapping a Destination for Cross Referencing
+.LP
+Effective cross referencing of
+.EM any
+document formatted by
+.CW groff
+requires multiple pass formatting.
+Details of how this multiple pass formatting may be accomplished,
+when working with the
+.CW pdfmark
+macros, will be discussed later,
+.XR do-xref ); (
+at this stage, the discussion will be restricted to the initial preparation,
+which is required at the time when the cross reference destinations are defined.
+.LP
+The first stage, in the process of cross referencing a document,
+is the generation of a cross reference map.
+Again, the details of
+.EM how
+the cross reference map is generated will be discussed in
+.pdfhref F SECREF L -D do-xref -A ;
+.pdfhref F
+however, it is important to recognise that
+.EM what
+content is included in the cross reference map is established
+when the reference destination is defined \(em it is derived
+from the reference data exported on the
+.CW stderr
+stream by the
+.CW pdfhref
+macro, when it is invoked with the
+.CWB M \& \& \(rq \(lq
+operator, and is controlled by whatever definition of the string
+.CW PDFHREF.INFO
+is in effect, when the
+.CW pdfhref
+macro is invoked.
+.LP
+The initial default setting of
+.CW PDFHREF.INFO
+is
+.QP
+.CW ".ds PDFHREF.INFO page \e\en% \e\e$*"
+.LP
+which ensures that the cross reference map will contain
+at least a page number reference, supplemented by any
+.CWI descriptive \& \& \~\c
+.CWI text
+which is specified for the reference mark, as defined by the
+.CW pdfhref
+macro, with its
+.CWB M \& \& \(rq \(lq
+operator; this may be redefined by the user,
+to export additional cross reference information,
+or to modify the default format for cross reference links,
+.XR set-format ). (
+.NH 4
+.XN -N pdfhref-view -- Associating a Document View with a Reference Mark
+.LP
+In the same manner as each document outline reference, defined by the
+.CW pdfhref
+macro with the
+.CWB O \& \& \(rq \(lq
+operator,
+.XR add-outline ), (
+has a specific document view associated with it,
+each reference destination marked by
+.CW pdfhref
+with the
+.CWB M \& \& \(rq \(lq
+operator, requires an associated document view specification.
+.LP
+The mechanism whereby a document view is associated with a reference mark
+is entirely analogous to that employed for outline references,
+.XR outline-view ), (
+except that the
+.CW PDFHREF.VIEW
+string specification is used, in place of the
+.CW PDFBOOKMARK.VIEW
+specification.
+Thus, the reference view is defined in terms of:\(en
+.QS
+.IP \*[= PDFHREF.VIEW]
+A string,
+establishing the position of the reference mark within the viewing window,
+and the magnification at which the document will be viewed,
+at the location of the marked reference destination;
+by default, it is defined by
+.RS
+.QP
+.CW ".ds PDFHREF.VIEW /FitH \e\en[PDFPAGE.Y] u"
+.RE
+.IP
+which displays the reference destination at the top of the viewing window,
+with the magnification set to fit the page width to the width of the window.
+.IP \*[= PDFHREF.VIEW.LEADING]
+A numeric register,
+specifying additional spacing, to be placed between the top of the display
+window and the actual position at which the location of the reference
+destination appears within the window.
+This register is shared with the view specification for outline references,
+and thus has the same default initial setting,
+.RS
+.QP
+.CW ".nr PDFHREF.VIEW.LEADING 5.0p"
+.RE
+.IP
+as in the case of outline reference views.
+.IP
+Again, notice that
+.CW PDFHREF.VIEW.LEADING
+does not represent true typographic \(lqleading\(rq,
+since any preceding text, set in the specified display space,
+will be visible at the top of the viewing window,
+when the reference is selected.
+.QE
+.LP
+Just as the view associated with outline references may be changed,
+by redefining
+.CW PDFBOOKMARK.VIEW ,
+so the view associated with marked reference destinations may be changed,
+by redefining
+.CW PDFHREF.VIEW ,
+and, if desired,
+.CW PDFHREF.VIEW.LEADING ;
+such changes will become effective for all reference destinations marked
+.EM after
+these definitions are changed.
+(Notice that, since the specification of
+.CW PDFHREF.VIEW.LEADING
+is shared by both outline reference views and marked reference views,
+if it is changed, then the views for
+.EM both
+reference types are changed accordingly).
+.LP
+It may again be noted, that the
+.CW PDFPAGE.Y
+register is used in the definition of
+.CW PDFHREF.VIEW ,
+just as it is in the definition of
+.CW PDFBOOKMARK.VIEW ;
+all comments in
+.pdfhref F SECREF L -D outline-view
+.pdfhref F
+relating to its use, and indeed to page position computations in general,
+apply equally to marked reference views and to outline reference views.
+.NH 3
+.XN -N link-named -- Linking to a Marked Reference Destination
+.LP
+Any named destination, such as those marked by the
+.CW pdfhref
+macro, using it's
+.CWB M \& \& \(rq \(lq
+operator, may be referred to from any point in
+.EM any
+PDF document, using an
+.EM "active link" ;
+such active links are created by again using the
+.CW pdfhref
+macro, but in this case, with the
+.CWB L \& \& \(rq \(lq
+operator.
+This operator provides support for two distinct cases,
+depending on whether the reference destination is defined in
+the same document as the link,
+.XR link-intern ), (
+or is defined as a named destination in a different PDF document,
+.XR link-extern ). (
+.NH 4
+.XN -N link-intern -- References within a Single PDF Document
+.LP
+The general syntactic form for invoking the
+.CW pdfhref
+macro,
+when creating a link to a named destination within the same PDF document is
+.QP
+.fam C
+.B .pdfhref
+.B L
+.B -D \& [
+.BI dest-name >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -X ] [
+.B -- ] [
+.I "descriptive text ...\&" ] [
+.LP
+where
+.CWI dest-name > <
+specifies the name of the link destination,
+as specified using the
+.CW pdfhref
+.CWB M \& \& \(rq \(lq
+operation; (it may be defined either earlier in the document,
+to create a backward reference, or later, to create a forward reference).
+.\"
+.\" Here's a example of how to add an iconic annotation.
+.\"
+.\".pdfnote -T "Internal Cross References" \
+.\" This description is rather terse, and could benefit from \
+.\" the inclusion of an example.
+.LP
+If any
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments are specified, then they will be inserted into the
+.CW groff
+output stream, to define the text appearing in the \(lqhot\(hyspot\(rq
+region of the link;
+this will be printed in the link colour specified by the string,
+.CW PDFHREF.TEXT.COLOUR ,
+which is described in
+.XR-NO-PREFIX set-colour .
+If the
+.CWB -X
+option is also specified, then the
+.CWI descriptive \& \& \~\c
+.CWI text
+will be augmented, by prefacing it with page and section number indicators,
+in accordance with the reference formatting rules which are in effect,
+.XR set-format ); (
+such indicators will be included within the active link region,
+and will also be printed in the link colour.
+.LP
+Note that
+.EM either
+the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option,
+.EM or
+the
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments,
+.EM "but not both" ,
+may be omitted.
+If the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option is omitted, then the first word of
+.CWI descriptive \& \& \~\c
+.CWI text \& \& ,
+i.e.\~all text up to but not including the first space,
+will be interpreted as the
+.CWBI dest\(hyname > <
+for the link; this text will also appear in the running text of the document,
+within the active region of the link.
+Alternatively, if the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option
+.EM is
+specified, and
+.CWI descriptive \& \& \~\c
+.CWI text
+is not,
+then the running text which defines the reference,
+and its active region,
+will be derived from the reference description which is specified
+when the named destination is marked,
+.XR mark-dest ), (
+and will be formatted according to the reference formatting rules
+which are in effect, when the reference is placed,
+.XR set-format ); (
+in this case, it is not necessary to specify the
+.CWB -X
+option to activate automatic formatting of the reference \(em it is implied,
+by the omission of all
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments.
+.LP
+The
+.CWB -P \& \& \~\c
+.CWBI prefix\(hytext > <
+and
+.CWB -A \& \& \~\c
+.CWBI affixed\(hytext > <
+options may be used to specify additional text
+which will be placed before and after the linked text respectively,
+with no intervening space.
+Such prefixed and affixed text will be printed in the normal text colour,
+and will not be included within the active region of the link.
+This feature is mostly useful for creating parenthetical references,
+or for placing punctuation adjacent to,
+but not included within,
+the text which defines the active region of the link.
+.LP
+The operation of the
+.CW pdfhref
+macro, when used with its
+.CWB L \& \& \(rq \(lq
+operator to place a link to a named PDF destination,
+may best be illustrated by an example.
+However, since the appearance of the link will be influenced by
+factors established when the named destination is marked,
+.XR mark-dest ), (
+and also by the formatting rules in effect when the link is placed,
+the presentation of a suitable exanple will be deferred,
+until the formatting mechanism has been explained,
+.XR set-format ). (
+.NH 4
+.XN -N link-extern -- References to Destinations in Other PDF Documents
+.LP
+The
+.CW pdfhref
+macro's
+.CWB L \& \& \(rq \(lq
+operator is not restricted to creating reference links
+within a single PDF document.
+When the link destination is defined in a different document,
+then the syntactic form for invoking
+.CW pdfhref
+is modified, by the addition of options to specify the
+name and location of the PDF file in which the destination is defined.
+Thus, the extended
+.CW pdfhref
+syntactic form becomes
+.QP
+.fam C
+.B .pdfhref
+.B L
+.B -F
+.BI file > <
+.B -D \& [
+.BI dest-name >] <
+\e
+.br
+\0\0\0
+.B -DF \& [
+.BI dos-file >] <
+.B -MF \& [
+.BI mac-file >] <
+.B -UF \& [
+.BI unix-file >] <
+\e
+.br
+\0\0\0
+.B -WF \& [
+.BI win-file >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -X ] [
+.B -- ] [
+.I "descriptive text ...\&" ] [
+.LP
+where the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option serves
+.EM two
+purposes: it both indicates to the
+.CW pdfhref
+macro that the specified reference destination
+is defined in an external PDF file,
+and it also specifies the normal path name,
+which is to be used to locate this file,
+when a user selects the reference.
+.LP
+In addition to the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, which
+.EM must
+be specified when referring to a destination in an external PDF file,
+the
+.CWB -DF \& \& \~\c
+.CWBI dos\(hyfile > < ,
+.CWB -MF \& \& \~\c
+.CWBI mac\(hyfile > < ,
+.CWB -UF \& \& \~\c
+.CWBI unix\(hyfile > <
+and
+.CWB -WF \& \& \~\c
+.CWBI win\(hyfile > <
+options may be used to specify the location of the file
+containing the reference destination,
+in a variety of operating system dependent formats.
+These options assign their arguments to the
+.CW /DosFile ,
+.CW /MacFile ,
+.CW /UnixFile
+and
+.CW /WinFile
+keys of the generated
+.CW pdfmark
+respectively; thus when any of these options are specified,
+.EM "in addition to"
+the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, and the document is read on the appropriate operating systems,
+then the path names specified by
+.CWBI dos\(hyfile > < ,
+.CWBI mac\(hyfile > < ,
+.CWBI unix\(hyfile > <
+and
+.CWBI win\(hyfile > <
+will be searched,
+.EM instead
+of the path name specified by
+.CWBI file > < ,
+for each of the
+.CW MS\(hyDOS \*(rg,
+.CW Apple \*(rg
+.CW Macintosh \*(rg,
+.CW UNIX \(tm
+and
+.CW MS\(hyWindows \*(rg
+operating systems, respectively; see the
+.pdfmark-manual ,
+for further details.
+.LP
+Other than the use of these additional options,
+which specify that the reference destination is in an external PDF file,
+the behaviour of the
+.CW pdfhref
+.CWB L \& \& \(rq \(lq
+operator, with the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, remains identical to its behaviour
+.EM without
+this option,
+.XR link-intern ), (
+with respect to the interpretation of other options,
+the handling of the
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments, and the formatting of the displayed reference.
+.LP
+Once again, since the appearance of the reference is determined by
+factors specified in the document reference map,
+and also by the formatting rules in effect when the reference is placed,
+the presentation of an example of the placing of
+a reference to an external destination will be deferred,
+until the formatting mechanism has been explained,
+.XR set-format ). (
+.NH 3
+.XN -N add-weblink -- Linking to Internet Resources
+.LP
+In addition to supporting the creation of cross references
+to named destinations in PDF documents, the
+.CW pdfhref
+macro also has the capability to create active links to Internet resources,
+or indeed to
+.EM any
+resource which may be specified by a Uniform Resource Identifier,
+(which is usually abbreviated to the acronym \(lqURI\(rq,
+and sometimes also referred to as a Uniform Resource Locator,
+or \(lqURL\(rq).
+.LP
+Since the mechanism for creating a link to a URI differs somewhat
+from that for creating PDF references, the
+.CW pdfhref
+macro is invoked with the
+.CWB W \& \& \(rq \(lq
+(for \(lqweb\(hylink\(rq) operator, rather than the
+.CWB L \& \& \(rq \(lq
+operator; nevertheless, the invocation syntax is similar, having the form
+.QP
+.fam C
+.B .pdfhref
+.B W
+.B -D \& [
+.BI URI >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -- ] [
+.I "descriptive text ...\&"
+.LP
+where
+.NH 3
+.XN -N set-format -- Establishing a Format for References
+.LP
+There are two principal aspects to be addressed,
+when defining the format to be used when displaying references.
+Firstly, it is desirable to provide a visual cue,
+to indicate that the text describing the reference is imbued
+with special properties \(em it is dynamically linked to the reference
+destination \(em and secondly, the textual content should
+describe where the link leads, and ideally,
+it should also describe the content of the reference destination.
+.LP
+The visual cue,
+that a text region defines a dynamically linked reference,
+is most commonly provided by printing the text within the active
+region in a distinctive colour.
+This technique will be employed automatically by the
+.CW pdfhref
+macro \(em
+.XR set-colour
+\(em unless the user specifically chooses to adopt, and implement,
+some alternative strategy.
+.NH 4
+.XN -N set-colour -- Using Colour to Demarcate Link Regions
+.LP
+Typically, when a PDF document contains
+.EM active
+references to other locations, either within the same document,
+or even in other documents, or on the World Wide Web,
+it is usually desirable to make the regions
+where these active links are placed stand out from the surrounding text.
+.NH 4
+.XN -N user-format -- Specifying Reference Text Explicitly
+.NH 4
+.XN -N auto-format -- Using Automatically Formatted Reference Text
+.NH 4
+.XN -N custom-format -- Customising Automatically Formatted Reference Text
+.LP
+It is incumbent on the user,
+if employing automatic formatting of the displayed reference,
+.XR set-format ), (
+to ensure that an appropriate reference definition
+is created for the reference destination,
+and is included in the reference map for the document
+in which the reference will appear;
+thus, it may be easiest to
+.EM always
+use manual formatting for external references.
+.NH 3
+.XN Problematic Links
+.LP
+Irrespective of whether a
+.CW pdfhref
+reference is placed using the
+.CWB L \& \& \(rq \(lq
+operator, or the
+.CWB W \& \& \(rq \(lq
+operator, there may be occasions when the resulting link
+does function as expected.
+A number of scenarios, which are known to be troublesome,
+are described below.
+.NH 4
+.XN -N page-trap -- Links with a Page Transition in the Active Region
+.LP
+When a link is placed near the bottom of a page,
+it is possible that its active region, or \(lqhot\(hyspot\(rq,
+may extend on to the next page.
+In this situation, a page trap macro is required
+to intercept the page transition, and to restart the mapping of
+the \(lqhot\(hyspot\(rq boundary on the new page.
+.LP
+The
+.CW pdfmark
+macro package includes a suitable page trap macro, to satisfy this requirement.
+However, to avoid pre\(hyempting any other requirement the user may have for
+a page transition trap, this is
+.EM not
+installed as an active page trap,
+unless explicitly requested by the user.
+.LP
+To enable proper handling of page transitions,
+which occur within the active regions of reference links,
+the user should:\(en
+.QS
+.nr ITEM 0 1
+.IP \n+[ITEM].
+Define a page transition macro, to provide whatever features may be required,
+when a page transition occurs \(em e.g.\& printing footnotes,
+adding page footers and headers, etc.
+This macro should end by setting the output position at the correct
+vertical page offset, where the printing of running text is to restart,
+following the page transition.
+.IP \n+[ITEM].
+Plant a trap to invoke this macro, at the appropriate vertical position
+marking the end of normal running text on each page.
+.KS
+.IP \n+[ITEM].
+Initialise the
+.CW pdfhref
+hook into this page transition trap, by invoking
+.RS
+.IP
+.fam C
+.B "pdfhref I -PT"
+.BI macro-name > <
+.LP
+where
+.CWBI macro-name > <
+is the name of the user supplied page trap macro,
+to ensure that
+.CW pdfhref
+will correctly restart mapping of active link regions,
+at the start of each new page.
+.KE
+.RE
+.QE
+.LP
+It may be observed that this initialisation of the
+.CW pdfhref
+page transition hook is, typically, required only once
+.EM before
+document formatting begins.
+Users of document formatting macro packages may reasonably expect that
+this initialisation should be performed by the macro package itself.
+Thus, writers of such macro packages which include
+.CW pdfmark
+bindings, should provide appropriate initialisation,
+so relieving the end user of this responsibility.
+The following example, abstracted from the sample
+.CW ms
+binding package,
+.CW spdf.tmac ,
+illustrates how this may be accomplished:\(en
+.DS I
+.CW
+\&.\e" groff "ms" provides the "pg@bottom" macro, which has already
+\&.\e" been installed as a page transition trap. To ensure proper
+\&.\e" mapping of "pdfhref" links which overflow the bottom of any
+\&.\e" page, we need to install the "pdfhref" page transition hook,
+\&.\e" as an addendum to this macro.
+\&.
+\&.pdfhref I -PT pg@bottom
+.DE
+.NH 2
+.XN -N add-note -- Annotating a PDF Document using Pop-Up Notes
+.NH 2
+.XN -N pdfsync -- Synchronising Output and \F[C]pdfmark\F[] Contexts
+.LP
+It has been noted previously, that the
+.CW pdfview
+macro,
+.XR docview ), (
+the
+.CW pdfinfo
+macro,
+.XR docinfo ), (
+and the
+.CW pdfhref
+macro, when used to create a document outline,
+.XR add-outline ), (
+do not immediately write their
+.CW pdfmark
+output to the PostScript\*(rg data stream;
+instead, they cache their output, in a
+.CW groff
+diversion, in the case of the
+.CW pdfview
+and
+.CW pdfinfo
+macros, or in an ordered collection of strings and numeric registers,
+in the case of the document outline,
+until a more appropriate time for copying it out.
+In the case of
+.CW pdfview
+and
+.CW pdfinfo
+\(lqmeta\(hydata\(rq,
+this \(lqmore appropriate time\(rq is explicitly chosen by the user;
+in the case of document outline data,
+.EM some
+cached data may be implicitly written out as the document outline is compiled,
+but there will
+.EM always
+be some remaining data, which must be explicitly flushed out, before the
+.CW groff
+formatting process is allowed to complete.
+.LP
+To allow the user to choose when cached
+.CW pdfmark
+data is to be flushed to the output stream, the
+.CW pdfmark
+macro package provides the
+.CW pdfsync
+macro, (to synchronise the cache and output states).
+In its simplest form, it is invoked without arguments, i.e.
+.QP
+.fam C
+.B .pdfsync
+.LP
+This form of invocation ensures that
+.EM both
+the \(lqmeta\(hydata cache\(rq, containing
+.CW pdfview
+and
+.CW pdfinfo
+data,
+.EM and
+the \(lqoutline cache\(rq,
+containing any previously uncommitted document outline data,
+are flushed; ideally, this should be included in a
+.CW groff
+\(lqend macro\(rq, to ensure that
+.EM both
+caches are flushed, before
+.CW groff
+terminates.
+.LP
+Occasionally,
+it may be desirable to flush either the \(lqmeta\(hydata cache\(rq,
+without affecting the \(lqoutline cache\(rq, or vice\(hyversa,
+at a user specified time, prior to reaching the end of the document.
+This may be accomplished, by invoking the
+.CW pdfsync
+macro with an argument, i.e.
+.QP
+.fam C
+.B ".pdfsync M"
+.LP
+to flush only the \(lqmeta\(hydata cache\(rq, or
+.QP
+.fam C
+.B ".pdfsync O"
+.LP
+to flush only the \(lqoutline cache\(rq.
+.LP
+The \(lqmeta\(hydata cache\(rq can normally be safely flushed
+in this manner, at any time
+.EM after
+output of the first page has started;
+(it may cause formatting problems,
+most notably the appearance of unwanted white space, if flushed earlier,
+or indeed, if flushed immediately after a page transition,
+but before the output of the content on the new page has commenced).
+Caution is required, however, when explicitly flushing the
+\(lqoutline cache\(rq, since if the outline is to be
+subsequently extended, then the first outline entry after flushing
+.EM must
+be specified at level 1.
+Nevertheless, such explict flushing may occasionally be necessary;
+for example, the
+.CW TC
+macro in the
+.CW spdf.tmac
+package,
+.XR using-spdf ), (
+invokes
+.CW ".pdfsync\ O" \(rq \(lq
+to ensure that the outline for the \(lqbody\(rq section of the document
+is terminated,
+.EM before
+it commences the formatting of the table of contents section.
+.bp
+.NH 1
+.XN -N pdf-layout -- PDF Document Layout
+.LP
+The
+.CW pdfmark
+macros described in the preceding section,
+.XR pdf-features ), (
+provide no inherent document formatting capability of their own.
+However,
+they may be used in conjunction with any other
+.CW groff
+macro package of the user's choice,
+to add such capability.
+.LP
+In preparing this document, the standard
+.CW ms
+macro package, supplied as a component of the GNU Troff distribution,
+has been employed.
+To facilitate the use of the
+.CW pdfmark
+macros with the
+.CW ms
+macros,
+a binding macro package,
+.CW spdf.tmac ,
+has been created.
+The use of this binding macro package is described in the following section,
+.XR using-spdf ); (
+it may also serve as an example to users of other standard
+.CW groff
+macro packages,
+as to how the
+.CW pdfmark
+macros may be employed with their chosen primary macro package.
+.NH 2
+.XN -N using-spdf -- Using \F[C]pdfmark\F[] Macros with the \F[C]ms\F[] Macro Package
+.LP
+The use of the binding macro package,
+.CW spdf.tmac ,
+allows for the use of the
+.CW pdfmark
+macros in conjunction with the
+.CW ms
+macros,
+simply by issuing a
+.CW groff
+command of the form
+.QP
+.fam C
+groff -Tps
+.B -mspdf
+.I "-options ...\&" ] [
+file(s) ...
+.LP
+When using the
+.CW spdf.tmac
+package, the
+.CW groff
+input files may be marked up using any of the standard
+.CW ms
+macros to specify document formatting,
+while PDF features may be added,
+using any of the
+.CW pdfmark
+macros described previously,
+.XR pdf-features ). (
+Additionally,
+.CW spdf.tmac
+defines a number of convenient extensions to the
+.CW ms
+macro set, to better accomodate the use of PDF features within the
+.CW ms
+formatting framework,
+and to address a number of
+.CW ms
+document layout issues,
+which require special handling when producing PDF documents.
+These additional macros,
+and the issues they are intended to address,
+are described below.
+.NH 3
+.XN \F[C]ms\F[] Section Headings in PDF Documents
+.LP
+Traditionally,
+.CW ms
+provides the
+.CW NH
+and
+.CW SH
+macros, to specify section headings.
+However,
+there is no standard mechanism for generating a
+table of contents entry based on the text of the section heading;
+neither is there any recognised standard method for establishing a
+cross reference link to the section.
+.LP
+To address this
+.CW ms
+limitation,
+.CW spdf.tmac
+defines the
+.CW XN
+macro,
+.XR xn-macro ), (
+to be used in conjunction with the
+.CW NH
+macro.
+.NH 4
+.XN -N xn-macro -- The \F[C]XN\F[] Macro
+.NH 1
+.XN The PDF Publishing Process
+.NH 2
+.XN -N do-xref -- Resolving Cross References
+.NH 3
+.XN -N create-map -- Creating a Document Reference Map
+.NH 3
+.XN -N import-map -- Deploying a Document Reference Map
+.TC
diff --git a/contrib/pdfmark/pdfmark.tmac b/contrib/pdfmark/pdfmark.tmac
new file mode 100644
index 00000000..263d7e98
--- /dev/null
+++ b/contrib/pdfmark/pdfmark.tmac
@@ -0,0 +1,1494 @@
+.\" -*- 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "LB",
+.\" (for LineBreak), is rather ugly, but does allow us to use
+.\"
+.\" .pdfnote Some text.\*[LB]Some more text, on a new line.
+.\"
+.ds LB \\\\\\\\\\\\\\\\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
+.\"
+.\" 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] .as pdf:bm\\n[pdf:bm.ic] " /Count \\n[pdf:bm.rc]
+.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 glyphs,
+.\" over which the hot spot will extend, while "PDFHREF.HEIGHT" sets
+.\" the hot spot height, PER LINE of text occupied by the reference.
+.\"
+.\" 2.5 points is 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 2.5p
+.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,
+. \" and adjusting "pdf:href.ok" to indicate where a reference
+. \" file list is required
+. \"
+. 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 and "pdf:href.ok" 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-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
+..
+.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
+..
+.\"
+.\" The "pdf*href.mark" macro is called internally, by "pdf*href", to
+.\" mark the start and end co-ordinates of the "link text" bounding box.
+.\" These are then used as the basis for computing the bounding box(es)
+.\" for the associated link "hot-spot".
+.\"
+.de pdf*href.mark(unused)
+.\" ----------------------------------------------------------------------
+.\" Usage: (internal use only):
+.\" .pdf*href.mark 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"
+.\"
+.\" Note that this requires two pass processing in "groff" ...
+.\" In pass 1, "pdf:href.map" is undefined; in pass 2, we source the
+.\" filtered output from pass 1, which defines it, (in terms of a series
+.\" of indexed sub-maps: "pdf:href.map-1" .. "pdf:href.map-N").
+.\"
+.pdf*href.map.init
+.ie !dpdf:href.map \{\
+. \"
+. \" In the first pass, we use the "grohtml" hook, to emit bounding
+. \" box co-ordinates to "stderr"; (note that we use a zero width
+. \" marker character, to obtain useful output -- we don't care that
+. \" these may be visible, since this is effectively a "dummy run"
+. \" through the formatter, and its PostScript output will be
+. \" discarded).
+. \"
+. nop \O1|\h'-\w"|"u'\O2\c
+. \}
+.el \{\
+. \"
+. \" In the second pass, we harvest the bounding box co-ordinates,
+. \" which we read back from the reprocessed "stderr" output from
+. \" the first pass, and assign them to specified registers.
+. \" First however, we will create an internal reference to the
+. \" "pdf:href.map"; we will read co-ordinates via this internal
+. \" reference, to ensure the "pdf:href.map" is not deleted from
+. \" the string namespace, when its data is exhausted.
+. \"
+. pdf*href.map.read \\$@
+. \}
+..
+.de pdf*href.mark.begin
+.pdf*href.map.init
+.ie dpdf:href.map \{\
+. pdf*href.mark.resolve \\$@
+. rn pdf*href.mark.resolve pdf*href.mark.begin
+. als pdf*href.mark.end pdf*href.mark.close
+. \}
+.el \{\
+. 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
+. pdf*href.map.read spg llx ury epg
+. 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.map.read urx lly
+. ie \\n[pdf:ury]=\\n[pdf:lly] \{\
+. \"
+. \" This link is entirely contained on a single output line;
+. \" we may simply emit the "hot-spot" PDFMARK definition, as
+. \" it has already been established.
+. \"
+. pdf*href.mark.emit 1
+. \}
+. el \{\
+. \" 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:urx.end \\n[pdf:urx]
+. nr pdf:ury.end \\n[pdf:lly]-\\n[PDFHREF.LEADING]
+. nr pdf:urx \\n(.o+\\n(.l
+. pdf*href.mark.emit 1
+. \"
+. \" Now, we adjust the initial "hot-spot" co-ordinates, to
+. \" mark the beginning of its second line.
+. \"
+. nr pdf:llx \\n(.o+\\n[.in]
+. nr pdf:ury +1v
+. if !\\n[pdf:ury.end]=\\n[pdf:ury] \{\
+. \"
+. \" This link spans MORE than two lines, so we redefine
+. \" its intermediate end point, in order to create a second
+. \" "hot-spot", which spans all but the first and last lines
+. \" of the "link text".
+. \"
+. nr pdf:lly \\n[pdf:ury.end]-1v+\\*[PDFHREF.HEIGHT]
+. pdf*href.mark.emit 2
+. \}
+. \" Finally, we adjust the "hot-spot" bounds once more, to
+. \" create a final "hot-spot", which extends from the start of
+. \" the last line of the "link text" to the originally computed
+. \" "hot-spot" end point.
+. \"
+. nr pdf:urx \\n[pdf:urx.end]
+. nr pdf:ury \\n[pdf:ury.end]
+. rr pdf:urx.end pdf:ury.end
+. pdf*href.mark.emit 0
+. \}
+. \}
+. 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.
+. \"
+. nr pdf:urx \\n(.o+\\n(.l
+. pdf*href.mark.emit 1
+. \"
+. \" Save the vertical trim distance, between the current text
+. \" base line and the top of the actual "hot-spot" region, so we
+. \" can make a similar adjustment at the top of the next page.
+. \"
+. mk pdf:ury.trim
+. nr pdf:ury.trim \\n[pdf:ury]-\\n[pdf:ury.trim]
+. \"
+. \" 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
+. als pdf*href.mark.end pdf*href.mark.release
+. \"
+. \" 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*href.map.read null null
+. 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>
+.\" <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 .nr pdf:ury -\\n[PDFHREF.LEADING]
+.if \\$1<2 .nr pdf:lly \\n[pdf:ury]u+\\*[PDFHREF.HEIGHT]
+.ie \\$1=3 \{\
+. 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 .pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN
+..
+.de pdf*href.mark.release
+.als pdf*href.mark.end pdf*href.mark.close
+.als pdf*href.mark.hook pdf*href.mark.idle
+.\"
+.\" Before finalising this link, check if its active region
+.\" extends beyond the first line of text on its last page.
+.\"
+.mk pdf:lly
+.ie \\n[pdf:lly]>\\n[pdf:ury] \{\
+. \"
+. \" When more than one line of link text overflows to a
+. \" new page, then we need to compute an extra active region
+. \" which will cover all but the last line of link text.
+. \"
+. nr pdf:lly +\\n[pdf:ury.trim]+\\n(.V-\\n[pdf:ury]
+. nr pdf:lly \\n[pdf:lly]/1v*1v-1v+\\*[PDFHREF.HEIGHT]+\\n[pdf:ury]
+. pdf*href.mark.emit 2
+. nr pdf:ury \\n[pdf:lly]-\\*[PDFHREF.HEIGHT]+1v
+. \"
+. \" Now, retrieve the page co-ordinates
+. \" for the end of the link text
+. \"
+. pdf*href.map.read urx lly
+. \}
+.el \{\
+. \" When the link text "overflow" occupies only a portion of
+. \" the first line on its final page, then we need to compute
+. \" the page co-ordinates for its upper right corner.
+. \"
+. pdf*href.map.read urx ury
+. nr pdf:ury -\\n[PDFHREF.LEADING]
+. \}
+.\" Finally, on the last line of the reference,
+.\" define the "hot-spot" region to cover the portion of the
+.\" link, from start of line to the end of the link text.
+.\"
+.pdf*href.mark.emit 0
+.pdf*href.mark.flush
+..
+.de pdf*href.mark.flush
+.rr pdf:spg pdf:llx pdf:lly pdf:urx pdf:ury pdf:ury.trim pdf:epg
+.if dPDFHREF.COLOR .als PDFHREF.COLOUR PDFHREF.COLOR
+..
+.de pdf*href.mark.close
+.ie '\\n(.z'' .pdf*href.mark.flush
+.el \!.pdf*href.mark.end
+..
+.de pdf*href.mark.end
+\O1|\h'-\w"|"u'\O2\c
+..
+.\"
+.\" 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 +\\n[pdf:ury.trim]
+.if \\n-[pdf:epg] .pdf*href.mark.emit 3
+..
+.\" 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
diff --git a/contrib/pdfmark/spdf.tmac b/contrib/pdfmark/spdf.tmac
new file mode 100644
index 00000000..5a666594
--- /dev/null
+++ b/contrib/pdfmark/spdf.tmac
@@ -0,0 +1,225 @@
+.\" -*- nroff -*-
+.ig
+
+spdf.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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+..
+.\"
+.if !rOPMODE .nr OPMODE 1
+.\"
+.mso s.tmac
+.mso pdfmark.tmac
+.\"
+.\" Omitted Sections
+.\" ================
+.\"
+.\" Define section markers, for special document sections,
+.\" which are to be omitted from regular document processing.
+.\"
+.de OMIT OMIT
+.de \\$1
+.omit@begin \\$1 \\$2
+..
+.de \\$2
+.omit@end \\$1 \\$2
+..
+.OMIT CS CE \" front cover text, processed independently
+.OMIT MS ME \" menu definitions, for info documents only
+.\"
+.de omit@begin
+.ds omit@section \\$1
+.ig \\$2
+..
+.de omit@end
+.if !'\\*[omit@section]'\\$1' .@error \\$2 without \\$1
+.rm omit@section
+..
+.de XM
+.\"
+.pdfhref M -X \\$@
+..
+.de XR
+.if \\n(.$ \{\
+. if \\n[OPMODE] \{\
+. ds spdf!opts -D "\\$1"
+. if \\n(.$>1 .as spdf!opts " -A "\\$2"
+. if \\n(.$>2 .as spdf!opts " -P "\\$3"
+. pdfhref L \\*[spdf!opts]
+. rm spdf!opts
+. \}
+. \}
+..
+.\"
+.\" Document Outlines, Section Headings and Table of Contents
+.\" =========================================================
+.\"
+.de XN
+.\" Use AFTER .NH n, to define the text of the numbered heading,
+.\" automatically generating a matching formatted TOC entry, and
+.\" a PDF document outline entry.
+.\"
+.\" String registers XNVS1, XNVS2 and XNVS3 establish additional leading,
+.\" prior to top level headings, preceding each level of indented subheading,
+.\" and following each nested level of subheading, respectively
+.\" (strings are used, rather than numeric registers, so that these
+.\" additional spacing parameters may be set relative to the current
+.\" document line spacing, as set by \n[VS]).
+.\"
+.rm xn*ref
+.while dopt*XN\\$1 \{\
+. opt*XN\\$1 \\$*
+. shift \\n[xn*argc]
+. \}
+.rr xn*argc
+.if '\\$1'--' .shift
+.if dxn*ref .XM -N \\*[xn*ref] -- \\$@
+.rm xn*ref
+.pdfhref O \\n[nh*hl] "\\*(SN \\$*"
+.XS
+.if rtc*hl \{\
+. if !dXNVS1 .ds XNVS1 1.0v \" default leading for top level
+. if !dXNVS2 .ds XNVS2 0.3v \" default leading at nesting increment
+. if !dXNVS3 .ds XNVS3 0.6v \" default leading following nested group
+. if \\n[nh*hl]==1 \{\
+. sp \\*[XNVS1]
+. nr tc*hl-max 1
+. \}
+. ie \\n[nh*hl]<\\n[tc*hl] .if \\n[nh*hl]>1 .sp \\*[XNVS3]
+. el \{\
+. ie \\n[nh*hl]>\\n[tc*hl] .sp \\*[XNVS2]
+. el \{\
+. if !r tc*hl-max .nr tc*hl-max 1
+. ie \\n[tc*hl-max]>\\n[nh*hl] .sp \\*[XNVS3]
+. el .nr tc*hl-max \\n[nh*hl]
+. \}
+. \}
+. \}
+.nr tc*hl \\n[nh*hl]
+\h'\\n[nh*hl]-1m'\c
+\&\\*(SN\h'1n'\\$*
+.\".pdfhref L -D \\*[PDFBOOKMARK.NAME] -- \&\\*(SN\h'1n'\\$*
+.XE
+\&\\$*
+..
+.de opt*XN-N
+.nr xn*argc 2
+.ds xn*ref \\$2
+..
+.de opt*XN-X
+.nr xn*argc 1
+.if !dxn*ref .ds xn*ref \\\\$1
+..
+.de LU
+.LP
+The content for this section is not yet available.
+..
+.de AN
+.ie \\n(.$ .@AN \\$*
+.el .@AN Note
+..
+.de @AN
+.SH
+\\$*
+.LP
+..
+.nr PDF-TOC-ONLY 1
+.nr PDF-BODY-TEXT 2
+.de OP
+.ie rPHASE \{\
+. ie \\n(.$ \{\
+. nr op:request 0
+. while \\n(.$ \{\
+. if \\$1=\\n[PHASE] .nr op:request 1
+. shift
+. \}
+. \}
+. el .nr op:request 1
+. if !\\n[op:request]=\\n[OPMODE] \{\
+. nr OPMODE \\n[op:request]
+. nop \O[\\n[OPMODE]]\c
+. \}
+. \}
+.el .nr OPMODE 1
+..
+.nr SAME-PAGE 0
+.de NN
+.if !\\n[SAME-PAGE] .bp
+.nr SAME-PAGE 0
+.NH \\$1
+.nn*setname \\$2
+.shift 2
+.XN -N \\*[nn*name] -- \\$@
+.rm nn*name
+..
+.de nn*setname
+.ds nn*name \\$1
+.shift
+.while \\n(.$ \{\
+. as nn*name -\\$1
+. shift
+. \}
+..
+.de PXREF
+.nn*setname \\$2
+.XR \\*[nn*name] )\\$1 (
+.rm nn*name
+..
+.de IS
+.RS
+.nr LL \\n(LL-\\n(PI
+..
+.de IE
+.RE
+.nr LL \\n(LL+\\n(PI
+..
+.\" Override the standard ms macro,
+.\" to ensure the document outline cache is flushed
+.\" BEFORE emitting the table of contents.
+.de TC
+.pdfsync O
+.P1
+.OP \n[PDF-TOC-ONLY]
+.pg@begin 1 i
+.if \\n[OPMODE] .pdf@toc
+.PX \\$1
+..
+.de pdf@toc
+.pdfhref O -T T 1 "\\*[TOC]"
+.pdfsync O
+..
+.de pdf@exit
+.if \\n[OPMODE] .pdfsync
+.pg@end-text
+..
+.em pdf@exit
+.OP \n[PDF-BODY-TEXT]
+.
+.\" groff "ms" provides the "pg@bottom" macro, which has already
+.\" been installed as a page transition trap. To ensure proper
+.\" mapping of "pdfhref" links which overflow the bottom of any
+.\" page, we need to install the "pdfhref" page transition hook,
+.\" as an addendum to this macro.
+.
+.pdfhref I -PT pg@bottom
+.\"
+.\" spdf.tmac: end of file: vim: ft=groff