PageRenderTime 110ms CodeModel.GetById 61ms app.highlight 25ms RepoModel.GetById 2ms app.codeStats 0ms

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

https://bitbucket.org/freebsd/freebsd-head/
Unknown | 1562 lines | 1552 code | 10 blank | 0 comment | 0 complexity | 6bdb5555941f549232897cad6cc8789d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file