From 19027907767d699e44966b54ab8990ab8f920486 Mon Sep 17 00:00:00 2001 From: wl Date: Wed, 8 Dec 2004 08:31:17 +0000 Subject: Import Keith's `pdfmark' package. Integration is very preliminary. * contrib/pdfmark/*: New files. * Makefile.in (OTHERDIRS): Add contrib/pdfmark. * NEWS: Updated. --- contrib/pdfmark/Makefile | 258 +++++ contrib/pdfmark/Makefile.sub | 10 + contrib/pdfmark/PROBLEMS | 25 + contrib/pdfmark/README | 50 + contrib/pdfmark/TODO | 34 + contrib/pdfmark/cover.ms | 57 + contrib/pdfmark/pdfmark.ms | 2357 ++++++++++++++++++++++++++++++++++++++++++ contrib/pdfmark/pdfmark.tmac | 1494 ++++++++++++++++++++++++++ contrib/pdfmark/spdf.tmac | 225 ++++ 9 files changed, 4510 insertions(+) create mode 100644 contrib/pdfmark/Makefile create mode 100644 contrib/pdfmark/Makefile.sub create mode 100644 contrib/pdfmark/PROBLEMS create mode 100644 contrib/pdfmark/README create mode 100644 contrib/pdfmark/TODO create mode 100644 contrib/pdfmark/cover.ms create mode 100644 contrib/pdfmark/pdfmark.ms create mode 100644 contrib/pdfmark/pdfmark.tmac create mode 100644 contrib/pdfmark/spdf.tmac (limited to 'contrib/pdfmark') 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 /contrib/pdfmark + make pdfmark + +where 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 +.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 +.\" $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 ... +.\" ----------------------------------------------------------------- +.\" +.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 +.\" == 0 --> normal operation -- link height = 1 line +.\" == 1 --> start of link -- add leading above text +.\" == 2 --> overtall link -- set intermediate baseline +.\" == 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 -