previous
TOC
next
Tralics, a LaTeX to XML translator; Part II

4. Interpreting XSL/Format in TeX

In general, an XML file describing a document like the Raweb contains instructions like: insert the table of contents here, or emphasize this word, but gives no details. In the next chapter we shall explain how these details can be added (using something like XSL/Transformations); here we explain how TeX can interpret these formatting commands. We assume that our document conforms to XSL (Extensible Style Sheet), which is a W3C recommendation of 15 October 2001. The important part of the recommendation is chapter 6 (Formatting objects) that describes all XML elements; they are in some namespace, conventionally abbreviated to `fo´.

We start with an example; it contains one line of the table of contents, associated to some section, here it is named “National Actions” and has a unique identifier, number 120. The style sheet that creates this piece of code added the section number 8.2, but the page number is still unknown: TeX must compute it. Some other information is added, for instance the color of the link, the font of the text, various dimensions, the type of the leaders.

Normally, such details do not appear in a TeX file, but are defined by a class. Since everything is explicit, any class could be used, and we shall see later that the article class is used; however your document can have a front matter, main matter, etc., as in the book class; they are associated to page sequences and page masters, which are rather complicated concepts.

<fo:block font-weight="bold" text-indent="0.25in">8.2. &#x2003;
  <fo:inline space-start="20pt">
    <fo:inline>National Actions</fo:inline>
  </fo:inline>
  <fo:leader rule-style="dotted" rule-thickness="0pt"/>
  <fo:inline color="red">
     <fo:basic-link internal-destination="uid120">
        <fo:page-number-citation ref-id="uid120"/>
     </fo:basic-link>
  </fo:inline>
</fo:block>

4.1. Generalities

We describe here the content of two files: fotex.xmt and fotex.sty. The fotex.xmt file contains definitions of elements, while the fotex.sty file contains some commands. Both files start like this

1 % Copyright 2003 Sebastian Rahtz/Oxford University
2 %      <sebastian.rahtz@oucs.ox.ac.uk>
3 %
4 % Permission is hereby granted, free of charge, to any person obtaining
5 % a copy of this software and any associated documentation files (the
6 % ``Software''), to deal in the Software without restriction, including
7 % without limitation the rights to use, copy, modify, merge, publish,
8 % distribute, sublicense, and/or sell copies of the Software, and to
9 % permit persons to whom the Software is furnished to do so, subject to
10 % the following conditions:
11 % The above copyright notice and this permission notice shall be included
12 % in all copies or substantial portions of the Software.

Lots of people are working on these files:

13 % Includes fixes from Tomas Bures <ghort@pauline.vellum.cz>
14 %                     Yura Zotov <yznews@hotbox.ru>
15 %                     Anton V. Boyarshinov <boyarsh@ru.echo.fr>
16 %                     Dirk Roorda <dirk.roorda@planet.nl>

In the first version of this document, we discussed version 1.17, here it is version 1.25 (distributed by teTeX3.0). Newer versions might exist. In what follows, version V1 refers to the first version of the document, hence to version 1.17 of the fotex package, and V2 refers to 1.25.

17 \ProvidesPackage{fotex}[2003/03/10: version 1.25.
18    support for XSL formatting, S Rahtz]

This file was modified by José Grimm in some places, we shall see why later on, this line gives the local revision number (this corresponds to the version dated 2006/11/23).

19 \immediate\write20{fotex.sty version 1.25. S Rahtz
20  (JG patches: $ Revision: 1.13 $)}

We shall indicate the differences between these two versions whenever appropriate. In some cases, local assignments were replaced by global ones; as a general rule, if <a> and <b> are children of <c>, then typesetting of <b> is independent of typesetting of <a>, and a groups is created for every element; hence, if side effects are needed while typesetting <a> they should be local, unless required by <b>, case where global assignments are needed; if moreover the scope is restricted to <c>, a local copy is needed. In some other cases, \relax tokens were added at the end of assignments. Remember that, if TeX sees \foo=0, it expands the following token, in order to see if additional digits are found. Since \relax is a non-expandable token that produces no text, it can be put after the zero. In most of the cases, the space inserted at the end of the line is enough.

The first difference is the following.

21 \gdef\XML@attrib@x#1#2{
22     \gdef\XML@tempb##1#1##2##3##4\relax\relax{
23         \global\let\inheritexplicit\relax
24         {\set@display@protect
25         \expandafter\ifx\csname#2\endcsname\inherit
26                 \global\let\inheritexplicit\noexpand
27         \fi}%
28         \ifx\inheritexplicit\relax
29                 \def##2{#2}%
30         \fi
31     ##1##4\relax\relax}}

As explained in Chapter 2, putting a \def in a \def in a \def is not usual. In our case, the inner definition is conditional, so that it is unclear what happens. The outer command takes two arguments, say A and B, and defines another command, say C. The command C takes as argument a long list, and extracts expression A, followed by two expressions D and E; the remaining part of the list is evaluated again. Quantity E is ignored, and D is defined to be B. Assume that we evaluate an element, defined by \XMLelement, and the first argument says that attribute X should be put in command Y with default value Z. Then D is Y, A is related to X, and B is the value of the attribute or a default value. The original code sets D. The modified code sets it conditionally, if the first \ifx is false. In fact, the test is done in a group, and if the test is true, a variable is globally changed, and the second \ifx looks at this change. The test is true in case B is `inherit´, but instead of comparing token lists, the code converts B in a command via \csname and compares command names. This can produce a lot of commands and might overflow the hash table. Commands produced by \csname are never undefined, but outside the group, the old value is restored.

Second addition:

32 \gdef\explicitattribute#1{
33 { \expandafter\def\csname#1-test\endcsname{\global\def\isexplicit{1}}
34   \global\let\isexplicit\relax
35   \def\XML@doattribute##1##2##3{\csname##2-test\endcsname}
36   \the\XML@attribute@toks}}

Write \do instead of \XML@doattribute and \L instead of \XML@attribute@toks. The quantity \L is a token list containing all items of the form of a \do followed by a namespace A, a local name B and a value C. This code takes an argument, say `foo´, and sets \isexplicit to true (i.e., \non-relax) if one B is `foo´. The idea is simple: the \do command is redefined in such a way as to modify \isexplicit if B is `foo´. Implementation is horrible: the package defines \foo-test to change the flag, and evaluates the command named B-test for every B.

In Chapter 2, we gave the example of an element with two attributes, `foo:bar´ and `color´, with values `gee´ and `red´. The first modification creates commands \gee and \red, and compares them to \inherit. The second modification creates commands \bar-test and \color-test, and evaluates them; the assumption is that these commands are not defined (made \relax by \csname), hence provoke no undesired result.

In one of our examples the code fails because the attribute is something like `&#2016;´, corresponding to the math construct \left\Vert. The second command always gives a negative result because applied in the case of an empty attribute list. One way to patch the first command is to redefine the ampersand; but the code shown here is safer.

37 \def\inheritname{inherit}
38 \def\jgXML@attrib@x#1#2{
39     \gdef\XML@tempb##1#1##2##3##4\relax\relax{
40        \def\tmp{#2}%
41         \ifx\tmp\inheritname\else\def##2{#2}%
42         \fi
43     ##1##4\relax\relax}}

Patch of the second command. We put `foo´ in \tmp, B in \atmp. In case of equality, we globally set \isexplicit to \empty (this should be different from relax).

44 \def\explicitattribute#1{{%
45    \def\tmp{#1}
46    \global\let\isexplicit\relax
47    \def\XML@doattribute##1##2##3{%
48       \def\atmp{##2}\ifx\tmp\atmp\global\let\isexplicit\empty\fi}
49     \the\XML@attribute@toks}}

The fotex-add.sty file loads the following packages: graphics, multicol, rotating, curves, soul, array, amsmath, longtable, url, ulem, color, times, mlnames, unicode, marvosym, ipa, ifsym, ucharacters, nameref, hyperref, and raweb-uni. This last package defines (or redefines) some Unicode characters. Some packages, like ifsym, were not in the original style file, they were added because providing access to some fonts. Setting the boolean hyperref to false via \hyperreffalse inhibits loading of the hyperref package.

The fotex-add.sty loads fotex-supp.tex if such a file exists. This file can load some additional packages; it can also inhibit loading of the package hyperref (in fact, it is the only place where you can use \hyperreffalse). This mechanism is a bit complicated, because all packages must be loaded before the start of the document, and you cannot unload a package. Both files fotex.xmt and fotex.sty had to be adapted for the Raweb.

50 \RequirePackage{fotex-add}

The fotex.xmt file starts with these two lines, it is followed by declarations of attributes, strings and elements. The namespace number of fo is 5 (see below), that of fotex is 6.

51 \DeclareNamespace{fotex}{http://www.tug.org/fotex}
52 \DeclareNamespace{fo}{http://www.w3.org/1999/XSL/Format}

4.2. The root

Handling the <fo:root> element is trivial, but some magic is implied. Let´s describe it. The main TeX file should define the \xmlfile command to be the name of the XML file to process, and input the xmltex.tex file. The last action of this file is to input xmltex.cfg, \jobname.cfg and the XML file. The file xmltex.cfg typically defines a catalog similar to the one shown in section 2.7. It defines the XSL/Format namespace (it assigns the number 5 to it) and says that the definitions are to be found in the fotex.xmt file. It may define other things. The \jobname.cfg file can also define some commands.

The \xmlfile file is read using XML syntax. It typically starts with a <?xml?> declaration (that defines the encoding, say UTF-8). In the case of the Raweb, it is followed by a <fo:root> element. This one contains a <fo:layout-master-set>, followed by some <fo:static-content> elements and some <fo:page-sequence> elements. The root element has three attributes, of the form xmlns:XX = `YY´. For each attribute, the code line 388 (page 2.8) is executed. One of the attributes has the name xmlns:fo and its value is the XSL/Format URI. This URI is the same as the declaration above (on line 51 above, in this chapter), so that the `fo´ in <fo:root> is the same namespace in the XML file and the xmt file. After all attributes have been read, the code on line 413 is executed. In particular, the `fo´ in <fo:root> is evaluated now (line 416, command \XML@ns, the value is 5). The command \XML@checkknown has as side effect to call \inputonce with, as argument, the file fotex.xmt, as explained in the catalogue. This has as effect to load the fotex.xmt file. After that, we know how to handle the root element. The first action is to evaluate the attributes. Almost all attributes are global. The norm(note: ) says: there is one attribute media-usage, in what follows, we shall assume that its value is `paginate´. The action is as follows: we define the documentclass to something non-trivial but not too complicated, and load the fotex package.

53 \XMLelement{fo:root}
54   {\XMLNSAX{fo}{fotex:spacing-style}{\FoTeXSpacingStyle}{normal}}
55   {\documentclass{article}
56    \usepackage{fotex}

We are now ready to evaluate everything. We start with \begin{document} plus some action (empty pagestyle, default language). When we see </fo:root> we evaluate \end{document}: this will stop everything.

57    \begin{document}
58    \pagestyle{empty}
59    \FOSetHyphenation
60    \FoTeXSetSpacingStyle
61    }
62   {\end{document}}

Bootstrap code: We use here \XMLNSA as a short name for \XMLnamespaceattribute (and the same for \XMLNSAX). Remember that this takes four arguments. In the line that follows, the effect is the following: for every element in the `fo´ namespace, the value of the language trait is stored in \FOlanguage; the default value is `\inherit´, this means that it is the same as the value of the father. The initial value is `none´. In the case of the hyphenate trait, the initial value is `false´, the default value is `\inherit´. Note: the mechanism works only if attributes are declared before elements; the fotex.xmt file starts with the list of all attributes, in alphabetic order; we prefer give the definition after first use.

63 \XMLNSAX{fo}{language}{\FOlanguage}{\inherit}
64 \XMLNSAX{fo}{hyphenate}{\FOhyphenate}{\inherit}
65 \gdef\FOlanguage{none}
66 \gdef\FOhyphenate{false}
67 \def\LastLanguage{(undefined)}
68 \selectlanguage{english}

This is an addition of V2. If fotex:spacing-style is `french´ then \frenchspacing will be executed.

69 \def\FoTeXSetSpacingStyle{%
70   \ifx\FoTeXSpacingStyle\att@french \frenchspacing \fi
71 }
72 \XMLstringX\att@french<>french</>

In the case where hyphenation is desired, this piece of code is assumed to switch to the right language, it sets \hyphenpenalty to some value (typically 50), otherwise to infinity.

73 \def\FOSetHyphenation{%
74   \ifx\FOhyphenate\att@true
75      \LoadLanguage{\FOlanguage}%
76      \hyphenpenalty=\exhyphenpenalty
77   \else
78      \hyphenpenalty=10000
79   \fi}

We put in \newL a canonical version of the language, say `FR´, then evaluate \L@FR, unless the language is the same. We remember in \LastLanguage the language. The file mlnames.sty defines a lot of languages(note: ).

80 \def\LoadLanguage#1{%
81   \begingroup\utfeight@protect@chars\xdef\newL{#1}\endgroup
82   \ifx\newL\LastLanguage
83   \else
84     \csname L@\newL\endcsname
85   \fi
86   \edef\LastLanguage{\newL}}

4.3. Mathematics

The elements defined in this paragraph are not defined by XSL/Format. In fact, they are not used by the Raweb.

Typesetting of <fotex:inlinemath>math</fotex:inlinemath>. We evaluate \(math\).

87 \XMLelement{fotex:inlinemath}
88    {} {\(}  {\)}

Typesetting of <fotex:equation>math</fotex:equation>. The evaluation of the math is in an equation environment.

89 \XMLelement{fotex:equation}
90    {}
91    {\begin{equation}}
92    {\end{equation}}

Typesetting of <fotex:displaymath> math </fotex:displaymath>. The evaluation of the math is a displaymath environment.

93 \XMLelement{fotex:displaymath}
94    {}
95    {\begin{displaymath}}
96    {\end{displaymath}}

Typesetting of <fotex:eqnarray>math</fotex:eqnarray>. The evaluation of the math is a gather* environment. This is an amsmath environment, that requires an explicit \end tag, so that we need to grab it.

97 \XMLelement{fotex:eqnarray}
98  {}
99  {\xmlgrab}
100  {\begin{gather*}#1\end{gather*}}

Handling of <fotex:subeqn>math</fotex:subeqn>. There is some action, that consists of evaluating the math, and a double backslash; this end-of-row marker must be executed outside the group defined by \xmlgrab, thus the \aftergroup. If there is a label (i.e. an id attribute in \FOid), we execute the \label command(note: ), otherwise, the equation will have no number.

101 \XMLelement{fotex:subeqn}
102   {}
103   {\xmlgrab}
104   {%\ifx\FOid\@empty
105      \gdef\w@t{#1\nonumber\\}
106    %\else
107    %  \gdef\w@t{#1\label{\temp}\\}
108    %\fi
109    \aftergroup\w@t}

4.4. Multiple columns

The passive tex package provides the nomulticol.sty file. It contains the following comments:

110 %% This is file `nomulticol.sty',
111 %% a tweak in package multicol.sty [2000/07/10 v1.5z
112 %%     multicolumn formatting (FMi)]
113 %% Tweaked by Dirk Roorda 2003/01/09

The purpose is to have the \begin{multicols} ... \end{multicols} functionality without putting the material inside a group. This is needed because in PassiveTeX a <fo:flow> is embedded in a multicols environment. But the <fo:block> with attribute span = `all´ must be able to interrupt this. However, saying \end{multicols} just before and \begin{multicols}{N} just after does not work, because it makes the attributes, set between the start of the flow and the beginning of the block, invisible. That´s why a grouping-transparent multicol setup is needed. The package provides two macros \nobeginmulticols and \noendmulticols that do essentially the same but do not create a group.

Initial version of the fotex package did not implement the span feature, hence loaded the multicol package like this.

114 \IfFileExists{multicol.sty}
115   {\RequirePackage{multicol}[1997/12/16]}
116   {\newenvironment{multicols}[1]%
117   {\typeout{Warning,  at line \the\inputlineno,
118     multicol package not available}}{}%
119 }

The current version tries to load this new package if possible, the old one otherwise.

120 \IfFileExists{nomulticol.sty}
121   {\confirmnomulticols}
122   {\IfFileExists{multicol.sty}
123     {\warnnomulticols}
124     {\warnmulticols}
125 }

If the nomulticol package is not available, we define the five commands provided by the package.

126 \def\fakenomulticols{
127  \def\nobeginmulticols##1{\begin{multicols}{##1}}
128  \def\noendmulticols{\end{multicols}}
129  \def\interbeginmulticols##1{}
130  \let\interendmulticols\relax
131  \let\refreshmulticols\relax
132 }

This is the action in case where the new package exists, or the old one exists, or none is found.

133 \def\confirmnomulticols{
134   \RequirePackage{nomulticol}[2003/01/09]
135   \typeout{INFO (nomulticol.sty:  fo:block span="all" works}
136 }
137 \def\warnnomulticols{
138   \RequirePackage{multicol}[1997/12/16]
139   \typeout{WARNING (multicol.sty:  fo:block span="all" does not work}
140   \fakenomulticols
141 }
142 \def\warnmulticols{
143   \typeout{WARNING (no multicol.sty:  multiple columns not available}
144   \newenvironment{multicols}[1]{\typeout{Warning,  at line
145        \the\inputlineno, multicol package not available}}{}
146   \fakenomulticols
147 }

4.5. Page masters

The children of <fo:root> are: a <fo:layout-master-set>, an optional <fo:declarations>, and some <fo:page-sequence>. The <fo:declarations> has a sequence of <fo:color-profile> elements as children, that define color profiles. These are currently unimplemented.

148 \XMLelement{fo:color-profile}{}{}{}
149 \XMLelement{fo:declarations}{}{}{}

The children of <fo:layout-master-set> are either <fo:simple-page-master> (that define the layout of a page) or <fo:page-sequence-master> (that define which simple page masters are to be used). We define in this section how simple-page-masters are handled. Each such object has a name, which is in the master-name trait. For the Raweb, we define eight such masters, named: simple1, left1, right1, first1, simple2, left2, right2, first2. Here the digit at the end indicates the number of columns of text on the page. The names left and right stand for even or odd pages (odd pages are on the right, even pages on the left). We have a special case for simple (`blank´ pages) and first pages. Each master has a reference-orientation. This will be ignored; it has also a writing-mode, that will be ignored. We assume that it is `lr-tb´, meaning: inline components and text within a line are written left-to-right; lines and blocks are placed top-to-bottom. With this convention, we have before=top, after=bottom, start=left and end=right. Schematically this can be represented like this:

before top
start body end      →      left body right
after bottom

The page is divided into five rectangular regions, four of them are called region-before, region-after, region-start and region-end (they correspond to the header, the footer, left margin, right margin). The content of these is `static´, said otherwise, it is the same for each page, except that it can contain the current page number. These regions have an extent (vertically, or horizontally). Whether the upper-left corner is part of the region-before or region-start depend on the precedence of the region-before. The four regions mentioned above surround the region-body. Both the page and the region-body have margins. How these margins and extents define the size of the body is unclear to me. For instance, the Raweb defines one page master with the following attributes: master-name = `left1´, page-width = `210mm´, page-height = `297mm´, margin-top = `75pt´, margin-bottom = `100pt´, margin-left = `80pt´, margin-right = `80pt´. With these values the text width is near 15cm, and the text height is 21cm (in fact, after the text, we have some space, an empty footer, and the margin, i.e. 24pt, 12pt and 100pt, a total of nearly 5cm).

We declare here some attributes (margins are declared later).

150 \XMLNSA{fo}{page-width}{\FOpagewidth}{auto}
151 \XMLNSA{fo}{page-height}{\FOpageheight}{auto}
152 \XMLNSAX{fo}{master-name}{\FOmastername}{}
153 \XMLNSAX{fo}{extent}{\FOextent}{0.0pt}

Action is trivial: we just evaluate the content.

154 \XMLelement{fo:layout-master-set}
155   {} {} {}

This will be used twice. The idea is that typesetting a page uses “traits”, that are computed from attributes; all four margins define a single trait, that can be defined by a single attribute (margin) or a sequence of four attributes (for instance margin-right), or can be inherited. We shall see later that the equivalent of TeX glue is a complicated trait.

156 \def\jg@expandmargins{%
157     \ifx\FOmargin\@empty\relax\else
158       \let\FOmarginright\FOmargin
159       \let\FOmarginleft\FOmargin
160       \let\FOmargintop\FOmargin
161       \let\FOmarginbottom\FOmargin
162      \fi}

The code for <fo:simple-page-master> has a comment that says tests removed see above. In V1, there were four lines of code shown here. These lines of code are now removed, so that our remark has to be commented out too: As mentioned above, the sum of the vertical margins are used, so that it is unclear why one variable is replaced by the maximum. In our cases, outer margins are larger than inner margins, so that the tests are false, and no variable is changed.

\ifdim\InnerTopMargin>\FOmargintop\def\FOmargintop{\InnerTopMargin}\fi
\ifdim\InnerBottomMargin>\FOmarginbottom\def\FOmarginbottom{\InnerBottomMargin}\fi
\ifdim\InnerRightMargin>\FOmarginright\def\FOmarginright{\InnerRightMargin}\fi
\ifdim\InnerLeftMargin>\FOmarginleft\def\FOmarginleft{\InnerLeftMargin}\fi

This defines \Atomic:left1 (assuming that the master name is `left1´), it contains the size of the page and the max values of the margins of the page and body. This is the old version.

\def\jg@define@atomic{
    \expandafter\xdef\csname Atomic:\FOMaster\endcsname{
     \MasterTopMargin\FOmargintop
     \MasterBottomMargin\FOmarginbottom
     \MasterRightMargin\FOmarginright
     \MasterLeftMargin\FOmarginleft
     \paperwidth\FOpagewidth
     \paperheight\FOpageheight}}

Assume that the master name is `left1´, this defines \Atomic:left1; when executed, this defines some commands to contain the sum of outer and inner values; the outer value is the value of the attribute (for instance margin-top) of the current element (the simple-page-master), the inner value is the value of the same attribute of the region-body child of the master. Quantities used in this code are defined later; the body of the macro contains ten lines of the form AXYR, where A is an optional \advance, R is an optional \relax, X is a dimension register, and Y a macro (definitions will be given later). The effect of the code is to store Y in X, or increment X by Y. Since the command is defined by \xdef, all possible tokens are expanded. Only these Y tokens can be expanded.

163 \def\jg@define@atomic{
164  \expandafter\xdef\csname Atomic:\FOMaster\endcsname{
165   \MasterTopMargin\FOmargintop
166   \advance\MasterTopMargin\InnerTopMargin\relax
167   \MasterBottomMargin\FOmarginbottom
168   \advance\MasterBottomMargin\InnerBottomMargin\relax
169   \MasterRightMargin\FOmarginright
170   \advance\MasterRightMargin\InnerRightMargin\relax
171   \MasterLeftMargin\FOmarginleft
172   \advance\MasterLeftMargin\InnerLeftMargin\relax
173   \paperwidth\FOpagewidth
174   \paperheight\FOpageheight}}

In the example of the Raweb, \Atomic:left1 contains the following.

\MasterTopMargin 75pt\advance \MasterTopMargin 24pt\relax
\MasterBottomMargin 100pt\advance \MasterBottomMargin 24pt\relax
\MasterRightMargin 80pt\advance \MasterRightMargin 0pt\relax
\MasterLeftMargin 80pt\advance \MasterLeftMargin 0pt\relax
\paperwidth 210mm
\paperheight 297mm.

The content of a <fo:simple-page-master> is a definition of each of the five regions mentioned above. In this version, we ignore the start and end regions: we assume that they are blank and have zero extent. Only region-body is mandatory, so that we provide a default for region-before and region-after. After this element has been completely evaluated, six commands are defined: assume that the master name is `left1´; we define \left1:before, \left1:after, to be names of regions, \left1:before-extent, \left1:after-extent, their extents; there is also \left1:B (instead of `B´, the name of the body region should be used, it is `xsl-region-body´, see below), and \Atomic:left1.

175 \XMLelement{fo:simple-page-master}
176   {}
177   {\let\FOMaster\FOmastername
178     \jg@expandmargins
179     \ifx\FOpagewidth\att@auto\edef\FOpagewidth{\paperwidth}\fi
180     \ifx\FOpageheight\att@auto\edef\FOpageheight{\paperheight}\fi
181     \expandafter\xdef\csname\FOMaster:after\endcsname{DummyRegion}
182     \expandafter\xdef\csname\FOMaster:before\endcsname{DummyRegion}
183     \expandafter\xdef\csname\FOMaster:before-extent\endcsname{\FOextent}
184     \expandafter\xdef\csname\FOMaster:after-extent\endcsname{\FOextent}
185     }
186   {
187   %% tests removed see above
188     \begingroup
189      \utfeight@protect@chars
190      \jg@define@atomic
191    \endgroup
192    }

These lines are from fotex.sty. The quantities \hoffset and \voffset are the opposite of the TeX offsets. The default paper width is strange.

193 \paperwidth211mm
194 \paperheight297mm
195 \hoffset-1in
196 \voffset-1in

The <fo:region-before> element is empty, it has some traits. We only consider region-name and extent. In the example given above, attributes are region-name = `xsl-region-before-left´ and extent = `12pt´. Each region has a default name, it is not used here. The code defines two global commands. For instance, this could define \left1:before to the name shown above (in the case where the master name is `simple1´ or `simple2´, the default name is used).

197 \XMLelement{fo:region-before}
198   {}
199   {\ifx\FOregionname\@empty \def\FOregionname{xsl-region-before}\fi
200    \begingroup
201      \utfeight@protect@chars
202      \expandafter\xdef\csname\FOMaster:before\endcsname{\FOregionname}
203      \expandafter\xdef\csname\FOMaster:before-extent\endcsname{\FOextent}
204    \endgroup
205   }
206   {}

Page footer. This is handled as above.

207 \XMLelement{fo:region-after}
208   {}
209   {\ifx\FOregionname\@empty \def\FOregionname{xsl-region-after}\fi
210    \begingroup
211      \utfeight@protect@chars
212      \expandafter\xdef\csname\FOMaster:after\endcsname{\FOregionname}
213      \expandafter\xdef\csname\FOMaster:after-extent\endcsname{\FOextent}
214    \endgroup
215   }
216   {}

These are not implemented.

217 \XMLelement{fo:region-start}{}{}
218 \XMLelement{fo:region-end}{}{}

The <fo:region-body> is empty; it has traits as the region-before. In the example of `left1´ they are the following: margin-bottom = `24pt´, margin-top = `24pt´ (the default value for the two other margins is zero; no extent can be given here). The default value of the region-name is used, because all pages have the same layout.

There are possibly other attributes, but most of them are not implemented. As explained above, we store somewhere the margins so that the page-master can use them. We also store in \left1:B (where `left1´ is the name of the master, and B the name of the region), the four following quantities: top margin, bottom margin, column-count and column-gap: this is because the page can contain more than one column of text, and we have to specify this number and the distance between the columns.

219 \XMLelement{fo:region-body}
220   {}
221   {
222   \jg@expandmargins
223   \xdef\InnerBottomMargin{\FOmarginbottom}
224   \xdef\InnerTopMargin{\FOmargintop}
225   \xdef\InnerLeftMargin{\FOmarginleft}
226   \xdef\InnerRightMargin{\FOmarginright}
227   \ifx\FOregionname\@empty \def\FOregionname{xsl-region-body} \fi
228   \begingroup
229      \utfeight@protect@chars
230       \expandafter\xdef\csname\FOMaster:\FOregionname\endcsname
231         {\FOcolumngap|\FOcolumncount|\FOmarginbottom|\FOmargintop|}
232   \endgroup
233   }
234  {}

This will be used later. It grabs the four values saved by the procedure above.

235 \def\Pass#1\\{\expandafter\@Pass#1}
236 \def\@Pass#1|#2|#3|#4|{%
237  \columnsep=#1
238  \def\NColumns{#2}%
239  \def\Marginbottom{#3}%
240  \def\Margintop{#4}%
241  }

Some declarations.

242 \XMLNSAX{fo}{region-name}{\FOregionname}{}
243 \XMLNSAX{fo}{master-reference}{\FOmasterreference}{}
244 \XMLNSAX{fo}{column-gap}{\FOcolumngap}{12.0pt}
245 \XMLNSAX{fo}{column-count}{\FOcolumncount}{1}
246 \def\NColumns{1}
247 \gdef\PrevNColumns{1}

4.6. Page sequences

A <fo:page-sequence-master> is an element that has a single trait master-name; its content defines the page sequence with that name, according to its single child, that can be one of three possibilities. The Raweb defines the following: twoside1nofirst, twoside1, oneside1, twoside2, oneside2, but uses only the second one. The meaning is the following: all even pages are the same, as well as all odd pages; the first page is special. If you look very closely, there are three pages numbered 2. At least one of them is empty; but this is a kludge. In fact, the initial page (the title page) has no headings, it is of type First; is it followed by an empty page, generated by <cleardoublepage/>. This page is followed by a second page sequence that contains the table of contents; this page sequence is followed by the text; this is a page sequence that starts on a right page, numbered one. The first two page sequences should define force-page-count to be end-on-even, rather than using this kludge. The behavior will change in 2005.(note: )

In all examples that follow, we shall assume that the master name is `twoside1´; this quantity is saved in a variable that can be used by the children. The master can define a single page, in this case the child defines this page; it can define a sequence of pages that look all the same, in this case, the child gives a model for these pages; finally, it can define a sequence of pages, whose aspect depend on parameters, case where the child contains a list of definitions; for each of this definitions, the master is the grand-father, this explains why the name is stored in a variable named \Granpa.

We shall see later that the V2 implementation allows the use of more than one simple page, numbered one, two, three, etc. The counter \SimplePMRefs holds the index of the next simple page master.

248 \XMLelement{fo:page-sequence-master}
249   {}
250   {\global\SimplePMRefs0\relax
251    \let\Granpa\FOmastername
252   }
253   {\global\SimplePMRefs0\relax}

We have an implementation problem: the FO specifications are too complex to match those of TeX, so that we use only 4 types of pages, named Even, Odd, First, Blank. The original fotex.sty did define but not use Blank. We changed this. In version V1, children of a page sequence master, say `twoside1´, were assumed to define the four commands \First:twoside1, \Blank:twoside1, \Odd:twoside1, \Even:twoside1, to be the name of a page master. In the case of a single, or repeatable page master reference, these four quantities were defined to be the master-reference attribute. In V2, we define only \Odd:twoside1 in the case of a repeatable page master reference, and we define \Lead:3:twoside1 if this is the third single page master reference in the list.

We define here <fo:single-page-master-reference>; this defines a single page. The non-trivial part here is that any Unicode character is allowed in the attribute value, and some protection is needed.

254 \XMLelement{fo:single-page-master-reference}
255    {}
256    {
257     \global\advance\SimplePMRefs1\relax
258     \begingroup
259       \utfeight@protect@chars
260       \expandafter\xdef\csname Lead:\the\SimplePMRefs:\Granpa\endcsname
261              {\FOmasterreference}
262     \endgroup
263     }
264    {}

We define here <fo:repeatable-page-master-reference>; this defines a sequence (of some length) of pages. The length is ignored. The action is as described above.

265 \XMLelement{fo:repeatable-page-master-reference}
266    {}
267    {
268     \begingroup
269       \utfeight@protect@chars
270       \expandafter\xdef\csname Odd:\Granpa\endcsname{\FOmasterreference}
271     \endgroup
272    }
273    {}

The content of <fo:repeatable-page-master-alternatives> is a sequence of conditional page master references. The recommendations specify how to chose them, but we use another algorithm.

274 \XMLelement{fo:repeatable-page-master-alternatives}
275    {} {} {}

The <fo:conditional-page-master-reference> may define one of \First:twoside1, etc., to the value of the master-reference-trait trait. This is the name of a page-master, for instance `left1´. The conditions are defined by the following traits: page-position which can be `first´, `last´(note: ), `rest´, or `any´ (here `rest´ means any page that is neither the first nor the last in a sequence); blank-or-not-blank can be `blank´, `not-blank´, or `any´ (a blank page is a forced page that contains no text); odd-or-even can be `odd´, `even´ or `any´. The parity of the page number is considered (if there are two consecutive pages numbered one, they are both odd; thus, this is not the same as left-or-right). What we do here is to define one and only one command. For instance, we could define \Even:twoside1 to be `right1´.

276 \XMLelement{fo:conditional-page-master-reference}
277    {}
278    {
279   \begingroup
280   \utfeight@protect@chars
281   \ifx\FOoddoreven\att@even
282       \expandafter\xdef\csname Even:\Granpa\endcsname{\FOmasterreference}
283   \else\ifx\FOoddoreven\att@odd
284       \expandafter\xdef\csname Odd:\Granpa\endcsname{\FOmasterreference}
285   \else \ifx\FOpageposition\att@first
286       \expandafter\xdef\csname First:\Granpa\endcsname{\FOmasterreference}
287   \else \ifx\FOblankornotblank\att@blank
288       \expandafter\xdef\csname Blank:\Granpa\endcsname{\FOmasterreference}
289   \else
290       \expandafter\xdef\csname Odd:\Granpa\endcsname{\FOmasterreference}
291   \fi\fi\fi\fi
292   \endgroup
293   }
294  {}

Declarations of attributes used here.

301 \XMLNSAX{fo}{page-position}{\FOpageposition}{any}
302 \XMLNSAX{fo}{odd-or-even}{\FOoddoreven}{any}
303 \XMLNSAX{fo}{blank-or-not-blank}{\FOblankornotblank}{any}
304 \XMLstringX\att@even<>even</>
305 \XMLstringX\att@odd<>odd</>
306 \newcount\SimplePMRefs

A <fo:page-sequence> is linked via its master-reference trait to a page master or a page sequence master. Its children are some <fo:static-content> elements (they define the content of the regions defined by the page master, except for the region-body) and a <fo:flow> that defines the content of the pages. Some important attributes are: initial-page-number that indicates the number of the first page (it can be `auto-even´ or `auto-odd´, this means that the first page number should be even or odd; it may imply the use of a blank page). The value of force-page-count can be `end-on-odd´ or `end-on-even´ (this may insert a final blank page). The language can be defined for a page sequence, a block or a character. The action is to evaluate the language trait via \FOSetHyphenation and to put the others in variables. Some traits are unused: country, letter-value, grouping-separator, grouping-size, format(note: ). In the case of the Raweb, the attributes of the main page sequence are format = `1´, text-align = `justify´, hyphenate = `true´, language = `en´, initial-page-number = `1´, master-name = `twoside1´.

307 \XMLelement{fo:page-sequence}
308   {}
309   {\let\CurrentPageMaster\FOmasterreference
310    \let\pendingID\FOid
311    \let\PageNumber\FOinitialpagenumber
312    \let\ForcePage\FOforcepagecount
313    \FOSetHyphenation
314    \LoadLanguage{\FOlanguage}
315    }
316   {}

Attributes.

317 \XMLNSAX{fo}{initial-page-number}{\FOinitialpagenumber}{auto}
318 \XMLNSAX{fo}{force-page-count}{\FOforcepagecount}{auto}
319 \XMLstringX\att@autoodd<>auto-odd</>
320 \XMLstringX\att@autoeven<>auto-even</>
321 \XMLstringX\att@endonodd<>end-on-odd</>
322 \XMLstringX\att@endoneven<>end-on-even</>

You can say <fo:static-content>, with an attribute flow-name whose value is something like xsl-region-before-right. This is the region-name of some page master (used by the current page sequence). Logically, given the name, it should define the header of odd pages. The content is a sequence of blocks, that will be typeset later (on one or more pages). The action is to call a command defined below. A priori, the result should be used only by the flow that is a sibling of this element, but this is hard to do in TeX.

323 \XMLelement{fo:static-content}
324  {}
325  {\xmlgrab}
326  {\protectCS\FOflowname
327   \FOSetStatic{#1}{\FOflowname}}

We show here a function \FOSetStatic that takes two arguments, the body of the static content, and its flow-name attribute. This code is wrong. Instead of \noexpand#1, there should be something that inserts the first argument, without expansion (this could be achieved by putting the argument in a token list, and using \the). The actual code uses \gdef instead of \xdef and \expandafter for each token that must be expanded.

\def\FOSetStatic#1#2{%
   \expandafter\xdef\csname Static:\FOflowname\endcsname
    {{{
     \def\noexpand\XML@parent{}
     \global\noexpand\FOinOutputtrue
       \def\noexpand\FOwhitespacecollapse{true}%
       \def\noexpand\FOwrapoption{wrap}%
       \def\noexpand\FOtextalign{start}%
       \def\noexpand\FOfontfamily{\FOfontfamily}%
       \def\noexpand\FOfontsize{\FOfontsize}%
       \def\noexpand\FOfontstretch{\FOfontstretch}%
       \def\noexpand\FOfontvariant{\FOfontvarian}%
       \def\noexpand\FOfontweight{\FOfontweight}%
       %\ignore{\FOtextindent}
       \def\noexpand\FOfontstyle{\FOfontstyle}
       \noexpand#1
    \global\noexpand\FOinOutputfalse
   }}}%
   \jg@hack@foot}

The action associated to <fo:static-content> is to grab some parameters. We have a sequence of commands, each of them reads and expands a quantity, and passes it to the next one. Assume that \foo expands to bar. Then bar\\ is added to the input stream. This is re-read, and converted to {bar}. This could be done directly, and left in stream until used by the final function. Said otherwise, the line shown here has the same effect and is more efficient.

\def\@@SetStatic{\expandafter\@@@SetStatic\expandafter{\FOfontweight}}

That´s the real code.

328 \def\FOSetStatic{\expandafter\@SetStatic\FOtextindent\\}
329 \def\@SetStatic#1\\{\expandafter\@@SetStatic\FOfontsize\\{#1}}
330 \def\@@SetStatic#1\\#2{\expandafter\@@@SetStatic\FOfontweight\\{#1}{#2}}
331 \def\@@@SetStatic#1\\#2#3{\expandafter
332     \@@@@SetStatic\FOfontvariant\\{#1}{#2}{#3}}
333 \def\@@@@SetStatic#1\\#2#3#4{\expandafter
334    \@@@@@SetStatic\FOfontstyle\\{#1}{#2}{#3}{#4}}
335 \def\@@@@@SetStatic#1\\#2#3#4#5{\expandafter
336    \@@@@@@SetStatic\FOfontstretch\\{#1}{#2}{#3}{#4}{#5}}
337 \def\@@@@@@SetStatic#1\\#2#3#4#5#6{\expandafter
338     \@@@@@@@SetStatic\FOfontfamily\\{#1}{#2}{#3}{#4}{#5}{#6}}

This code globally defines \Static:xsl-region-before-right (or a command like this) whose effect is to execute the content of the <fo:static-content> in a TeX group, where some parameters are defined. These parameters are: font family, font stretch, font style, font variant, font weight, font size, textindent (unused, but explicitly set to zero in the main block of the static content), (arguments #1 to #7). Argument #8 is the content, argument #9 is the name. The switch \ifFOinOutput is set to true while evaluating the content. The \XML@parent command is locally set to empty. See explanations later.

339 \def\@@@@@@@SetStatic#1\\#2#3#4#5#6#7#8#9{%
340    \expandafter\gdef\csname Static:#9\endcsname{%
341      {%
342       {\def\XML@parent{}\global\FOinOutputtrue
343        \def\FOwhitespacecollapse{true}%
344        \def\FOwrapoption{wrap}%
345        \def\FOtextalign{start}%
346        \def\FOfontfamily{#1}%
347        \def\FOfontsize{#6}%
348        \def\FOfontstretch{#2}%
349        \def\FOfontvariant{#4}%
350        \def\FOfontweight{#5}%
351        \def\FOfontstyle{#3}#8\global\FOinOutputfalse}}}%
352    \jg@hack@foot{#9}
353 }

Assume that \Static:xsl-footnote-separator was just defined. Said otherwise, we have defined a static region for the footnote separator. We store in \footnoterulepre the name of this command, and execute it. This should produce the footnote rule. The dimension of the resulting box is remembered in \skip\footins, a quantity that defaults to \bigskipamount. We set \footnotesep to zero. This quantity is defined by the class file (to 6.6pt for a ten point article). Finally, we define \footnoterule to use this funny command in a vbox of height zero. The \vfill is strange.

354 \def\jg@hack@foot#1{
355   \ifx\FOflowname\att@xsl@footnote@separator\relax
356     \xdef\footnoterulepre{Static:#1}%
357     \global\footnotesep\z@
358     \setbox\@tempboxa\vbox{\csname\footnoterulepre\endcsname}%
359     \@tempdima=\z@
360     \advance\@tempdima\ht\@tempboxa
361     \advance\@tempdima\dp\@tempboxa
362     \global\skip\footins\@tempdima\relax
363     \gdef\footnoterule{\vfill\vbox to\z@{
364        \vss\csname\footnoterulepre\endcsname}}%
365   \fi
366 }

We define here the action associated to DummyRegion, it is empty.

367 \expandafter\def\csname Static:DummyRegion\endcsname{}
368 \XMLNSAX{fo}{flow-name}{\FOflowname}{}

4.7. Flows

Changes in V2: the command \setaccordingtomaster was added; it contains a very long (one hundred lines) and complicated piece of code, moved from fotex.xmt to fotex.sty. We have split this code into smaller pieces, this is the only way to understand what happens. Another change: a great number of assignments are made global, replacing \def by \gdef, \edef by \xdef, or adding a \global prefix. The command \BlankPage not only creates a blank page, but also ships it out. Finally, handling of multiple columns per page has changed.

The content of the <fo:flow> formatting object is a sequence of blocks that defines a sequence of pages. The action associated is a bit complicated; for this reason, we shall define some pseudo functions instead of the original big code. Let´s recall that the <fo:page-sequence> element remembers in \pendingID the current id and in \PageNumber the value of the initial page number. What we do here is to evaluate these instructions. We start with \clearpage, this makes sure that all pages are shipped out; this is not needed in the case where there are more than one column per page, see below. In the case where the desired page number is `auto´ we are done; if it is `auto-odd´ or `auto-even´, we emit an empty page, if needed, so as to make sure that the page number has the given parity. Finally, the page number can be an integer, in this case, we set the page counter. From now one, the page number is correct, so that we can insert the label of the parent. It is however too early to typeset something, for instance, \textwidth is still random. Changes in V2: \BlankPage used instead of \hbox{}\newpage.

369 \def\jg@flowI{%
370   \ifnum\PrevNColumns>1\relax
371   \else
372    \clearpage
373   \fi
374   \ifx\PageNumber\att@auto
375   \else
376      \ifx\PageNumber\att@autoeven
377         \ifodd\c@page\BlankPage\fi
378      \else
379         \ifx\PageNumber\att@autoodd
380           \ifodd\c@page\else\BlankPage\fi
381         \else
382           \setcounter{page}{\PageNumber}%
383         \fi
384      \fi
385   \fi
386   \let\FOid\pendingID \FOlabel\global\let\pendingID\@empty % hacked jg
387 }

After evaluation of the children of the flow, we terminate with a \clearpage. We look at the force-page-count trait. If this imposes that the last page be even or odd, we may emit a blank page (note that the page counter holds one more than the last page number).

388 \def\jg@flowV{%
389    \clearpage
390    \ifx\ForcePage\att@auto
391    \else
392      \ifx\ForcePage\att@endoneven
393        \ifodd\c@page\else\BlankPage\fi
394      \else
395         \ifx\ForcePage\att@endonodd
396           \ifodd\c@page\BlankPage\fi
397         \fi
398      \fi
399    \fi
400 }

We define now four quantities \PEven, \POdd, \PBlank and \PFirst according to the master-reference; this can be the name of a page-sequence-master or a page-master. In the second case, we put this name into all four commands(note: ). Otherwise, the reference is something like `twoside1´ and the command \Odd:twoside1 is a pagemaster. We put this value in \POdd. We do the same for the other commands. However, if \Peven is undefined, we use the value of \POdd instead. The case of \PFirst is a bit more complicated: in fact, if it is undefined, we look at the parity of the current page number. The code shown here is much simpler than the initial one, but has the same effects. Note: the code shown in the first version of the document was wrong; we have replaced it by a call to \ifnotdefined, that is a conditional macro that should evaluate to true if the argument comes from an undefined \csname. We shall give the real code below.

  \@ifundefined{Atomic:\CurrentPageMaster}
   {
    \edef\PFirst{\csname First:\CurrentPageMaster\endcsname}
    \edef\PBlank{\csname Blank:\CurrentPageMaster\endcsname}
    \edef\PEven{\csname Even:\CurrentPageMaster\endcsname}
    \edef\POdd{\csname Odd:\CurrentPageMaster\endcsname}
    \ifnotdefined\PBlank\let\PBlank\POdd\fi
    \ifnotdefined\PEven\let\PEven\POdd\fi
    \ifnotdefined\PFirst
      \ifodd\c@page\let\PFirst\POdd \else\let\PFirst\PEven\fi\fi
  }
  {...}

In order to make the code easy to understand, we introduce the command \Fdef, and we can say \Fdef{\POdd}{Odd}. This defines \POdd as above. The next function computes \PFirst; we cannot say: if the page master does not define First, than use \POdd or \Peven because these commands are not yet defined. If the first page is even, the value of \PFirst depends on whether the page master defines Even; if undefined, we use the value for odd pages. We use \Cdef for such a conditional definition. There is a further complication. The value of the first page is defined by \FOinitialpagenumber. In the code shown above, we assumed that the page counter has already been set according to this value. In the code below, this is not necessarily true. Thus, we introduce \Pdef that sets its first argument depending on the parity of the second.

401 \def\Fdef#1#2{\xdef#1{\csname #2:\CurrentPageMaster\endcsname}
402 \def\Cdef#1#2#3{%
403  \@ifundefined{#2:\CurrentPageMaster}
404    {\Fdef{#1}{#3}}{\Fdef{#1}{#2}}%
405 }
406 \def\Pdef#1#2{%
407    \ifodd#2 \Fdef{#1}{Odd}
408    \else \Cdef{#1}{Even}{Odd}\fi
409 }
410  
411 \def\jg@compute@Pfirst{%
412  \@ifundefined{First:\CurrentPageMaster}
413    {
414     \ifx\FOinitialpagenumber\att@auto
415       \Pdef\PFirst\c@page
416     \else \ifx\FOinitialpagenumber\att@autoeven
417       \Cdef{\PFirst}{Even}{Odd}
418     \else \ifx\FOinitialpagenumber\att@autoodd
419       \Fdef{\Pfirst}{Odd}
420     \else
421       \Pdef\Pfirst\FOinitialpagenumber
422     \fi\fi\fi\fi
423    }
424    {\Fdef{\Pfirst}{First} }
425 }

This is the complete code, in the case of a page sequence master like `twoside1´. A non trivial question is when to use \PFirst. The answer is when the boolean @specialpage is true. This is initially set to true, then to false after first use. A special case is when \Lead:17:twoside1 is not defined, but could be used. In this case, the page is special if the number is one, non-special otherwise.

426 \def\jg@flowII@conditional{
427  \ifnum\SimplePMRefs>1\relax\global\@specialpagefalse\fi
428  \jg@compute@Pfirst
429  \Cdef{\PBlank}{Blank}{Odd}
430  \Cdef{\PEven}{Even}{Odd}
431  \Fdef{\POdd}{Odd}
432 }

This is the code in case the reference is a page-master sequence. In the case \Lead:17:twoside1 is defined, this is the name of the page to be used, whatever the value of the page number.

433 \def\jg@flowII{
434  \@ifundefined{Lead:\the\SimplePMRefs:\CurrentPageMaster}
435  { \jg@flowII@conditional }
436  {
437    \xdef\PFirst{\csname Lead:\the\SimplePMRefs:\CurrentPageMaster\endcsname}
438    \global\let\POdd\PFirst
439    \global\let\PEven\PFirst
440    \global\let\PBlank\PFirst
441  }
442 }

This is now the whole function. There are two cases to consider. The master-reference can be the name a page-master, for instance `left1´, case where \Atomic:left1 is defined and we set \First, as well as all other quantities to `left1´. It can be a page-sequence-master, case handled above. Action associated to \jg@flowIII is described later.

443 \def\setaccordingtomaster{%
444   \global\@specialpagetrue
445   \@ifundefined{Atomic:\CurrentPageMaster}
446    { \jg@flowII }
447    {
448     \global\let\PFirst\CurrentPageMaster
449     \global\let\PBlank\CurrentPageMaster
450     \global\let\POdd\CurrentPageMaster
451     \global\let\PEven\CurrentPageMaster
452    }
453   \jg@flowIII
454 }

We use the \PEven command to define four commands, that contain the name of the header, footer, and their extent. The same is done for the other type of pages.

455 \def\jg@set@headings{
456    \xdef\EvenHeadExtent{\csname\PEven:before-extent\endcsname}
457    \xdef\EvenHead{Static:\csname\PEven:before\endcsname}
458    \xdef\EvenTailExtent{\csname\PEven:after-extent\endcsname}
459    \xdef\EvenTail{Static:\csname\PEven:after\endcsname}
460    \xdef\FirstHeadExtent{\csname\PFirst:before-extent\endcsname}
461    \xdef\FirstHead{Static:\csname\PFirst:before\endcsname}
462    \xdef\FirstTailExtent{\csname\PFirst:after-extent\endcsname}
463    \xdef\FirstTail{Static:\csname\PFirst:after\endcsname}
464    \xdef\OddHeadExtent{\csname\POdd:before-extent\endcsname}
465    \xdef\OddHead{Static:\csname\POdd:before\endcsname}
466    \xdef\OddTailExtent{\csname\POdd:after-extent\endcsname}
467    \xdef\OddTail{Static:\csname\POdd:after\endcsname}
468    \xdef\BlankHeadExtent{\csname\PBlank:before-extent\endcsname}
469    \xdef\BlankHead{Static:\csname\PBlank:before\endcsname}
470    \xdef\BlankTailExtent{\csname\PBlank:after-extent\endcsname}
471    \xdef\BlankTail{Static:\csname\PBlank:after\endcsname}
472 }

We define here a function that fetches some of these parameters. The value stored in \themargin will be defined later. It depends on the parity of the page number. This was not in the original fotex.sty.

473 \def\jg@use@blankpage{%
474     \def\@thehead{\csname\BlankHead\endcsname}%
475     \def\@thefoot{\csname\BlankTail\endcsname}%
476      \ifodd\count\z@ \let\@themargin\oddsidemargin
477      \else \let\@themargin\evensidemargin\fi
478     \def\headheight{\BlankHeadExtent}%
479     \def\tailheight{\BlankTailExtent}}%

We consider here three commands that handle the other cases. It is assumed that the first page is always odd.

480 \def\jg@use@specialpage{%
481     \def\@thehead{\csname\FirstHead\endcsname}%
482     \def\@thefoot{\csname\FirstTail\endcsname}%
483     \let\@themargin\oddsidemargin
484     \def\headheight{\FirstHeadExtent}%
485     \def\tailheight{\FirstTailExtent}}%

Case of even pages.

486 \def\jg@use@evenpage{%
487     \def\@thehead{\csname\EvenHead\endcsname}%
488     \def\@thefoot{\csname\EvenTail\endcsname}%
489     \let\@themargin\evensidemargin
490     \def\headheight{\EvenHeadExtent}%
491     \def\tailheight{\EvenTailExtent}}%

Case of odd pages.

492 \def\jg@use@oddpage{%
493     \def\@thehead{\csname\OddHead\endcsname}%
494     \def\@thefoot{\csname\OddTail\endcsname}%
495     \let\@themargin\oddsidemargin
496     \def\headheight{\OddHeadExtent}%
497     \def\tailheight{\OddTailExtent}}%

This is how we select one of these four commands.

498 \newif\ifBlankPage
499 \def\jg@usepagestyle{%
500  \ifBlankPage
501     \jg@use@blankpage
502  \else \if@specialpage
503    \jg@use@specialpage
504  \else \ifodd\count\z@
505    \jg@use@oddpage\else \jg@use@evenpage
506  \fi\fi\fi
507  \global\@specialpagefalse
508  \global\BlankPagefalse
509 }

This defines a blank page. The original code was wrong. This was corrected in V2. Originally there was a \mark{}, it has disappeared. Is this OK?

510 \def\nocontentbox{\vbox to \z@{}}
511 \def\BlankPage{%
512  \global\BlankPagetrue
513  \nocontentbox
514  \newpage
515 }

The original output routine contained: \hb@xt@ \textwidth {\@thehead}. In the code that follows, we removed the line that decreases the text width by \FOheadindent, because this value is always zero. We also replace \vfil by \vss, in the case of a border.

516 \def\jg@headings#1#2{%
517   \@tempdima\textwidth
518   %\advance\@tempdima by -\FOheadindent
519   \setbox\@tempboxa \vbox to #1{%
520      \color@hbox
521      \normalcolor
522      \hb@xt@\textwidth{\hfill\llap{\hb@xt@\@tempdima{#2}}}%
523      \color@endbox
524      \vss%  \vfil
525   }%
526   \dp\@tempboxa \z@
527   \box\@tempboxa}%

The boolean quantity \ifForcePageSetup is sometimes true. We shall see later that it is true inside a flow, said otherwise, almost always. The command is called at the end of the output routine; we increment the \SimplePMRefs counter, and recompute the new page master. This is done for every page; in V1, it was done once per <fo:flow>; this make the code a little bit slower.

528 \def\jg@check@setup{%
529  \ifForcePageSetup
530    \global\advance\SimplePMRefs1\relax
531    \setaccordingtomaster
532    \ifnum\NColumns>1\relax
533      \refreshmulticols
534    \fi\fi
535 }

This is the modified output routine. Changes in V2 use \offinterlineskip instead of the code commented out below. The result is not exactly the same. Added lines marked V2.

536 \def\@outputpage{%
537 \begingroup           % the \endgroup is put in by \aftergroup
538   \let \protect \noexpand
539 %  \@resetactivechars
540   \@parboxrestore
541   \shipout \vbox{%
542     \set@typeset@protect
543     \aftergroup \endgroup
544     \aftergroup \set@typeset@protect
545   \jg@usepagestyle
546   \reset@font
547   \normalsize
548   \normalsfcodes
549   \let\label\@gobble
550   \let\index\@gobble
551   \let\glossary\@gobble
552   \offinterlineskip
553   %\baselineskip\z@skip \lineskip\z@skip \lineskiplimit\z@  % V2 remove
554    \@begindvi
555     \vskip \topmargin
556     \vskip -\InnerTopMargin  % V2 add
557     \moveright\@themargin \vbox {%
558       \jg@headings{\headheight}{\@thehead}%
559       \vskip \headsep
560       \vskip\InnerTopMargin % V2 add
561       \box\@outputbox
562       \baselineskip \footskip
563       \vskip \bottommargin
564       \vskip-\tailheight % V2 add
565       \jg@headings{\tailheight}{\@thefoot}%
566       }%
567     }%
568   \global \@colht \textheight
569   \stepcounter{page}
570   \jg@check@setup  % V2 add
571   \let\firstmark\botmark
572 }

Bootstrap code. Seems useless. As a consequence, no variable is added for blank pages.

573 \gdef\OddTail {}
574 \gdef\OddHead {}
575 \gdef\EvenTail {}
576 \gdef\EvenHead {}
577 \gdef\FirstTail {}
578 \gdef\FirstHead {}
579 \gdef\OddTailExtent{\z@}
580 \gdef\OddHeadExtent{\z@}
581 \gdef\EvenTailExtent{\z@}
582 \gdef\EvenHeadExtent{\z@}
583 \gdef\FirstTailExtent{\z@}
584 \gdef\FirstHeadExtent{\z@}

We simplified the code by removing all references to a quantity SpecialOffset that was always zero. We have already explained what the \Pass command does: it fetches some parameters from the region-body (note the fixed name here); they are \columnsep, \NColumns, \Marginbottom and \Margintop. We also evaluate \Atomic:XXX. The result is to define \MasterXXXMargins, as well as \paperwidth and \paperheight. We hope that both evaluations yield the same result. The only difference between them is that the left margin can change (we hope that the sum of the left and right margins are the same). All these variables will be used by \FOSetPage, and forgotten after that.

585 \def\jg@flowIII{%
586   \expandafter\Pass\csname\POdd:xsl-region-body\endcsname\\
587   \csname Atomic:\POdd\endcsname
588   \global\oddsidemargin\MasterLeftMargin
589   \csname Atomic:\PEven\endcsname
590   \global\evensidemargin\MasterLeftMargin
591   \jg@set@headings
592   \FOSetPage}

The purpose of this command is to compute the text height and text width, and to store it wherever needed (\hsize, \vsize, \@colht, etc). We also remember three quantities: \bottommargin, \headsep and \topmargin. There are two kinds of changes in V2. Some lines are commented out because some quantities are now computed differently. On the other hand, this command is called from \jg@flowIII, hence from \@outputpage, hence inside the \output command; this explains while assignments must be global. Moreover, since this is called for every page, the current page is no more special, and the assignment to \if@specialpage has to be moved elsewhere.

593 \def\FOSetPage{%
594  \global\bottommargin\Marginbottom
595 % \global\headsep\Margintop
596  \global\headsep\z@
597  \global\topmargin\MasterTopMargin
598  \global\textheight\paperheight
599  \global\textwidth\paperwidth
600 % \global\advance\textheight by -\FirstHeadExtent
601 % \global\advance\textheight by -\FirstTailExtent
602  \global\advance\textheight by -\MasterTopMargin
603 % \global\advance\textheight by -\Margintop
604  \global\advance\textheight by -\MasterBottomMargin
605 % \global\advance\textheight by -\Marginbottom
606  \global\advance\textwidth by -\MasterLeftMargin
607  \global\advance\textwidth by -\MasterRightMargin
608  \FOpdfsetpagesize{\paperwidth}{\paperheight}
609  \global\global\@colht\textheight
610  \global\@colroom\textheight
611  \global\vsize\textheight
612 % \global\linewidth\textwidth
613  \global\columnwidth\textwidth
614  \global\hsize\columnwidth
615  \global\linewidth\hsize
616  \gdef\headheight{12pt}%
617  \FOResetPageParts
618 % \global\@specialpagetrue
619 }

The next command is used for typesetting lists. In the case where \This@LineWidth is defined, i.e., non-\relax, we put its value into \linewidth.

620 \def\FOResetPageParts{
621   \expandafter\ifx\csname This@LineWidth\endcsname\relax\else
622       \global\linewidth\This@LineWidth\relax
623  \fi
624 }

This might be useful.

625 \def\FOpdfsetpagesize#1#2{%
626  \@ifundefined{pdfoutput}{}{%
627    \global\pdfpagewidth\paperwidth
628    \global\pdfpageheight\paperheight}}

Added in V2. Added at the start of a \fo:flow element.

629 \def\jg@start@multicolumns{%
630    \xdef\PrevNColumns{\NColumns}%
631    \ForcePageSetuptrue
632    \ifnum\NColumns>1\relax \nobeginmulticols{\NColumns}%
633    \fi}

Added at the end of a \fo:flow element.

634 \def\jg@end@multicolumns{%
635   \ForcePageSetupfalse
636   \ifnum\NColumns>1\relax \noendmulticols
637   \else \clearpage
638   \fi
639 }

This is the flow element. With all these simplifications and auxiliary commands, the code becomes easy to understand.

640 \XMLelement{fo:flow}
641   {}
642   {\global\SimplePMRefs1\relax
643    \FOSetHyphenation
644    \jg@flowI
645    \setaccordingtomaster
646    \jg@start@multicolumns
647    }
648   {
649    \jg@end@multicolumns
650    \jg@flowV
651    }

4.8. Borders

A border has three properties: a color, a style and a width. There are four borders. They are called `before´, `after´, `start´ and `end´. These quantities are called relative, because they depend on the writing-mode trait. We assume that this is `lr-td´ (Inline components and text within a line are written left-to-right. Lines and blocks are placed top-to-bottom). In such a case, `before´ is `top´, `after´ is `bottom´, `start´ is `left´ and `end´ is `right´, see schema section 4.5. Quantities like `top´ and `bottom´ are called absolute. We shall use absolute quantities only to set relative quantities.

Here we declare the relative attributes.

652 \XMLNSA{fo}{border-before-color}{\FOborderbeforecolor}{\FOcolor}
653 \XMLNSA{fo}{border-after-color}{\FOborderaftercolor}{\FOcolor}
654 \XMLNSA{fo}{border-start-color}{\FOborderstartcolor}{\FOcolor}
655 \XMLNSA{fo}{border-end-color}{\FOborderendcolor}{\FOcolor}
656  
657 \XMLNSAX{fo}{border-before-style}{\FOborderbeforestyle}{none}
658 \XMLNSAX{fo}{border-after-style}{\FOborderafterstyle}{none}
659 \XMLNSAX{fo}{border-start-style}{\FOborderstartstyle}{none}
660 \XMLNSAX{fo}{border-end-style}{\FOborderendstyle}{none}
661  
662 \XMLNSA{fo}{border-before-width}{\FOborderbeforewidth}{medium}
663 \XMLNSA{fo}{border-after-width}{\FOborderafterwidth}{medium}
664 \XMLNSAX{fo}{border-start-width}{\FOborderstartwidth}{medium}
665 \XMLNSAX{fo}{border-end-width}{\FOborderendwidth}{medium}

Here we declare the absolute attributes. The default value is a special marker.

666 \XMLNSA{fo}{border-top-color}{\FObordertopcolor}{\LINK}
667 \XMLNSA{fo}{border-bottom-color}{\FOborderbottomcolor}{\LINK}
668 \XMLNSA{fo}{border-left-color}{\FOborderleftcolor}{\LINK}
669 \XMLNSA{fo}{border-right-color}{\FOborderrightcolor}{\LINK}
670  
671 \XMLNSAX{fo}{border-top-style}{\FObordertopstyle}{\LINK}
672 \XMLNSAX{fo}{border-bottom-style}{\FOborderbottomstyle}{\LINK}
673 \XMLNSAX{fo}{border-left-style}{\FOborderleftstyle}{\LINK}
674 \XMLNSAX{fo}{border-right-style}{\FOborderrightstyle}{\LINK}
675  
676 \XMLNSAX{fo}{border-top-width}{\FObordertopwidth}{\LINK}
677 \XMLNSAX{fo}{border-bottom-width}{\FOborderbottomwidth}{\LINK}
678 \XMLNSAX{fo}{border-left-width}{\FOborderleftwidth}{\LINK}
679 \XMLNSAX{fo}{border-right-width}{\FOborderrightwidth}{\LINK}
680  
681 \XMLNSAX{fo}{border-left}{\FOborderleft}{\LINK}
682 \XMLNSAX{fo}{border-right}{\FOborderright}{\LINK}
683 \XMLNSAX{fo}{border-top}{\FObordertop}{\LINK}
684 \XMLNSAX{fo}{border-bottom}{\FOborderbottom}{\LINK}

The attribute border is a shorthand for all four borders. Its value is a list of three items: width, style and color. This means that border = `thin solid red´ is a valid specification. All four borders will have the same value; the command \interpretwidth replaces `thin´ by a numeric value.

685 \def\expandBorder#1 #2 #3\\{%
686     \def\FOborderstartcolor{#3}%
687     \def\FOborderendcolor{#3}%
688     \def\FOborderbeforecolor{#3}%
689     \def\FOborderaftercolor{#3}%
690     \def\FOborderstartwidth{#1}%
691     \def\FOborderendwidth{#1}%
692     \def\FOborderbeforewidth{#1}%
693     \def\FOborderafterwidth{#1}%
694     \def\FOborderstartstyle{#2}%
695     \def\FOborderendstyle{#2}%
696     \def\FOborderbeforestyle{#2}%
697     \def\FOborderafterstyle{#2}
698     \interpretwidth
699 }

The width of a border can be a dimension, or one of `thin´, `medium´ or `thick´. This command sets the width to 0.4pt, 0.8pt or 1.2pt accordingly.

700 \def\interpretwidth{%
701    \ifx\FOborderwidth\att@thin\def\FOborderwidth{0.4pt}\fi
702    \ifx\FOborderwidth\att@medium\def\FOborderwidth{0.8pt}\fi
703    \ifx\FOborderwidth\att@thick\def\FOborderwidth{1.2pt}\fi
704    \ifx\FOborderbeforewidth\att@thin\def\FOborderbeforewidth{0.4pt}\fi
705    \ifx\FOborderbeforewidth\att@medium\def\FOborderbeforewidth{0.8pt}\fi
706    \ifx\FOborderbeforewidth\att@thick\def\FOborderbeforewidth{1.2pt}\fi
707    \ifx\FOborderafterwidth\att@thin\def\FOborderafterwidth{0.4pt}\fi
708    \ifx\FOborderafterwidth\att@medium\def\FOborderafterwidth{0.8pt}\fi
709    \ifx\FOborderafterwidth\att@thick\def\FOborderafterwidth{1.2pt}\fi
710    \ifx\FOborderstartwidth\att@thin\def\FOborderstartwidth{0.4pt}\fi
711    \ifx\FOborderstartwidth\att@medium\def\FOborderstartwidth{0.8pt}\fi
712    \ifx\FOborderstartwidth\att@thick\def\FOborderstartwidth{1.2pt}\fi
713    \ifx\FOborderendwidth\att@thin\def\FOborderendwidth{0.4pt}\fi
714    \ifx\FOborderendwidth\att@medium\def\FOborderendwidth{0.8pt}\fi
715    \ifx\FOborderendwidth\att@thick\def\FOborderendwidth{1.2pt}\fi
716 }

We declare here the border attribute. There are three other attributes that specify only one quantity (color, width, style) for all four borders.

717 \XMLNSAX{fo}{border}{\FOborder}{}
718 \XMLNSA{fo}{border-color}{\FObordercolor}{black}
719 \XMLNSAX{fo}{border-width}{\FOborderwidth}{}
720 \XMLNSAX{fo}{border-style}{\FOborderstyle}{}

We declare here the padding variables(note: ).

721 \XMLNSAX{fo}{padding}{\FOpadding}{\z@}
722  
723 \XMLNSAX{fo}{padding-top}{\FOpaddingtop}{\z@}
724 \XMLNSAX{fo}{padding-bottom}{\FOpaddingbottom}{\z@}
725 \XMLNSAX{fo}{padding-left}{\FOpaddingleft}{\z@}
726 \XMLNSAX{fo}{padding-right}{\FOpaddingright}{\z@}
727  
728 \XMLNSAX{fo}{padding-before}{\FOpaddingbefore}{\z@}
729 \XMLNSAX{fo}{padding-after}{\FOpaddingafter}{\z@}
730 \XMLNSAX{fo}{padding-start}{\FOpaddingstart}{\z@}
731 \XMLNSAX{fo}{padding-end}{\FOpaddingend}{\z@}

Here we declare the attributes for the margins, and we define default values. These values are absolute. The corresponding relative properties are space-before, space-after, space-start, and space-end. The quantities space-before and space-after are defined for block level formatting objects (in \SpaceAttributes), while space-start, and space-end are for inline objects(note: ). There are also two quantities start-indent, end-indent which are related to margins, but are a bit complicated. They are defined later.

732 \XMLNSAX{fo}{margin}{\FOmargin}{}
733 \XMLNSAX{fo}{margin-left}  {\FOmarginleft}  {0pt}
734 \XMLNSAX{fo}{margin-right}  {\FOmarginright}  {0pt}
735 \XMLNSAX{fo}{margin-top}  {\FOmargintop}  {0pt}
736 \XMLNSAX{fo}{margin-bottom}  {\FOmarginbottom}  {0pt}
737  
738 \gdef\FOmarginbottom{\z@}
739 \gdef\FOmarginleft{\z@}
740 \gdef\FOmarginright{\z@}
741 \gdef\FOmargintop{}

Absolute values have precedence over relative values, for the style, width and color of a border, hence the 12 first lines of the code. The case of the border is a bit special, and explained above. In the case of style, width, color, and margin, you can either set a single value, or four values. This code copies the single value in the four slots whenever adequate. In the case of color, there is a little problem: the code here makes no difference between black and no value. Finally, we hack the border style. The value can be one of `none´, `hidden´, `dotted´, `dashed´, `solid´, `double´, `groove´, `ridge´, `inset´, or `outset´. Currently, only `solid´ is implemented. In all other cases, we set the width to zero and ignore it. In the case where one of the four borders is solid, we set a boolean value to true. The line marked `JG´ was not in the original...

742 \def\FOexpandattributes{%
743 \ifx\FObordertopstyle\LINK\else\let\FOborderbeforestyle\FObordertopstyle\fi
744 \ifx\FOborderbottomstyle\LINK\else\let\FOborderafterstyle\FOborderbottomstyle\fi
745 \ifx\FOborderrightstyle\LINK\else\let\FOborderendstyle\FOborderrightstyle\fi
746 \ifx\FOborderleftstyle\LINK\else\let\FOborderstartstyle\FOborderleftstyle\fi
747 \ifx\FObordertopwidth\LINK\else\let\FOborderbeforewidth\FObordertopwidth\fi
748 \ifx\FOborderbottomwidth\LINK\else\let\FOborderafterwidth\FOborderbottomwidth\fi
749 \ifx\FOborderrightwidth\LINK\else\let\FOborderendwidth\FOborderrightwidth\fi
750 \ifx\FOborderleftwidth\LINK\else\let\FOborderstartwidth\FOborderleftwidth\fi
751 \ifx\FObordertopcolor\LINK\else\let\FOborderbeforecolor\FObordertopcolor\fi
752 \ifx\FOborderbottomcolor\LINK\else\let\FOborderaftercolor\FOborderbottomcolor\fi
753 \ifx\FOborderrightcolor\LINK\else\let\FOborderendcolor\FOborderrightcolor\fi
754 \ifx\FOborderleftcolor\LINK\else\let\FOborderstartcolor\FOborderleftcolor\fi
755   \ifx\FObordercolor\att@black
756   \else
757     \let\FOborderstartcolor\FObordercolor
758     \let\FOborderendcolor\FObordercolor
759     \let\FOborderbeforecolor\FObordercolor
760     \let\FOborderaftercolor\FObordercolor
761   \fi
762   \ifx\FOborderwidth\@empty
763   \else
764     \let\FOborderstartwidth\FOborderwidth
765     \let\FOborderendwidth\FOborderwidth
766     \let\FOborderbeforewidth\FOborderwidth
767     \let\FOborderafterwidth\FOborderwidth
768   \fi
769   \ifx\FOborderstyle\@empty
770   \else
771     \let\FOborderstartstyle\FOborderstyle
772     \let\FOborderendstyle\FOborderstyle
773     \let\FOborderbeforestyle\FOborderstyle
774     \let\FOborderafterstyle\FOborderstyle
775   \fi
776   \ifx\FOborder\@empty
777   \else
778     \expandafter\expandBorder\FOborder\\{}%
779   \fi
780   \ifdim\FOpadding>\z@
781     \let\FOpaddingstart\FOpadding
782     \let\FOpaddingend\FOpadding
783     \let\FOpaddingbefore\FOpadding
784     \let\FOpaddingafter\FOpadding
785   \fi
786   \ifx\FOmargin\@empty
787   \else
788     \let\tmpmargin\FOmargin
789     \let\FOmarginleft\tmpmargin
790     \let\FOmarginright\tmpmargin
791     \let\FOmargintop\tmpmargin
792     \let\FOmarginbottom\tmpmargin
793   \fi
794   \ifx\FOborderendstyle\att@solid
795    \FOBlockGrabtrue
796   \else
797    \def\FOborderendwidth{\z@}%
798   \fi
799   \ifx\FOborderstartstyle\att@solid
800    \FOBlockGrabtrue
801   \else
802    \def\FOborderstartwidth{\z@}%
803   \fi
804   \ifx\FOborderafterstyle\att@solid
805    \FOBlockGrabtrue %%  <---  JG
806   \else
807    \def\FOborderafterwidth{\z@}%
808   \fi
809   \ifx\FOborderbeforestyle\att@solid
810    \FOBlockGrabtrue
811   \else
812    \def\FOborderbeforewidth{\z@}%
813   \fi
814   \interpretwidth
815 }

4.9. Spacing for blocks

In XSL/Format a block is the equivalent of a TeX box. It can define some space before it, and after it. If we have two blocks, one with some space x after it and another one, with some space y before it, there are some precedence rules that explain what to do. These are not implemented in fotex. However assume that we have a sequence of spaces; each such sequence is defined by a triple (x 1 ,x 2 ,x 3 ), optimum, maximum, and minimum value. If I understand correctly, the following happens. First, the largest sequence of spaces is considered. Then, conditionality is considered; this is used at the start or end of a page, at the start or end of a line (in LaTeX, it is the difference between \hspace and \hspace*); in such a case, all initial conditional spaces are removed. If any of these spaces is forcing, the result is the sum of the forcing spaces, otherwise, the merge of them. When merging spaces, only those of highest priority are used. Consider two of them (x 1 ,x 2 ,x 3 ), and (y 1 ,y 2 ,y 3 ). If x 1 y 1 (different optimum values), then the one with lowest optimum value is discarded. Otherwise, the result is (x 1 =y 1 ,min(x 2 ,y 2 ),max(x 3 ,y 3 )).

These spaces are local to a block, hence are not globally defined.

816 \def\SpaceAttributes{
817  \XMLattributeX{space-after.optimum}{\FOspaceafteroptimum}{\z@}
818  \XMLattributeX{space-after.maximum}{\FOspaceaftermaximum}{\z@}
819  \XMLattributeX{space-after.minimum}{\FOspaceafterminimum}{\z@}
820  \XMLattributeX{space-before.optimum}{\FOspacebeforeoptimum}{\z@}
821  \XMLattributeX{space-before.maximum}{\FOspacebeforemaximum}{\z@}
822  \XMLattributeX{space-before.minimum}{\FOspacebeforeminimum}{\z@}
823  \XMLattributeX{space-after}{\FOspaceafter}{}
824  \XMLattributeX{space-before}{\FOspacebefore}{}}

This is how we use these space-after.xxx attributes. Original code was inlined. Let A, B, and C, be the optimum, minimum and maximum values. The specifications say that, if \FOspaceafter is given, this should be the value of non-provided A, B and C. It also states that, if margin-top is defined, then setting space-before.minimum will have no effect. The code that follows does not implement these subtleties. Assume that the values are 2, 3 and 4pt. Then we could use some glue of value 3pt plus 1pt minus 1pt. The shrink part is A-B, the stretch part is C-A. This code uses A+C instead (strange). In fact, the stretch value can grow arbitrarily in TeX; said otherwise, we cannot implement exactly the XSL/Format mechanism. The argument of this command is a skip register, that contains the desired glue, or a TeX command that uses the glue.

825 \def\jg@usespaceafter#1{
826   \ifx\@empty\FOspaceafter
827       \@tempdima\FOspaceafteroptimum
828       \advance\@tempdima by -\FOspaceafterminimum
829       \@tempdimb\FOspaceafteroptimum
830       \advance\@tempdimb by \FOspaceaftermaximum
831       #1\FOspaceafteroptimum plus \@tempdimb minus \@tempdima
832     \else
833       #1\FOspaceafter
834     \fi}

This is how we use these space-before.xxx attributes. Original code was inlined. The code is as above.

835 \def\jg@usespacebefore#1{
836     \ifx\@empty\FOspacebefore
837       \@tempdima\FOspacebeforeoptimum
838       \advance\@tempdima by -\FOspacebeforeminimum
839       \@tempdimb\FOspacebeforeoptimum
840       \advance\@tempdimb by \FOspacebeforemaximum
841       #1\FOspacebeforeoptimum plus \@tempdimb minus \@tempdima
842     \else
843       #1\FOspacebefore
844     \fi}

Attributes for keep-together. There are three sub-cases: within line, page, column. The value can be `always´, `auto´, or a number. It corresponds in TeX to some penalty: 0 for `auto´, 10000 for `always´. Otherwise, the number should produce something between these two values (currently ignored). Keep-within-line means a penalty in horizontal mode, otherwise in vertical mode. Note that it is not possible to associate a penalty to a column-break (in TeX switching from one column to the other is the same as switching from one page to the other; the difference is how \output handles these cases). The within-line case is not implemented.

845 \XMLNSAX{fo}{keep-together}{\FOkeeptogether}{\inherit}
846 \XMLNSAX{fo}{keep-together.within-column} {\FOkeeptogetherColumn}{\inherit}
847 \XMLNSAX{fo}{keep-together.within-page} {\FOkeeptogetherPage}{\inherit}
848 \XMLstringX\att@always<>always</>

Attributes for keep-with-next. As above. There is also a keep-with-previous, but this is not implemented. Too bad.

849 \XMLNSAX{fo}{keep-with-next}{\FOkeepwithnext}{auto}
850 \XMLNSAX{fo}{keep-with-next.within-column}{\FOkeepwithnextColumn}{auto}
851 \XMLNSAX{fo}{keep-with-next.within-page} {\FOkeepwithnextPage}{auto}

This was inlined. We call \samepage if no page break should occur.

852 \def\jg@keep@together{%
853   \ifx\FOkeeptogether\att@always\samepage\fi
854   \ifx\FOkeeptogetherColumn\att@always\samepage\fi
855   \ifx\FOkeeptogetherPage\att@always\samepage\fi}

This is a bit more complicated: we set a switch that says that we have to keep this item with the next one.

856 \def\jg@keepnext{%
857    \@tempswafalse
858    \ifx\FOkeepwithnext\att@always\@tempswatrue\fi
859    \ifx\FOkeepwithnextColumn\att@always\@tempswatrue\fi
860    \ifx\FOkeepwithnextPage\att@always\@tempswatrue\fi}

In order to understand the following code, you must know that there are four kinds of blocks. If \ifFOinOutput is true, we are typesetting a static area (page headers and footers). If \FOinTable is positive, we are in a table, and a special case is when we typeset the label of an item in a list. Originally, the code did some action if \FOTableNesting was positive; however, it is currently impossible to nest tables, and the counter is never modified.

This inserts some vertical space. We compute in \@tempskipa the quantity to add and in \@tempswa a boolean value that says whether or not a penalty should be inserted. We insert the penalty and the skip. This resets to zero the value of \FOspacebefore. Moreover another quantity is computed but not used, it is not indicated here.

861 \def\FOvspacebefore{%
862   \ifFOinOutput
863   \else
864     \jg@usespacebefore{\@tempskipa}
865     \jg@keepnext
866     \if@tempswa\addpenalty\@secpenalty\fi
867     \addvspace\@tempskipa
868   \fi
869   \def\FOspacebefore{\z@}}

This adds some vertical space after a block. Nothing is done in table headings. Changes in V2: infinite penalty \@M before \vspace was replaced by a finite one, namely 9996, after \vspace.

870 \newskip\FOafterskip
871 \def\FOvspaceafter{%
872   \ifFOinOutput
873   \else
874    \jg@usespaceafter{\FOafterskip}
875    \jg@keepnext
876    \addvspace\FOafterskip
877    \if@tempswa\addpenalty{9996}\fi
878   \fi}

Note : the package redefines \addpenalty, but the old code is the same as the new one, not shown here.

The code above was modified in the following way. Consider the case of a section title, A, followed by a subsection title B, followed by some text C. Both titles forbid a page break, hence \if@tempswa is true in both commands above, this means that we add twice a very high penalty (was infinite in V1). However, when we add a space at the start of B and C, this inserts some penalty (found in\@secpenalty). This is a negative one, hence encourages a page break before B and C, said otherwise, after A and B. The modification consists in remembering in a global variable the value of the second @tempswa (true if keep-with-next.within-page is `always´ for a given block), and to modify the action at the start of a block: we discard the value of @tempswa (that depends on keep-with-next), and instead, if the global variable is true insert a high positive penalty, and otherwise, a negative one. This gives much better page breaks; however, there is little stretchability between blocks, so that the height of the pages varies considerably.

4.10. Quadding

The value of the text-align can be one of the following: `start´, `end´, `center´, `justify´, `insid´e, `outside´, `left´, `right´, or a string. The value of text-align-last can be any of these, plus `relative´. The value `relative´ means that forced lines behave like other ones, except if the text is justified, case where forced lines are left aligned (in TeX, this corresponds to a default \parfillskip). By forced line, we mean either the last in a paragraph, or one induced by evaluation of the character U+000A (this is not implemented in fotex; note however that U+2028 calls \newline). This is a CSS property, adapted to XSL/Format; for this reason `left´ is the same as `start´ and `right´ as `end´. If alignment is `start´, it means that there is no space between the first character and the margin, if it is `end´, then there is no space between the last character and the margin.

We declare the attributes.

879 \XMLNSAX{fo}{text-align}{\FOtextalign}{\inherit}
880 \XMLNSAX{fo}{text-align-last}{\FOtextalignlast}{\inherit}
881 \XMLstringX\att@relative<>relative</>
882 \gdef\FOtextalign{start}
883 \gdef\FOtextalignlast{relative}

The indentation (left and right) is given by two quantities, stored in \FOstartindent and \FOendindent. In the case where we have a list and an item in a list, the start of the body is defined by body-start() and the end of the label by label-end(). In fact, there are two traits, one that indicates the distance between the starts of the label and the body, and one that indicates the distance between the end of the label and the start of the body.

884 \XMLNSA{fo}{start-indent}{\FOstartindent}{\inherit}
885 \XMLNSA{fo}{end-indent}{\FOendindent}{\inherit}
886 \XMLstring\att@labelend<>label-end()</>
887 \XMLstring\att@bodystart<>body-start()</>

We use here two commands that return zero in the case where the attribute value is one of the functions mentioned above, and a third one that set these quantities to zero.

888 \gdef\EndIndent{\ifx\FOendindent\att@labelend\z@\else\FOendindent\fi}
889 \gdef\StartIndent{\ifx\FOstartindent\att@bodystart\z@\else\FOstartindent\fi}
890 \def\jg@hackindent{
891    \ifx\FOstartindent\att@bodystart \let\FOstartindent\z@ \fi
892    \ifx\FOendindent\att@labelend \let\FOendindent\z@ \fi}

We use three commands \QuaddingStart, \Quadding and \QuaddingEnd. The first function is defined as follows. This does not seem to correspond to the explanations given above.

893 \def\QuaddingStart{%
894  \ifx\FOtextalignlast\att@relative
895    \csname startQ@\FOtextalign\endcsname
896  \else
897    \csname startQ@\FOtextalignlast\endcsname
898  \fi}

Function two for quadding.

899 \def\QuaddingEnd{%
900  \ifx\FOtextalignlast\att@relative
901    \csname endQ@\FOtextalign\endcsname
902  \else
903    \csname endQ@\FOtextalignlast\endcsname
904  \fi}

Function three for quadding.

905 \def\Quadding{%
906  \ifx\FOtextalignlast\att@relative
907    \csname Q@\FOtextalign\endcsname
908  \else
909    \csname Q@\FOtextalignlast\endcsname
910  \fi}

Remaining code in this paragraph comes from the file mlnames.sty. These commands describe the action in the case where the text should be centered. Note that line separator character U+2028 is bound to \newline, and needs to be redefined. Why is \Q@centered defined? The code of \Q@center is interesting. Assume that start- and end-indent are a and b respectively. In order to center the text in a region where a has been removed on the left and b on the right, we can put a plus 1fil in \leftskip, b plus 1fil in \rightskip. In fact we subtract a+b from both these quantities (this does not change the alignment). Question: why do we change \@rightskip? In V2, fil was replaced by fill.

911 \def\startQ@center{\hskip\z@ plus 1filll}
912 \def\endQ@center{\hskip\z@ plus 1filll}
913 \def\Q@center{%
914   \let\newline\@centercr
915   \rightskip-\StartIndent plus 1fill%
916   \@rightskip\rightskip
917   \leftskip-\EndIndent plus 1fill%
918   \parfillskip\z@skip
919 }
920 \let\Q@centered\Q@center

This is in the case right-justified, case where alignment is `right´ or `end´. Changes in V2: \rightskip and \@rightskip added.

921 \def\startQ@end{\hfill}
922 \def\endQ@end{}
923 \def\Q@end{
924   \let\newline\@centercr
925   \leftskip\StartIndent plus 1fill % fill
926   \rightskip\EndIndent
927   \@rightskip\rightskip
928   \parfillskip\z@skip
929 }
930 \let\startQ@right\startQ@end
931 \let\endQ@right\endQ@end
932 \let\Q@right\Q@end

This is in the case left-justified, case where alignment is `start´ or `left´.

933 \def\startQ@start{}
934 \def\endQ@start{\hfill}
935 \def\Q@start{
936   \let\newline\@centercr
937   \rightskip\EndIndent plus 1fil
938   \@rightskip\rightskip
939   \leftskip\StartIndent
940   \parfillskip\z@skip
941 }
942 \let\startQ@left\startQ@start
943 \let\endQ@left\endQ@start
944 \let\Q@left\Q@start

This is in the case left and right justified. Why do we need a definition for `justified´?

945 \def\startQ@justify{}
946 \def\endQ@justify{}
947  
948 \def\startQ@justified{%
949   \leftskip\StartIndent
950   \rightskip\EndIndent
951   \@rightskip\rightskip
952 }
953 \def\Q@justified{%
954   \parfillskip\@flushglue
955   \leftskip\StartIndent
956   \rightskip\EndIndent
957   \@rightskip\rightskip
958 }
959 \def\endQ@justified{}
960 \let\Q@justify\Q@justified

Case empty. Strange.

961 \let\startQ@\startQ@justified
962 \let\endQ@\endQ@justified
963 \let\Q@\Q@justified

This is what the documentation says if the value of text-align is `inside´: If the page binding edge is on the start-edge, the alignment will be `start´. If the binding is the end-edge, the alignment will be `end´. If neither, use `start´ alignment. For `outside´, it is the opposite. If I understand correctly, this may depend on the parity of the page, hence cannot be implemented in TeX.

964 \def\startQ@pageoutside{\hfill}
965 \def\endQ@pageoutside{}
966  
967 \def\startQ@pageinside{}
968 \def\endQ@pageinside{\hfill}

4.11. Arrays

Implementing arrays is a bit complicated. It uses a lot of variables. There were also different tentatives, so that some variables and tests have no usage anymore.

We start with a piece of code that remembers the column widths. This declares a counter.

969 \newcount\arraylength

After \Array{foo}[bar]{gee}, the command \foobar contains gee. This is assumed to be the width of column `bar´ of array `foo´.

970 \def\Array#1[#2]#3{%
971   \expandafter\xdef\csname #1#2\endcsname{#3}}

Initialization of the foo array. Column 0 of the array is set to empty. In the original code, this constructed \foo so that \foo[bar] calls \foobar, but the command was never used.

972 \def\DeclareArray#1{%
973    \Array{#1}[0]{}}

This finds the length of an array by considering the first \csname that produces \relax as result (i.e. first undefined slot).

974 \def\getArraylength#1{%
975    \arraylength0
976    \loop\expandafter\ifx\csname #1\the\arraylength\endcsname\relax%
977    \else\advance\arraylength by1\repeat}%

We find the end of the array, then insert something there.

978 \def\addToArray#1#2{\getArraylength{#1}%
979         \Array{#1}[\the\arraylength]{#2}}%

This removes from memory everything associated to this table. Since it is not possible to remove the command from the hash table, we set it to \relax (not undefined!).

980 \def\clearArray#1{\getArraylength{#1}%
981         \loop\ifnum\arraylength >0%
982         \global\expandafter\let\csname #1\the\arraylength\endcsname\relax%
983         \advance\arraylength by-1\repeat}%

These are the variables used below.

984 \newcount\AbsoluteTableCount   % unique Id for a table
985 \newcount\CellCount            % index of a cell in a row
986 \newcount\FOinTable            % >0 if in a table
987 \newcount\NCols                % non-zero if col specs given
988 \newdimen\CurrentCellWidth     % width of current cell
989 \newdimen\TableWidth           % width of the table
990 \newif\ifFOFirstCell           % unused...
991 \def\TableHeader{}             % current table header
992 \newtoks\BoxedFootnotes        % this contains the notes of the table
993 \NCols0
994 \FOinTable0
995 % \newcount\RowCount           % unused
996 % \newtoks\ColSpecs            % unused

We do not want TeX to insert vertical space between rows of our table. There is a command \offinterlineskip designed for this purpose (it is like the code shown here, with \maxdimen instead of 2 14 -1). The command saves some parameters.

997 \def\saveinterlineskip{%
998    \edef\savedbaselineskip{\the\baselineskip}%
999    \edef\savedlineskip{\the\lineskip}%
1000    \edef\savedlineskiplimit{\the\lineskiplimit}%
1001    \baselineskip=-1000pt\relax
1002    \lineskiplimit=16383pt\relax
1003    \lineskip=0pt
1004 }

This restores the settings saved by the previous command.

1005 \def\restoreinterlineskip{%
1006   \baselineskip\savedbaselineskip\relax
1007   \lineskip\savedlineskip\relax
1008   \lineskiplimit\savedlineskiplimit\relax
1009 }

In version two, some quantities are stored in global variables, associated to the array whose number is in \AC (short for \AbsoluteTableCount). This is the function that stores the parameters.

1010 \def\jg@save@parameters{
1011    \addToArray{fotabletextalign\the\AC:}{\FOtextalign}%
1012    \addToArray{fotableborderbeforestyle\the\AC:}{\FOborderbeforestyle}%
1013    \addToArray{fotableborderafterstyle\the\AC:}{\FOborderafterstyle}%
1014    \addToArray{fotableborderstartstyle\the\AC:}{\FOborderstartstyle}%
1015    \addToArray{fotableborderendstyle\the\AC:}{\FOborderendstyle}%
1016    \addToArray{fotableborderbeforewidth\the\AC:}{\FOborderbeforewidth}%
1017    \addToArray{fotableborderafterwidth\the\AC:}{\FOborderafterwidth}%
1018    \addToArray{fotableborderstartwidth\the\AC:}{\FOborderstartwidth}%
1019    \addToArray{fotableborderendwidth\the\AC:}{\FOborderendwidth}%
1020    \addToArray{fotableborderbeforecolor\the\AC:}{\FOborderbeforecolor}%
1021    \addToArray{fotableborderaftercolor\the\AC:}{\FOborderaftercolor}%
1022    \addToArray{fotableborderstartcolor\the\AC:}{\FOborderstartcolor}%
1023    \addToArray{fotableborderendcolor\the\AC:}{\FOborderendcolor}%
1024 }

This is the command that declares the parameters.

1025 \def\jg@declare@parameters{%
1026   \DeclareArray{fotabletextalign\the\AC:}%
1027   \DeclareArray{fotableborderbeforestyle\the\AC:}%
1028   \DeclareArray{fotableborderafterstyle\the\AC:}%
1029   \DeclareArray{fotableborderstartstyle\the\AC:}%
1030   \DeclareArray{fotableborderendstyle\the\AC:}%
1031   \DeclareArray{fotableborderbeforewidth\the\AC:}%
1032   \DeclareArray{fotableborderafterwidth\the\AC:}%
1033   \DeclareArray{fotableborderstartwidth\the\AC:}%
1034   \DeclareArray{fotableborderendwidth\the\AC:}%
1035   \DeclareArray{fotableborderbeforecolor\the\AC:}%
1036   \DeclareArray{fotableborderaftercolor\the\AC:}%
1037   \DeclareArray{fotableborderstartcolor\the\AC:}%
1038   \DeclareArray{fotableborderendcolor\the\AC:}%
1039 }

This is the command that clears the array.

1040 \def\jg@clear@parameters{%
1041    \clearArray{fotabletextalign\the\AC:}%
1042    \clearArray{fotableborderbeforestyle\the\AC:}%
1043    \clearArray{fotableborderafterstyle\the\AC:}%
1044    \clearArray{fotableborderstartstyle\the\AC:}%
1045    \clearArray{fotableborderendstyle\the\AC:}%
1046    \clearArray{fotableborderbeforewidth\the\AC:}%
1047    \clearArray{fotableborderafterwidth\the\AC:}%
1048    \clearArray{fotableborderstartwidth\the\AC:}%
1049    \clearArray{fotableborderendwidth\the\AC:}%
1050    \clearArray{fotableborderbeforecolor\the\AC:}%
1051    \clearArray{fotableborderaftercolor\the\AC:}%
1052    \clearArray{fotableborderstartcolor\the\AC:}%
1053    \clearArray{fotableborderendcolor\the\AC:}%
1054 }

This is the command that gets values from attributes or from quantities stored in the table.

1055 \def\jg@compute@parameters{%
1056   \inheritfromcolumn{text-align}{textalign}%
1057   \inheritfromcolumn{border-before-style}{borderbeforestyle}%
1058   \inheritfromcolumn{border-after-style}{borderafterstyle}%
1059   \inheritfromcolumn{border-start-style}{borderstartstyle}%
1060   \inheritfromcolumn{border-end-style}{borderendstyle}%
1061   \inheritfromcolumn{border-before-width}{borderbeforewidth}%
1062   \inheritfromcolumn{border-after-width}{borderafterwidth}%
1063   \inheritfromcolumn{border-start-width}{borderstartwidth}%
1064   \inheritfromcolumn{border-end-width}{borderendwidth}%
1065   \inheritfromcolumn{border-before-color}{borderbeforecolor}%
1066   \inheritfromcolumn{border-after-color}{borderaftercolor}%
1067   \inheritfromcolumn{border-start-color}{borderstartcolor}%
1068   \inheritfromcolumn{border-end-color}{borderendcolor}%
1069 }

The following command takes two arguments, say `foo´ and `bar´. It looks at the attribute list of the current element, to see if `foo´ is in the list. If so, the command \isexplicit is set to a non-\relax value. Otherwise, we define \FObar to the value found in the table (this is the command that holds the value of the attribute `foo´ in case it is explicitly given).

1070 \def\inheritfromcolumn#1#2{%
1071  \explicitattribute{#1}%
1072  \ifx\isexplicit\relax
1073   \expandafter\edef\csname FO#2\endcsname{%
1074     \csname fotable#2\the\AbsoluteTableCount:\the\CellCount\endcsname}%
1075  \fi
1076 }

This sets the width of the table to be the argument, minus the \tabcolsep, the left margin and the right margin.

1077 \def\jg@settablewidth#1{%
1078    \TableWidth#1%
1079    \advance\TableWidth by -\tabcolsep
1080    \advance\TableWidth by -\FOmarginleft
1081    \advance\TableWidth by -\FOmarginright}

Same code, without the \tabcolsep.

1082 \def\jg@settablewidth@alt#1{%
1083    \TableWidth#1%
1084    \advance\TableWidth by -\FOmarginleft
1085    \advance\TableWidth by -\FOmarginright}

This initializes some other quantities.

1086 \def\jg@tablesetup{%
1087    \NCols0
1088    \gdef\TableHeader{}%
1089    \NoTableSetup}

New in V2. If footnotes appear in a table, they are stored in a token list and inserted later on. This inserts the list, kills it, and resets the command that typesets footnotes.

1090 \def\NoTableFinish{
1091   \ifnum\FOinTable=0
1092     \the\BoxedFootnotes
1093     \global\BoxedFootnotes={}%
1094     \global\let\FOfoottext\FOplainfoottext
1095   \fi
1096 }

This is the command used at the start of a table. In this case and the previous one, if a table is in another one, the action is executed only for the outer table.

1097 \def\j@start@tablenotes{
1098   \ifnum\FOinTable=0
1099     \global\BoxedFootnotes{}%
1100     \global\let\FOfoottext\FOboxedfoottext
1101   \fi
1102 }

This piece of code is executed at the start of a table or tabular. In the case of a tabular in a table, it will be executed twice. We commented out the code that increments the table counter: this is because it is currently impossible to put tables in tables; and once a table is typeset, all information about it is discarded. However, some names remain in the hash table.

1103 \def\NoTableSetup{%
1104   \ifx\FOwidth\att@auto\else     %% this test added by JG
1105     \jg@settablewidth{\FOwidth}%
1106  \fi
1107   % \global\advance\AbsoluteTableCount by 1 %
1108   \DeclareArray{fotable\the\AbsoluteTableCount:}%
1109   \jg@declare@parameters
1110   \global\CellCount0
1111   \jg@start@tablenotes
1112  }

We declare here an attribute for the placement of tables. This is in the fotex namespace. We declare also the reference orientation. This can be used in an inline container, for turning things.

1113 \XMLNSAX{fo}{fotex:placement}{\FOkplacement}{}
1114 \XMLNSAX{fo}{reference-orientation}{\FOreferenceorientation}{0}
1115 \XMLname{fo:inline-container}{\FOInlineContainer}
1116 \gdef\FOkplacement{}

A table is defined by the <fo:table-and-caption> element, has <fo:table-caption> (optional) and <fo:table> (required) as children.

In the case of <fo:table-and-caption>, we use a floating environment. This can be a table or a sideways table. We must close the same environment at the end.

1117 \XMLelement{fo:table-and-caption}
1118   {}
1119   {
1120    \jg@settablewidth{\linewidth}
1121    \jg@tablesetup
1122     \ifx\XML@parent\FOInlineContainer
1123       \ifnum\FOreferenceorientation=0
1124       \else \begin{sidewaystable}\fi
1125     \else
1126      \ifnum\FOreferenceorientation=0
1127        \ifx\FOkplacement\@empty
1128         \begin{table}[!htbp]\FOlabel
1129          \else \edef\ktable{\noexpand\begin{table}[\FOkplacement]} \ktable \fi
1130       \else \begin{sidewaystable}\fi
1131     \fi
1132     \FOlabel
1133   }
1134   {\ifx\XML@parent\FOInlineContainer
1135      \ifnum\FOreferenceorientation=0  \else \end{sidewaystable}  \fi
1136    \else
1137      \ifnum\FOreferenceorientation=0 \end{table} \else \end{sidewaystable} \fi
1138    \fi
1139    \NoTableFinish
1140   }

Typesetting the caption is trivial. In particular, we do not call \caption. The table has a caption-side trait that explains where to put the caption. This will be ignored.

1141 \XMLelement{fo:table-caption}
1142   {}
1143   {}
1144   {\par}

A <fo:table> can be used inside or outside of a <fo:table-and-caption>. The content: some <fo:table-column> elements, an optional <fo:table-header>, an optional <fo:table-footer> and some <fo:table-body> elements. Translation is trivial.

This is what we do for a table (equivalent of a LaTeX tabular). It has no header. Changes in V2: the whole table is put in a vbox, that starts with a top border and finishes with a bottom border.

1145 \XMLelement{fo:table}
1146   {}
1147   {
1148    \FOexpandattributes
1149    \jg@settablewidth@alt{\linewidth}
1150    \jg@tablesetup
1151    \vbox\bgroup\FOBorderTop
1152   }
1153   {\FOBorderBottom\egroup
1154    \NoTableFinish}

The header of a table is not typeset now, but later. The footer is currently ignored. Too bad. The global definition here is one that forbids putting tables in tables.

1155 \XMLelement{fo:table-header}
1156   {}
1157   {\xmlgrab}
1158   {\gdef\TableHeader{#1}}

This command is used to specify the width and other properties of one or more columns. The doc says: The number-columns-repeated property specifies the repetition of a <fo:table-column> specification n times; with the same effect as if the <fo:table-column> formatting object had been repeated n times in the result tree. The column-number property, for all but the first, is the column-number of the previous one plus the value of the number-columns-spanned property.

Changes in V2: attribute text-align added, but why? Some attributes are saved by the routines explained above. The list of these is larger than the list of attributes defined by the standard.

1159 \XMLelement{fo:table-column}
1160  {
1161    \XMLattributeX{text-align}{\FOtextalign}{\inherit}
1162  }
1163  {
1164   \@tempcnta0
1165   \loop\ifnum\FOnumbercolumnsrepeated>\@tempcnta
1166    \advance\@tempcnta by 1
1167    {\NoTableColumn}%
1168   \repeat
1169   }
1170  {}

There is something wrong in this procedure: the column number is unused (said otherwise, if specifications are not in the order 1, 2, 3, etc, they will be stored in random order). Note: the column-number should not be zero. If at least one table column has been given, then \Ncols is not zero. The test to proportional-column-width is strange: what if the argument is not one? If the value is a percentage, it refers to the width of the table. The computed value is stored in \@tempdima, and then in the array data structure.

1171 \def\NoTableColumn{%
1172    \ifx\@empty\FOcolumnnumber
1173     \global\advance\NCols by 1
1174    \else
1175     \global\NCols\FOcolumnnumber
1176    \fi
1177    \ifx\prop@width\FOcolumnwidth\def\FOcolumnwidth{1in}\fi
1178    \ifx\@empty\FOcolumnwidth\def\FOcolumnwidth{1in}\fi
1179    \TablePercentToDimen{\FOcolumnwidth}%
1180    \addToArray{fotable\the\AbsoluteTableCount:}{\the\@tempdima}%
1181    \jg@save@parameters
1182 }
1183 \XMLstringX\prop@width<>proportional-column-width(1)</>

The table body, header and footer contain either rows, or cells. Footers are currently ignored. Inside a table \FOinTable is 1. Since V2, the interlineskip parameters are saved and set to zero. Each row of the table is a box (a hbox in a vbox), and we do not want additional vertical space between the rows.

1184 \XMLelement{fo:table-body}
1185   {  }
1186   { \FOFirstCelltrue
1187     \FOinTable1
1188     \saveinterlineskip
1189     \expandafter\NoTableStart{\TableHeader}%
1190   }
1191   { \NoTableEnd }

Action is trivial.

1192 \def\NoTableStart#1{#1}
1193 \def\NoTableEnd{%
1194    \clearArray{fotable\the\AbsoluteTableCount:}%
1195    \jg@clear@parameters
1196 }

We use a command for typesetting a row.

1197 \XMLelement{fo:table-row}
1198   {}
1199   {\xmlgrab}
1200   {\NoTableRow{#1}}

We use two passes for our table rows. For the first pass the height of the row may be unknown; hence we use a boolean that says that it is the first or the second pass.

1201 \newdimen\NoTableCellHeight
1202 \newif\ifNoTableCheckHeight

This is for the first pass. We use a \strut, a capital letter and a letter with a descender. Note: it is two small if the cell has a border or padding. Changes in V2. If a height attribute is given, it will be used instead this string for computation of the strut.

1203 \def\jg@default@cell@height{%
1204  \setbox0=\vbox{
1205   \ifx\FOheight\att@auto%
1206     \strut They
1207   \else
1208     \rule{\z@}{\FOheight}%
1209   \fi
1210   }%
1211  \NoTableCellHeight=\ht0
1212  \advance\NoTableCellHeight by \dp0
1213  \NoTableCheckHeightfalse}

In the first pass, we put the row in a box, and we compute the total height plus depth of the box. Changes in V2: a hbox in a vbox is used instead of a simple hbox. Footnotes are ignored (in the second pass they will move). Then we look at page parameters to see if there is enough place on the current page; we may call \clearpage.

1214 \def\jg@tablerow@firstpass#1{%
1215  \setbox0=\vbox{\hbox{\let\FOfoottext\FOnofoottext#1}}%
1216  \@tempdima=\ht0
1217  \advance\@tempdima by \dp0
1218  \FOspaceleft=\pagegoal
1219  \advance\FOspaceleft by -\pagetotal
1220  \ifdim\FOspaceleft<\@tempdima \clearpage \fi}

Second pass: we use the actual height as target height. In V1, we could use the box if not too big; but in V2, we have to process the table again, because otherwise we could lose footnotes.

1221 \def\jg@tablerow@secondpass#1{
1222  \ifdim\@tempdima>\NoTableCellHeight
1223    \NoTableCellHeight=\@tempdima
1224  \fi
1225  \global\CellCount0
1226  \NoTableCheckHeighttrue
1227  \vbox to \NoTableCellHeight {\hbox{#1}}}

The code looks like this. In V1, we inserted the opposite of \lineskip; this assumes that TeX places a glue of value \lineskip, because the height of the box is greater than the baselineskip limit. It can fail if the height is small. In V2, we inhibit insertion of this glue, hence the code is not needed anymore.

1228 \def\NoTableRow#1{%
1229  \jg@default@cell@height
1230  \global\CellCount0 \jg@tablerow@firstpass{#1}%
1231  \jg@tablerow@secondpass{#1}%
1232  %\vskip-\lineskip
1233 }

In the case of a table cell, we call some functions. A table body can consist of rows, or cells. In the case of cells, we have an attribute that says if the cell starts or ends a row. We set \FOinTable to 2, meaning “in cell”.

1234 \XMLelement{fo:table-cell}
1235   {
1236    \XMLattributeX{ends-row}{\FOendsrow}{false}
1237    \XMLattributeX{starts-row}{\FOstartsrow}{false}
1238   }
1239   {\xmlgrab}
1240   {\FOlabel
1241   \FOexpandattributes
1242   \FOinTable2
1243   \NoTableCell{#1}}

This reduces the argument by the width of the padding, margin and border width on both sizes. Thus, we have in #1, a dimension register, the width of the region in which we can typeset the cell.

1244 \def\jg@removemarg#1{
1245    \advance#1 by -\FOpaddingstart
1246    \advance#1 by -\FOpaddingend
1247    \ifx\FOborderstartstyle\att@solid\advance#1 by -\FOborderstartwidth\fi
1248    \ifx\FOborderendstyle\att@solid\advance#1 by -\FOborderendwidth\fi
1249    \advance#1 by -\FOmarginright
1250    \advance#1 by -\FOmarginleft}

We increment the cell count, or reset it, in case there is an attribute that says this cell is the first in a row.

1251 \def\jg@test@startrow{%
1252  \ifx\FOstartsrow\att@true
1253 %    \vskip-\lineskip  % not needed in V2
1254     \global\CellCount1
1255  \else
1256     \global\advance\CellCount by 1
1257  \fi}

If this cell is the last in a row, set the counter to zero.

1258 \def\jg@test@endrow{%
1259  \ifx\FOendsrow\att@true
1260     %\vskip-\lineskip   % not needed in V2
1261     \global\CellCount0
1262  \fi}

Write \CCWidth instead of \CurrentCellWidth for simplicity. This is the width of the cell. If \NCols is zero, no specifications are given for the table. In this case, we use the natural width of the cell. Otherwise we use the stored value. We must reset the interline skip to its normal value.

1263 \def\jg@getCCwidth#1{
1264  \ifnum\NCols<1
1265   \CCWidth\z@
1266   \setbox0=\hbox{\restoreinterlineskip#1\strut}%
1267   \CCWidth=\wd0
1268  \else
1269   \CCWidth=\csname fotable\the\AbsoluteTableCount:\the\CellCount\endcsname
1270   \jg@compute@parameters
1271   \interpretwidth
1272  \fi}

If the cell spans more than one column, we assume that specifications are given for all columns. We compute the sum of these quantities.

1273 \def\jg@getCCwidth@aux{%
1274  \ifnum\FOnumbercolumnsspanned>1
1275     \@tempcnta1
1276     \loop\ifnum\@tempcnta<\FOnumbercolumnsspanned
1277         \advance\@tempcnta by 1
1278         \global\advance\CellCount by 1
1279         \advance\CCWidth\csname fotable\the
1280            \AbsoluteTableCount:\the\CellCount\endcsname
1281     \repeat
1282  \fi}

This is now the code of a cell. The parent is a table row or a table. If we are in a row, all cells are typeset (see next section) and the resulting boxes are put in a row-box, these row-boxes are put one above the other. These cells align nicely, because a cell in row i column j has a common height H i and a width W j (these value depends only on i and j and not the cell, the height is in \NoTableCellHeight and used only for the second pass, the width is in \CCwidth, real name of command shown above). In the case where the cell is directly in a table, the cell is put in a hbox, and \leavevmode is called. The attributes telling this is the first or last cell in a row have as only purpose to change the cell count. As a consequence, all cells are on a single line(note: ).

1283 \def\NoTableCell#1{%
1284  \jg@test@startrow
1285  \jg@getCCwidth{#1}%
1286  \jg@removemarg{\CCWidth}
1287  \jg@getCCwidth@aux
1288  \ifx\XML@parent\FOTableRow
1289    \FOTableCellBlock#1\FOEndTableCellBlock
1290  \else
1291    \leavevmode\hbox{\FOTableCellBlock#1\FOEndTableCellBlock}%
1292  \fi
1293  \jg@test@endrow}

Some declarations.

1294 \XMLNSA{fo}{column-width}{\FOcolumnwidth}{}
1295 \XMLNSAX{fo}{number-columns-repeated}{\FOnumbercolumnsrepeated}{1}
1296 \XMLNSAX{fo}{number-columns-spanned}{\FOnumbercolumnsspanned}{1}
1297 \XMLNSAX{fo}{column-number}{\FOcolumnnumber}{}

4.12. Boxed blocks

We typeset a cell by opening in a lrbox (this is really a \hbox) in which we open a \vbox. Since V2, a color group is added only if the \ifFOinOutput switch is false.(note: ) We hack spacing. We removed a test to an undefined variable, that could center vertically the box.

1298 \def\FOTableCellBlock{%
1299  \begin{lrbox}{\CellBox}%
1300  \vbox\bgroup
1301  \hsize\the\CurrentCellWidth
1302  \restoreinterlineskip
1303  \ifFOinOutput\else \color@begingroup\fi
1304  \FOSetFont{tablecellblock}%
1305  \jg@activew}

This is a bit longish, but easy to understand. We finish our \vbox and our lrbox. After that, we construct some boxes. Let´s denote by PA, PB, PS, and PE the padding before, after (vertical), start, end (horizontal), by BA, BB, BS, and BE the border width (whenever the border is solid), and by ML, MR, MT, and MB the margins (left, right, top, bottom). Let a be the sum of MT, PB and BB, and let b be the sum of PS, PE and the width of the cell box. The first box we construct is A, the cell box. The second box we construct is B, an hbox containing PS, A and PE. The third box is C, a vbox containing PB, filler, B, filler, and PA. The filler is a \vfil, which is inserted in certain circumstances : if NoTableCheckHeight is true, we insert the filler if some attributes have the right value. In this case C is a \vtop to the height of the table computed earlier (this is the height of the row, we are in the second pass). The width of this box is the quantity b defined above. Now we construct a box D, an hbox with BS, bg, C, and BE, where bg may be empty if no background is desired. Otherwise it consists of a rule of width b, followed by a kern of width minus b (the height of the rule is the height of C). Then comes a box E, this is a vbox containing BB, D and BA. Note that BS, BE, BB, and BA are borders: they are implemented via hrules or vrules. Then comes a box F, it is a vbox containing MT, E and MB, and a box G, this is an hbox that contains ML, F and MR. This box is shifted down by the quantity a. Finally, we put everything in an hbox.

Changes in V2: Horizontal margins use \hskip, but vertical margins use \kern instead of \vskip. In the case of BoxedBlock, \kerns are used for both horizontal and vertical margins.

1306 \def\FOEndTableCellBlock{%
1307  \ifx\FOverticalalign\att@top\vfill\fi
1308  \ifFOinOutput\else \color@endgroup\fi
1309  \egroup
1310  \end{lrbox}%
1311  \@tempdima\FOmargintop
1312  \advance\@tempdima\FOpaddingbefore
1313  \ifx\FOborderbeforestyle\att@solid\advance\@tempdima\FOborderbeforewidth\fi
1314 \@tempdimb\wd\CellBox
1315 \advance\@tempdimb by \FOpaddingstart
1316 \advance\@tempdimb by \FOpaddingend
1317 \hbox{%
1318     \lower\@tempdima
1319      \hbox{%
1320       \hskip\FOmarginleft
1321       \vbox{%
1322         \kern\FOmargintop
1323         \vbox{%
1324         \ifx\FOborderbeforestyle\att@solid
1325            {\color{\FOborderbeforecolor}\hrule\@height\FOborderbeforewidth}%
1326         \fi
1327         \hbox{%
1328           \ifx\FOborderstartstyle\att@solid
1329             {\color{\FOborderstartcolor}\vrule\@width\FOborderstartwidth}%
1330           \fi
1331           \ifx\FObackgroundcolor\att@transparent
1332           \else
1333            {\color{\FObackgroundcolor}\vrule\@width\@tempdimb\kern-\@tempdimb}%
1334           \fi
1335            \ifNoTableCheckHeight
1336              \vtop to \NoTableCellHeight{%
1337                \kern\FOpaddingbefore
1338                \ifx\FOdisplayalign\att@auto
1339                  \else\ifx\FOdisplayalign\att@before
1340                    \else\ifx\FOdisplayalign\att@after\vfil
1341                      \else\ifx\FOdisplayalign\att@centered\vfil\fi
1342                    \fi
1343                  \fi
1344                \fi
1345                \hbox{\kern\FOpaddingstart\box\CellBox\kern\FOpaddingend}%
1346                \ifx\FOdisplayalign\att@auto\vfil
1347                  \else\ifx\FOdisplayalign\att@before\vfil
1348                    \else\ifx\FOdisplayalign\att@after
1349                      \else\ifx\FOdisplayalign\att@centered\vfil\fi
1350                    \fi
1351                  \fi
1352                \fi
1353                \kern\FOpaddingafter
1354              }%
1355            \else
1356             \vbox{%
1357               \kern\FOpaddingbefore
1358                 \hbox{\kern\FOpaddingstart\box\CellBox\kern\FOpaddingend}%
1359               \kern\FOpaddingafter
1360               }%
1361            \fi
1362           \ifx\FOborderendstyle\att@solid
1363            {\color{\FOborderendcolor}\vrule\@width\FOborderendwidth}%
1364           \fi
1365         }%
1366         \ifx\FOborderafterstyle\att@solid
1367            {\color{\FOborderaftercolor}\hrule\@height\FOborderafterwidth}\fi
1368         }%
1369         \kern\FOmarginbottom
1370      }%
1371      \hskip\FOmarginright
1372     }%
1373    }%
1374 }

This is done when we start a boxed object. This is like the start of a cell, but a bit simpler. Note the \Quadding and the \strut.(note: )

1375 \def\FOBoxedBlock#1{%
1376  \@tempdimb#1%
1377  \jg@removemarg{\@tempdimb}
1378  \begin{lrbox}{\BlockBox}%
1379  \vbox\bgroup
1380  \hsize\the\@tempdimb
1381  \FOSetFont{tableblock}%
1382  \color@begingroup
1383  \jg@activew
1384  \parindent\FOtextindent
1385  \Quadding
1386  \start@strut }

This is like the end of a cell box. It is a bit simpler. Dimensions a and b are renamed to b and c. We construct a box, as follows: A is the box that contains the material seen so far, B contains PS, A and PE, C contains PB, B and PA, D contains BS, bg, C, and BE, E contains BD, D and BA, F contains MT, E and MB, finally G contains Ml, F and MR. The difference with a cell: no vertical skip, and Ml is margin-left plus text-indent(note: ).

1387 \def\FOEndBoxedBlock{%
1388  \start@strut
1389  \color@endgroup
1390  \egroup
1391  \end{lrbox}%
1392  \@tempdimb\FOmargintop
1393  \advance\@tempdimb\FOpaddingbefore
1394  \ifx\FOborderbeforestyle\att@solid\advance\@tempdimb\FOborderbeforewidth\fi
1395  \@tempdimc\wd\BlockBox
1396 \advance\@tempdimc by \FOpaddingstart
1397 \advance\@tempdimc by \FOpaddingend
1398 \FOtempdim\FOmarginleft
1399 \advance\FOtempdim by \FOtextindent
1400 \hbox{%
1401     \lower\@tempdimb
1402      \hbox{%
1403       \kern\FOtempdim
1404       \vbox{%
1405         \kern\FOmargintop
1406         \vbox{%
1407         \ifx\FOborderbeforestyle\att@solid
1408            {\color{\FOborderbeforecolor}\hrule\@height\FOborderbeforewidth}%
1409         \fi
1410         \hbox{%
1411           \ifx\FOborderstartstyle\att@solid
1412             {\color{\FOborderstartcolor}\vrule\@width\FOborderstartwidth}\fi
1413           \ifx\FObackgroundcolor\att@transparent
1414           \else
1415            {\color{\FObackgroundcolor}\vrule\@width\@tempdimc\kern-\@tempdimc}%
1416           \fi
1417             \vbox{%
1418               \kern\FOpaddingbefore
1419                \hbox{\kern\FOpaddingstart\box\BlockBox\kern\FOpaddingend}%
1420               \kern\FOpaddingafter
1421               }%
1422           \ifx\FOborderendstyle\att@solid
1423            {\color{\FOborderendcolor}\vrule\@width\FOborderendwidth}\fi
1424         }%
1425         \ifx\FOborderafterstyle\att@solid
1426            {\color{\FOborderaftercolor}\hrule\@height\FOborderafterwidth}\fi
1427         }%
1428         \kern\FOmarginbottom
1429      }%
1430      \kern\FOmarginright
1431     }%
1432    }%
1433 }

Attributes.

1434 \XMLNSAX{fo}{display-align}{\FOdisplayalign}{\inherit}
1435 \XMLstringX\att@top<>top</>
1436 \gdef\FOdisplayalign{auto}
1437 \XMLstringX\att@after<>after</>
1438 \XMLstringX\att@before<>before</>

4.13. Lists

In XSL/Format four formatting objects construct lists: the main element is <fo:list-block>, the children are one or more <fo:list-item>, each containing a pair of <fo:list-item-label> and <fo:list-item-body>. There are two attributes, specific to lists. We shall abbreviate the names to PLS and PDBS.

1439 \XMLNSAX{fo}{provisional-label-separation}
1440    {\FOprovisionallabelseparation}{\inherit}
1441 \XMLNSAX{fo}{provisional-distance-between-starts}
1442    {\FOprovisionaldistancebetweenstarts}{\inherit}

This command is used twice: at the start of a list, and at the start of a block in a list. It defines some parameters (item indent, left margin, right margin, and label width) that are used by the \item command. Changes in V2: PDBS can be a percentage.

1443 \def\jg@use@listparams{
1444   \itemindent=\FOstartindent
1445   \PercentToDimen{\FOprovisionaldistancebetweenstarts}%
1446   \leftmargin=\@tempdima\relax
1447   \rightmargin=\FOmarginright
1448   \labelwidth=\@tempdima\relax
1449   \advance\labelwidth by -\FOprovisionallabelseparation}

The translation of <fo:list-block> is essentially a call to the list environment (it takes two arguments, explained below). We globally change (increase by one) the \FOinList counter. The text-align attribute will be used for alignment of the labels, for instance, if it is `start´, we call the command \Liststart, that defines \makelabel adequately (it will left justify the label). We use \csname for this purpose; the \expandafter before it is useless.

Changes in V2: Call to \FOSetFont commented out. Setting of \partopsep added. Conditional call to \leavevmode and final \par commented out. As a consequence a list could be inline. This means that some checks have to be made elsewhere.

There is a second change in V2, it concerns \linewidth. The question is: how should this be defined? what command uses it? In general, the value is the same as \hsize. It is used and modified by \list (as shown below), and used by tables (in a non-trivial manner by \@stopline, but this is not used by fotex). However, we have already seen that the fotex implementation of tables uses this value, and we have seen another use of the variable. Now comes the trick. Let X be the command \This@LineWidth, and Y its value, let H be the value of \hsize. The command \setaccordingtomaster is called for each page, and for each flow; it calls \FOResetPageParts that redefines \hsize. It also redefines \linewidth to Y, if X is defined, and to H otherwise. The question is whether or not the value should be modified (whenever a new flow is created, it is clear that we should set it to H, when a new page is entered, the value should not change). Given this scheme, the variable X, whenever it has a value, should contain the right quantity. The code here defines two scopes: the <fo:list-block> element and the list environment, let´s call them A and B. The first definition is in scope A, and the purpose is to restore the value of the line width (it will be globally modified). The second definition is in scope B, it is used only in the case where a page break occurs while typesetting the list.

1450 \XMLelement{fo:list-block}
1451   {\SpaceAttributes}
1452   {
1453    \jg@hackindent
1454    %\FOSetFont{normal}%
1455    \advance\FOinList by 1\relax
1456    %\ifnum\FOinList>1\relax\leavevmode\fi
1457    \edef\This@LineWidth{\the\linewidth}%
1458    \begin{list}{}{%
1459      \jg@use@listparams
1460      \advance\leftmargin by \FOmarginleft
1461      \expandafter\csname List\FOtextalign\endcsname
1462      \labelsep\FOprovisionallabelseparation
1463      \itemsep\z@ \parsep\z@ \partopsep\z@ \topsep\z@  \parskip\z@
1464      \jg@usespacebefore{\topsep} }
1465      %\edef\This@LineWidth{\the\linewidth}% comment JG
1466    }
1467   {\end{list}
1468    \global\linewidth\This@LineWidth\relax
1469    \advance\FOinList by -1\relax
1470    %\par
1471   }

These are the definitions used in the code above. The default value (reset by \list in any case) corresponds to `end´.

1472 \def\Listjustified{  \gdef\makelabel##1{##1}}
1473 \def\Liststart{      \gdef\makelabel##1{##1\hfil}}
1474 \def\Listend{        \gdef\makelabel##1{\hfil##1}}
1475 \def\Listcentered{   \gdef\makelabel##1{\hfil##1\hfil}}
1476 \def\Listcenter{     \gdef\makelabel##1{\hfil##1\hfil}}

The command \list has been changed in V2, as explained above. It takes two arguments. The first defines \@itemlabel, the value to be used when \item has no optional argument (unused here), and the second contains a list of commands to be executed before the call to \@trivlist. The standard \list command increments \@listdepth and tests it for overflow; this is useless in our case, especially because the effects of command that depends on the list level (for instance \@listii) are neutralized via the second argument. In effect we define \itemsep, \parsep, \partopsep, \listparindent, and \parskip to be zero, \topsep to be the value of the space-before attribute, \itemindent to be the value of start-indent. After that, the left and right margin will take the value of the corresponding attribute, but the left margin is increased by the value of PDBS, \labelwidth will contain PDBS minus PLS and \labelsep will contain PLS. After \@trivlist, we copy two zero quantities in \parskip and \parindent. We subtract left and right margin from \linewidth. Note: this is done globally in V2, and the caller restores the old value (this is a bit strange). Finally, we call \parshape, so that the first line (holding the item) is typeset differently.

1477 \def\list#1#2{%
1478   \ifnum \@listdepth >5\relax \@toodeep
1479   \else \global\advance\@listdepth\@ne
1480   \fi
1481   \rightmargin\z@
1482   \listparindent\z@
1483   \itemindent\z@
1484   \csname @list\romannumeral\the\@listdepth\endcsname
1485   \def\@itemlabel{#1}%
1486   \let\makelabel\@mklab
1487   \@nmbrlistfalse
1488   #2\relax
1489   \@trivlist
1490   \parskip\parsep
1491   \parindent\listparindent
1492   \global\advance\linewidth -\rightmargin        % V2
1493   \global\advance\linewidth -\leftmargin         % V2
1494   \advance\@totalleftmargin \leftmargin
1495   \parshape \@ne \@totalleftmargin \linewidth
1496   \ignorespaces}

The \endlist command calls \endtrivlist (shown below) and decrements the list depth counter. For completeness, we show here the code of \@trivlist. The command on the first line is “a switch set true by a sectioning command when it is creating an in-text heading with \everypar” according to Lamport. In such a case, the heading is kept in a variable, and output only when a new paragraph is started, hence the \leavevmode. Then comes a piece of code shown below, and settings of three skip parameters (for justification). We copy \parskip somewhere, set a boolean to true and start checking for missing items.

1497 \def\@trivlist{%
1498   \if@noskipsec \leavevmode \fi
1499   \jg@trivlist@A
1500   \leftskip \z@skip
1501   \rightskip \@rightskip
1502   \parfillskip \@flushglue
1503   \jg@trivlist@B
1504   \global \@newlisttrue
1505   \@outerparskip \parskip}

Four boolean variables control how lists are typeset. We have already seen @newlist. This is true as long as the list is new. Said otherwise, it is set to true at the start of the list, and set to false at the start of the first paragraph (\everypar in an item). This redefines \par, to be \@@par (the primitive command) if the list is not new, and otherwise to do nothing (however, after a thousand calls an error will be signaled). As a consequence, if there is some text before the first item, even if there are \par commands, the current mode will be horizontal.

1506 \def\jg@trivlist@B{%
1507  \par@deathcycles \z@
1508  \@setpar{%
1509    \if@newlist
1510      \advance\par@deathcycles \@ne
1511      \ifnum \par@deathcycles >\@m \@noitemerr {\@@par}\fi
1512    \else {\@@par} \fi}}%

The second switch, @inlabel, “is false except between the time an \item is encountered and the time that TeX actually enters horizontal mode”, the quote is from Lamport. At the end of a list, or inside \newpage, if the switch is true, \leavevmode is executed, and the switch reset to false; this has as effect to flush pending labels. Otherwise, the switch is set to true in \jg@itemA shown below, and to false by \jg@itemB. There is third switch, @noparitem, it is set by \list to true if @inlabel is true. This is the case when the user says, for instance \item[foo] \begin{itemize}\item[bar]. In this case, we have two items in a row. Finally @noparlist is set at the start of a list as a copy of @inlabel.

Two dimensions are defined. The first is \@topsepadd, containing \topsep plus \partopsep (omitted in horizontal mode); this is copied in \@topsep, unless we are in a label (case where \@topsep is left unchanged). If \noparlist is false, the command \@endparenv is called at the end of the list, and inserts the \@topsepadd vertical glue. Denote this by T´, denote by P the value of \parskip, and let T be the sum of these two quantities; we put T in \@topsep; it will be inserted by \@item.

1513 \def\jg@trivlist@A{%
1514   \@topsepadd \topsep
1515   \ifvmode \advance\@topsepadd \partopsep \else \unskip \par \fi
1516   \if@inlabel \@noparitemtrue \@noparlisttrue
1517   \else
1518     \if@newlist \@noitemerr \fi
1519     \@noparlistfalse
1520     \@topsep \@topsepadd
1521   \fi
1522   \advance\@topsep \parskip}

Second part of \endtrivlist. This is used when \noparlist is false, said otherwise, if the list was not inside a label. Let L, P and O be the values of the last skip, the parskip, and \@outerparskip (the parskip that was in effect before the list). If the last item in the vertical list is glue, then L contains this value, otherwise it will be zero. If L is negative or zero, nothing is done; otherwise, the opposite of L is added, followed by L+P-O. This gives three items of glue; there are similar cases where a penalty is inserted after the second glue.

1523 \def\jg@endtrivlist@B{%
1524     \ifdim\lastskip >\z@
1525       \@tempskipa\lastskip \vskip -\lastskip
1526       \advance\@tempskipa\parskip \advance\@tempskipa -\@outerparskip
1527       \vskip\@tempskipa
1528     \fi}

The code that follows handles the special case of a list A, containing an item B, that starts with a list C; in this case the @noparitem switch is true. When we see the first item D in the list C, we call this piece of code (the source has a comment: “this clause hardly every taken, so made a macro”). The action is divided into three parts: first, we set the switch to false, second, we shift the labels left by the value of \leftmargin (note that this is how much the current list is indented with respect to its environment), finally, we adjust vertical space. We add two items of glue. With the the same notations as before, we insert are -L and L+O-P. When the label is finally printed, TeX will use the current \parskip, hence P. This gives a total of L+O: the old glue plus the old \parskip. Note that the code above inserts L+P-O.

1529 \def\@donoparitem{%
1530   \@noparitemfalse
1531   \global\setbox\@labels\hbox{\hskip -\leftmargin
1532                                \unhbox\@labels
1533                                 \hskip \leftmargin}%
1534   \if@minipage\else
1535     \@tempskipa\lastskip
1536     \vskip -\lastskip
1537     \advance\@tempskipa\@outerparskip
1538     \advance\@tempskipa -\parskip
1539     \vskip\@tempskipa
1540   \fi}

First part of \endtrivlist. If we are still in the label, we enter horizontal mode, and say that we are no more in the label. An error is signaled if the list is new (case where no item was found).

1541 \def\jg@endtrivlist@A{%
1542   \if@inlabel
1543     \leavevmode
1544     \global \@inlabelfalse
1545   \fi
1546   \if@newlist
1547     \@noitemerr
1548     \global \@newlistfalse
1549   \fi}

This is now \endtrivlist, as defined by V2. The test \ifInInsertion was added. An error test (if the end of the list occurs in math mode) was removed for no clear reason.

1550 \def\endtrivlist{%
1551   \jg@endtrivlist@A
1552   \ifhmode\unskip \par\fi %% else error omitted
1553   \if@noparlist \else\ifInInsertion\else
1554     \jg@endtrivlist@B\fi
1555     \@endparenv
1556   \fi}

Quoted from the LaTeX source: “When you leave a list environment, returning either to an enclosing list or normal text mode, LaTeX begins a new paragraph if and only if you leave a blank line after the \end command. This is accomplished by the \@endparenv command. Blank lines are ignored every other reasonable place”. Later on, there is “Instead of redefining \par and \everypar, \@endparenv was changed to set the @endpe switch, letting \end redefine \par and \everypar”. The fotex V2 file redefines the command by adding a test to \ifInInsertion (true in a footnote).

1557 \def\@endparenv{%
1558   \ifInInsertion\else
1559     \addpenalty\@endparpenalty
1560     \addvspace\@topsepadd
1561     \@endpetrue
1562   \fi}

The \fotex file redefines \item like this. Note that \leavevmode could be used to flush pending labels.

1563 \let\olditem\item
1564 \def\item{\if@inlabel\leavevmode\fi\olditem}

We now redefine the \item command. This is a bit complicated. For this reason, we split the command into smaller pieces.

1565 \def\@item[#1]{%
1566   \@itemA
1567   \@itemB
1568   \@itemC
1569   \@itemD{#1}%
1570   \@itemE
1571   \ignorespaces}

The first idea is that the label is typeset in a box, and this box will be used later. The \sbox command produces essentially a hbox. The LaTeX source file says that the \label command should produce some glue, for instance, the code on lines 1473 to 1476 is OK, the code on line 1472 is not. The first line was added because it corrects a bug. See explanations later.

1572 \def\@itemD#1{%
1573   %\savebox{\ItemBox}{#1}% Added Grimm
1574   \sbox\@tempboxa{\makelabel{#1}}}%

We can have more than one consecutive labels. For this reason, we put in the box \@labels all these labels. We consider three dimensions, say A, B, and C, that contain the space after the label, the nominal width of the label, and the total space allowed for the label and its surrounding space. We emit four items of glue, first, three items that correspond to C-A-B, then the label box, then A. In the case where the width of the label is smaller than B, we use \hbox to XX, with a \unhbox: here it is important that the box contains glue that can stretch without producing underful boxes.

1575 \def\@itemE{%
1576   \global\setbox\@labels\hbox{%
1577     \unhbox\@labels
1578     \hskip \itemindent
1579     \hskip -\labelwidth
1580     \hskip -\labelsep
1581     \ifdim \wd\@tempboxa >\labelwidth
1582       \box\@tempboxa
1583     \else
1584       \hbox to\labelwidth {\unhbox\@tempboxa}%
1585     \fi
1586     \hskip \labelsep}}%

In the case of an enumeration, there is a counter, whose name is in \@listctr, that has to be incremented. We know that we are in an enumeration, because \if@nmbrlist is true (in the FO case, it is false). In the case \item has an optional argument, \if@noitemarg is false, and in this case the user gives a number, so that the counter is not modified.

1587 \def\@itemC{%
1588   \if@noitemarg
1589     \@noitemargfalse
1590     \if@nmbrlist \refstepcounter\@listctr \fi
1591   \fi}

The following piece of code is executed if \if@newlist is true (hence for the first item in a list). The effect of \@nbitem is to add some vertical space (the value is O-P, according to the description above). The LaTeX source has a comment that says: “Kludge if list follows \section”. This was commented out by fotex.sty. Otherwise, we use two \addvspace instead of a single one, namely T and minus P; remember that T´ is T-P.

1592 \def\@itemAA{%
1593 %      \if@nobreak \@nbitem \else  %%% REMOVED
1594         \addpenalty\@beginparpenalty
1595         \addvspace\@topsep
1596         \addvspace{-\parskip}%
1597 %      \fi
1598 }

This is now how \item manages vertical space. The code on line 1603 is strange: remember that \indent inserts current paragraph indentation, while \par terminates the current paragraph (all we need is to insert the \everypar token list, in order to flush previous items). On the next line, we have a double \unskip; the reason is that commands like \addvspace add a double skip in order to make it more difficult to remove it. However, this is generally not done in horizontal mode, strange... Changes in V2: \ifInInsertion added (this test is true inside a foot note).

1599 \def\@itemA{
1600   \if@noparitem
1601     \@donoparitem
1602   \else
1603     \if@inlabel \indent \par \fi
1604     \ifhmode \unskip\unskip \par \fi
1605     \ifInInsertion \else
1606        \if@newlist \@itemAA
1607        \else \addpenalty\@itempenalty \addvspace\itemsep \fi
1608     \fi
1609     \global\@inlabeltrue
1610   \fi
1611 }

Now, the \everypar token list is redefined. The difference with the original LaTeX code is that some \global declarations have been added. In the case \if@inlabel is true, we set it to false, and output the label box. We kill \itemindent, in the case where the user says \noindent (in other cases, a new paragraph is created by an explicit or implicit \indent, that inserts a box of width \parindent). There is another change in V2: the call to \FOlabel; we commented it out, because the \FOlabel is also called after the item is completely typeset (and before the box is flushed, but can a page break appear just after the link? this is not so clear).

1612 \def\@itemB{%
1613  \global\everypar{%   %% Global added
1614     \@minipagefalse
1615     \global\@newlistfalse
1616     \if@inlabel
1617       \global\@inlabelfalse
1618       {\setbox\z@\lastbox
1619        \ifvoid\z@ \kern-\itemindent \fi}%
1620       \box\@labels\FOlabel %% added in V2
1621       \penalty\z@
1622     \fi
1623     \if@nobreak
1624       \global\@nobreakfalse   % Global added
1625       \clubpenalty \@M
1626     \else
1627       \clubpenalty \@clubpenalty
1628       \global\everypar{}%   % Global added
1629     \fi}}

A list should contain <fo:list-item> elements. We insert some vertical space at the start of the item. The \par was missing in the first version. Without it, the following happens: the command \jg@usespacebefore computes some quantity in \@tempdima, and calls \vskip. This, being a vertical mode command, terminates the current paragraph, and may start a new page. In this case, the command (with the arguments) is evaluated after the page is shipped out; in this case, \@tempdima is modified, it contains now Xpt, the text width), and the argument of \vskip is now 4pt plus 4pt minus Xpt. In one case, TeX found an optimum break point with 30% of glue set (meaning: the actual glue between the two items is 4pt minus one third of the text width, this is minus 125 pt, say ten lines). In the case there is a label, we handle it after the \vskip.

1630 \XMLelement{fo:list-item}
1631   {\SpaceAttributes}
1632   {
1633    \FOSetHyphenation
1634    \par
1635    \jg@usespacebefore{\vskip}% noskip if spacebefore is zero V2
1636 %      \ifdim\FOspacebefore=0pt\relax\else\vskip\FOspacebefore\fi
1637    \FOlabel}
1638   {}

An item is declared via <fo:list-item-label>. Question: why do we put the argument into \ItemBox? the box is never used! There is a similar code on line 1573. This is to correct a bug, see explanations below.

1639 \newsavebox\ItemBox
1640 \XMLelement{fo:list-item-label}
1641   {}
1642   {\xmlgrab}
1643   {\jg@hackindent
1644    \savebox{\ItemBox}{#1}\item[#1]\FOlabel}

This is called in the case where the current block is the label of a list. This computes some quantities (left margin, right margin, itemsep, etc). It is not clear whether or not these quantities need to be computed. Note that the last line of code defines \makelabel.

1645 \def\FOListBlock{%
1646    \FOSetFont{normal}%
1647    \get@external@font\xdef\FOlistlabelfont{\external@font}%
1648    \jg@usespacebefore{\itemsep}
1649    \jg@use@listparams
1650    \expandafter\csname List\FOtextalign\endcsname}

Bug explanation. The content of <fo:list-item-label> is evaluated twice, fake and real, see line 1644 (occurence A, fake), line 1573 (occurence B, fake), and line 1574 (occurrence C, real). We once thought it better to move the fake code from A to B (as near as possible to C); the trouble is the preceding like above: it defines globally \makelabel, according to the text-align attribute of the <fo:block> of the item. Since \makelabel is used to typeset this block, redefining it inside C is useless (hence, without A, the first item in a list was justified according to the list, and each other was justified according to the previous one). While debugging, we found that the text-align attribute of the list item was `justify´, and \Listjustify was not defined. We added a definition, making it equivalent to `center´.

This piece of code sets the switch FOListInnerPar to true if we are inside a list and this is not the first block. The \relax was missing in V1, as a consequence the test was evaluated before the assignment is complete; consequences of this are explained below. Also equals to one was replaced by less than two.

1651 \def\jg@setlistinnerpar{%
1652         \ifx\XML@parent\FOListItemBody
1653           \global\advance\FOListBlocks by 1\relax%
1654           \ifnum\FOListBlocks<2\relax\else\FOListInnerPartrue\fi
1655         \else
1656           \ifFOListBody \FOListInnerPartrue \fi
1657         \fi}

We explain here a second bug, that occurs when dvi is produced instead of Pdf. If you look at lines 1620 and 1644, you will see two occurrences of \FOlabel; only one of these two will be used because \FOlabel kills \FOid (the command is defined in section 4.22). Consider the scenario where we have only a command at line 1644, and we generate a Pdf file; it will contain some glue and a penalty, then a \write with \newlabel, and a \pdfdest command (each followed by an infinite penalty), then \parskip and \baselineskip (let´s hope that a page break does not occur here, but at the penalty mentioned above), then a paragraph, starting with the label. Now, it happens that adding a hyper anchor in a dvi file calls \leavevmode (via \pdfmark and \pdf@rect), and this flushes the label (the \everypar token list defined on line 1613 is executed, and the line 1620 is executed). This has as consequence that the dvi file contains: first some glue and a penalty, then the \write then \parskip and \baselineskip, then a paragraph starting with the label, followed by some \special commands.

Now, if we have a command at lines 1620 and 1644, the command on line 1620 is executed before the other one is complete, and the \write is executed twice. This means that the command should be used only on line 1620. Now the bug is that the first paragraph of the item is not considered as such, and a \par command is executed (line 1826). If the label is not flushed, this command does nothing, otherwise, it inserts a line break after the label; thus we have a different behavior in the Pdf and dvi file.

The body of the item is declared via <fo:list-item-body>. We say that we are in the body of the list, and start a counter with zero. This counter is (globally) incremented for each paragraph (i.e., <fo:block>) that is not the child of a list item label, nor in a static section, neither a table cell, but is the child of a list item body (see line 1653); the counter is local to the list item, hence must be saved in a local variable \This@FOListBlocks, and restored at the end of the element.

1658 \XMLelement{fo:list-item-body}
1659   {}
1660   {\ifx\FOstartindent\att@bodystart \let\FOstartindent\z@  \fi
1661    \edef\This@FOListBlocks{\the\FOListBlocks}%
1662    \FOListBodytrue\global\FOListBlocks0}
1663   {\global\FOListBlocks\This@FOListBlocks\relax}

Default values for the attributes.

1664 \gdef\FOstartindent{\z@}
1665 \gdef\FOendindent{\z@}
1666 \gdef\FOprovisionaldistancebetweenstarts{24.0pt}
1667 \gdef\FOprovisionallabelseparation{6.0pt}
1668 \newcount\FOListBlocks
1669 \edef\This@FOListBlocks{\the\FOListBlocks}

4.14. Blocks

The <fo:block> is an important object.

We have seen cases where the switch FOBlockGrab has to be set to true. Here is another one: when the border style is solid or when the background is not transparent.

1670 \def\jg@hack@background{%
1671      \ifx\FObackgroundcolor\att@transparent
1672         \ifx\FOborderstyle\att@solid \FOBlockGrabtrue \fi
1673      \else
1674          \FOBlockGrabtrue
1675      \fi}

This is the major addition in V2. If the current block should span the whole page, but the current page has more than one column, we stop and restart the multi-columns environment. Test of widows and orphans added. The documentation says: the orphans (widows) property specifies the minimum number of line-areas in the first (last) area generated by the formatting object; default value is 2. This code is correct if the value is one or two; better than that cannot be done in TeX.

1676 \def\jg@block@span{%
1677   \ifx\FOspan\att@all
1678     \ifnum\NColumns>1\relax \interendmulticols \fi
1679   \fi
1680   \ifnum\FOwidows>1\relax\widowpenalty10000\relax\else\widowpenalty0\relax\fi
1681   \ifnum\FOorphans>1\relax\clubpenalty10000\relax\else\clubpenalty0\relax\fi}

Action at end of block.

1682 \def\jg@endblock@span{%
1683   \ifx\FOspan\att@all
1684     \ifnum\NColumns>1\relax \interbeginmulticols{\NColumns}\fi
1685   \fi}

This is the action associated to a block.

We define two commands, \w@t and \@whattodonext, to be executed at the start of the element, and at the end. The first is followed by \jg@keep@together, the second is preceded by \jg@keep@together. This is a command that may evaluate a \samepage command. There are four cases to consider. Case 1: the parent is a list-item-label. In this case, we execute \FOListBlock and \FOEndBlock. Case 2: FOInOutput is true. The actions are \FOOutputBlock and \FOEndOutputBlock. Case 3: In a table. Actions are \FOBoxedBlock and \FOEndBoxedBlock. Case 4 (otherwise): actions are \FONormalBlock and \FOendBlock. Remember, when we typeset a static block (page headers), we are in case 2, and the parent is empty; can this element contain lists? this would give strange page headings.

1686 \XMLelement{fo:block}
1687   {\SpaceAttributes}
1688   {%
1689   \jg@block@span
1690   \FOBlockGrabfalse
1691   \FOexpandattributes
1692   \FOSetHyphenation
1693   \ifx\XML@parent\FOListItemLabel
1694        \def\w@t{\FOListBlock}%
1695        \def\@whattodonext{\FOEndBlock}%
1696   \else
1697    \ifFOinOutput
1698      \jg@hack@background
1699      \def\w@t{\FOOutputBlock}%
1700      \def\@whattodonext{\FOEndOutputBlock}%
1701    \else
1702        \ifnum\FOinTable>1\relax
1703          \def\w@t{\FOBoxedBlock{\CurrentCellWidth}}%
1704          \def\@whattodonext{\FOEndBoxedBlock}
1705        \else
1706         \jg@setlistinnerpar
1707         \jg@hack@background
1708         \def\@whattodonext{\FOEndBlock}
1709         \def\w@t{\FONormalBlock}%
1710        \fi
1711     \fi
1712   \fi
1713   \w@t
1714   \jg@keep@together
1715   }
1716   {\jg@keep@together
1717   \@whattodonext
1718   \jg@endblock@span}

Declarations.

1719 \XMLNSA{fo}{background-color}{\FObackgroundcolor}{transparent}
1720 \XMLstringX\att@transparent<>transparent</>
1721 \XMLstringX\att@solid<>solid</>

This piece of code is executed at the end of a block (except output, or boxed). We do nothing if this is a label of a list (see later). We emit a \par if this block is somewhere else in a list and FOListInnerPar is true. We call \FOEndBlockTwo in the case where the block is neither in a list nor in a table.

1722 \def\FOEndBlock{%
1723   \ifx\XML@parent\FOListItemLabel
1724   \else
1725     \ifnum\FOinList>0
1726       \ifInInsertion\start@strut\fi
1727       \ifFOListInnerPar\unskip\par\fi
1728     \else
1729        \ifnum\FOTableNesting>0
1730        \else \FOEndBlockTwo  \fi
1731     \fi
1732   \fi}

This is the end of a normal block. We first terminate the paragraph. After that, we call \FOEndBoxedBlock if the block is boxed, or else add some vertical space and some padding. After that, we decide if a new page, or a new double page should be started here. We instantiate the switch @tempswa with a boolean value that says whether or not it is wise to start a new page here. If it is, we just insert some vertical space, otherwise, we insert a penalty, some vertical space, and call a command \@afterheading (a standard LaTeX command). Changes in V2: instead of adding an infinite penalty, this calls \addpenalty, a LaTeX command that can do strange things (included signal a missing \item error). Normally it inserts a penalty, a large one here.

1733 \def\FOEndBlockTwo{%
1734   \par
1735    \ifFOBlockGrab
1736        \FOEndBoxedBlock
1737    \else
1738         \ifdim\FOpaddingafter>\z@ \vskip\FOpaddingafter \fi
1739         \FOBorderBottom
1740    \fi
1741    \jg@handle@breakafter
1742    \jg@keepnext
1743    \if@tempswa\addpenalty{9993}\fi
1744    \FOvspaceafter
1745 %   \if@tempswa\@afterheading\fi
1746 }
1747 \XMLstringX\att@oddpage<>odd-page</>
1748 \XMLstringX\att@evenpage<>even-page</>

This considers the break-after attribute. The value can be one of `auto´, `column´, `page´, `even-page´ or `odd-page´. The code was improved in V2, but still is strange. In particular the second \cleardoublepage seems ineffective. In my opinion, we should use a blank page or a double-blank page here.

1749 \def\jg@handle@breakafter{%
1750    \ifx\FObreakafter\att@page
1751      \clearpage
1752    \else \ifx\FObreakafter\att@oddpage
1753       \ifodd\c@page\cleardoublepage\else\clearpage\fi
1754    \else \ifx\FObreakafter\att@evenpage
1755       \ifodd\c@page\clearpage\else\cleardoublepage\fi
1756    \fi\fi\fi
1757 }

In principle, a break before a block should be interpreted in the same way as a break after. Note that here, we have a blank page.

1758 \def\jg@handle@breakbefore{%
1759       \ifx\FObreakbefore\att@page
1760         \penalty -\@M
1761       \else
1762         \ifx\FObreakbefore\att@oddpage
1763         \penalty -\@M
1764         \ifodd\c@page\else\BlankPage\newpage\fi
1765         \fi
1766       \fi}

This is the start of an output block. It is not complicated. We call functions that specify how to align (justify) the text. If the switch BlockGrab is true, we put the text in a box with a given size. Note: We added \@inlabelfalse because the \color command says \leavevmode if this is true. This gives an empty line if a page break occurs because of an \item. We kill also \FOid. I´m not sure that this is useful, but the page head or foot should contain no anchor. Changes in V2: conditional part moved from before quadding to after quadding. Command \Quadding commented out.

1767 \def\FOOutputBlock{%
1768  \FOSetFont{output}%
1769  \@inlabelfalse\let\FOId\@empty
1770  \QuaddingStart
1771  %\Quadding
1772  \ifFOBlockGrab \FOBoxedBlock{\textwidth}  \fi
1773 }

The end code is easy. If we have opened a grab block, we must close it.

1774 \def\FOEndOutputBlock{%
1775  \QuaddingEnd
1776  \ifFOBlockGrab \FOEndBoxedBlock \fi
1777  \par}

This is used at the start of a border block. If the border is solid and has non-zero width, we insert the \hrule.

1778 \def\FOBorderTop{%
1779   \ifdim\FOborderbeforewidth>\z@
1780    \ifx\FOborderbeforestyle\att@solid
1781     {\color{\FObordercolor}\hrule height \FOborderbeforewidth}%
1782    \fi
1783  \fi}

This is used at the end of a border block. If the border is solid and has non-zero width, we insert the \hrule. Note: This may set the switch FOBlockGrab to true. This is very strange (isn´t it too late?).

1784 \def\FOBorderBottom{%
1785   \ifx\FOborderafterstyle\att@solid
1786    \ifx\FOborderafterwidth\att@thin\def\FOborderafterwidth{0.4pt}\fi
1787    \ifx\FOborderafterwidth\att@medium\def\FOborderafterwidth{0.8pt}\fi
1788    \ifx\FOborderafterwidth\att@thick\def\FOborderafterwidth{1.2pt}\fi
1789   \else
1790    \def\FOborderafterwidth{\z@}%
1791   \fi
1792   \ifx\FOborderbeforestyle\att@solid
1793    \ifx\FOborderbeforewidth\att@thin\def\FOborderbeforewidth{0.4pt}\fi
1794    \ifx\FOborderbeforewidth\att@medium\def\FOborderbeforewidth{0.8pt}\fi
1795    \ifx\FOborderbeforewidth\att@thick\def\FOborderbeforewidth{1.2pt}\fi
1796    \FOBlockGrabtrue
1797   \else
1798    \def\FOborderbeforewidth{\z@}%
1799   \fi
1800    \ifdim\FOborderafterwidth>\z@
1801     \ifx\FOborderafterstyle\att@solid
1802       {\color{\FObordercolor}\hrule height \FOborderafterwidth}%
1803     \fi
1804    \fi
1805 }

This will be used later. It redefines the behavior of space and end-of-line. The value of white-space can be `normal´, `pre´, or `nowrap´. Its effect is to specify some other properties; first white-space-treatment, that can be `ignore´, `preserve´, `ignore-if-before-linefeed´, `ignore-if-after-linefeed´, `ignore-if-surrounding-linefeed´; then white-space-collapse that can be `true´ or `false´; then linefeed-treatment can be `ignore´, `preserve´, `treat-as-space´, `treat-as-zero-width-space´; finally, wrap-option can be `wrap´ or `no-wrap´. It is not clear to me if the code that follows has anything to do with the XSL/Format recommendations.

1806 \def\jg@activew{%
1807    \ifx\FOwhitespace\att@pre\obeyspaces\obeylines\fi
1808    \ifx\FOwhitespacecollapse\att@false\obeyspaces\fi
1809    \ifx\FOwrapoption\att@nowrap\obeylines\fi}

We declare the attribute and the default value.

1810 \XMLNSAX{fo}{wrap-option}{\FOwrapoption}{\inherit}
1811 \XMLNSAX{fo}{white-space}{\FOwhitespace}{\inherit}
1812 \XMLNSAX{fo}{white-space-collapse}{\FOwhitespacecollapse}{\inherit}
1813 \XMLNSAX{fo}{orphans}{\FOorphans}{\inherit}
1814 \XMLNSAX{fo}{widows}{\FOwidows}{\inherit}
1815 \gdef\FOwrapoption{wrap}
1816 \gdef\FOwhitespace{normal}
1817 \gdef\FOwhitespacecollapse{true}
1818 \XMLstringX\att@nowrap<>no-wrap</>
1819 \gdef\FOwidows{2}
1820 \gdef\FOorphans{2}

This is what we do in the case of a normal block. The code was a bit simplified: We removed a reference to \@x (always \relax), the code executed in case of tables in tables (this cannot happen), and the code that saves \FOid if a page is started here.

If we are in a list, three actions are taken: a) we evaluate the label, b) emit a \par and some vertical space (provided that this is allowed), and c) look at translation of spaces and new lines. In the general case, more actions are taken. If there is an attribute that says that we must change page we do it (this test was modified in V2). We emit a \par. If we must grab, we start a grab box. Otherwise we add some vertical space (note: a page break can occur here; in this case the label is on the wrong page; for this reason we moved the \FOlabel near the end). We define \leftskip, \rightskip and some other quantities. We execute action c) above.

Changes in V2: \unskip added before \par; \ifInInsertion test added; minus infinite penalty replaced by \newpage; test added: we change to normal font only if the parent is not \FOFootnoteBody.

1821 \def\FONormalBlock{%
1822 %  \ifnum\FOTableNesting>0
1823 %  \else
1824     \ifnum\FOinList>0
1825       \FOlabel
1826       \ifFOListInnerPar\unskip\par\FOvspacebefore\fi
1827       \jg@activew
1828       \ifInInsertion\start@strut\fi
1829     \else
1830       \jg@handle@breakbefore
1831       \ifx\FObreakbefore\att@page
1832         \newpage
1833       \else
1834         \ifx\FObreakbefore\att@oddpage
1835           \newpage
1836           \ifodd\c@page\else\BlankPage\fi
1837         \else
1838            \ifx\FObreakbefore\att@evenpage
1839               \newpage
1840              \ifodd\c@page\BlankPage\fi
1841            \fi
1842         \fi
1843       \fi
1844       \par
1845 %      \FOlabel JG
1846       \Quadding
1847       \ifFOBlockGrab
1848         \FOBoxedBlock{\linewidth}%
1849       \else
1850         \FOBorderTop
1851         \ifdim\FOpaddingbefore>\z@
1852          \vskip\FOpaddingbefore
1853         \fi
1854         \FOvspacebefore
1855         \parindent\FOtextindent
1856         \advance\leftskip by  \FOpaddingstart
1857         \advance\leftskip by  \FOmarginleft
1858         \advance\rightskip by \FOpaddingend
1859         \advance\rightskip by \FOmarginright
1860       \fi
1861       \jg@activew
1862     \fi
1863     \FOlabel %moved this [jg]
1864     \ifx\XML@parent\FOFootnoteBody\else\FOSetFont{normal}\fi
1865 %  \fi
1866 }

Attributes.

1867 \XMLNSAX{fo}{break-before}{\FObreakbefore}{auto}
1868 \XMLNSAX{fo}{break-after}{\FObreakafter}{auto}

4.15. Percentages

This command is a helper for percentage. If it is called with argument `foo\relax%.\@{A}{B}´, and foo has no % character in it, then #2 is a dot, the test is false, B is evaluated. If foo has the form 33.33%, then the test is true, the number 33.33 is put in \percentval and A is evaluated.

1869 {\catcode`\%=12
1870   \gdef\percenttest#1%#2#3\@{\ifx#2\relax
1871    \def\percentval{#1}\expandafter\@firstoftwo
1872   \else
1873     \expandafter\@secondoftwo
1874   \fi}

We define here \defpercentother, a command that globally defines an active percent character to be \percentother that evaluates to a non-active percent character (in V1, the category code of the percent sign above was 13, and this trick was not needed). There is a little problem with this code: the old value of the percent character as an active character is never restored. In the case where the percent character was made active in order to typeset it, this piece of code is fine; otherwise, we might get unexpected results.

1875 {\catcode`\%=12\relax
1876 \gdef\percentother{%}
1877 }
1878 {\catcode`\%=13\relax
1879 \gdef\defpercentother{\xdef%{\percentother}}
1880 }

In version 1, percentages were computed using the first line shown here. In V2, we change the category code of the percent sign, so that the second line is used now.

1881 %%\expandafter\percenttest#1\relax%.\@
1882 %%\performpercent{#1}

The command \performpercent fully expands the argument as well as the percent sign. Result is put in a temporary command that is evaluated again.

1883 \gdef\performpercent#1{
1884    \defpercentother
1885    \edef\dopercent{\noexpand\percenttest#1\relax%.\noexpand\@}
1886    \dopercent}

This takes an argument, a dimension or a percentage. In the case of a dimension, it is put in \@tempdima. Otherwise it is converted. Conversion is strange: Assume that the number is 33.33. We put 33.33pt in a skip register, divide this by 100, and use \strip@pt, a command that returns the value (without the unit, here 0.3333). This is then used as a multiplier for \TableWidth. The result is in \SCALE.

1887 \gdef\TablePercentToDimen#1{\performpercent{#1}
1888   {\@tempdimb\percentval pt\relax\divide\@tempdimb by 100
1889    \edef\SCALE{\strip@pt\@tempdimb}\global\@tempdima
1890          =\SCALE\TableWidth}{\global\@tempdima#1}}

Same code, but we use \hsize instead of \TableWidth. The result is in \SCALE.

1891 \gdef\PercentToDimen#1{\performpercent{#1}
1892   {\@tempdimb\percentval pt\relax\divide\@tempdimb by 100
1893    \edef\SCALE{\strip@pt\@tempdimb}\global\@tempdima
1894           =\SCALE\hsize}{\global\@tempdima#1}}

Same code, but we use \Gin@nat@width. We use the value of \FOcontentwidth. The result is in \WSCALE, is used for \setkeys {Gin} {width=something}.

1895 \gdef\FOSetGWidth{\performpercent{\FOcontentwidth}
1896   {\@tempdima\percentval pt\relax\divide\@tempdima by 100
1897   \edef\WSCALE{\strip@pt\@tempdima}\setkeys{Gin}%
1898     {width=\WSCALE\Gin@nat@width}}{\setkeys{Gin}{width=\FOcontentwidth}}}

Same code, but we use \Gin@nat@height instead of \TableWidth. We use the value of \FOcontentheight. The result is in \HSCALE, used for \setkeys{Gin} {height=something}.

1899 \gdef\FOSetGHeight{\performpercent{\FOcontentheight}
1900   {\@tempdima\percentval pt\relax\divide\@tempdima by 100
1901   \edef\HSCALE{\strip@pt\@tempdima}\setkeys{Gin}%
1902      {height=\HSCALE\Gin@nat@height}}{\setkeys{Gin}{height=\FOcontentheight}}}

Same idea. However, we divide \f@size by 100. The result is in \FOfontsizefinal.

1903 \gdef\PlayWithFSize#1{\@default\f@size pt
1904   \performpercent{#1}
1905       {\dimen@0.01\@default
1906      \multiply\dimen@\percentval\relax}{\dimen@#1}%
1907      \edef\FOfontsizefinal{\the\dimen@}}

Same code, but we use \baselineskip instead of \TableWidth. Result in \dimen@.

1908 \gdef\PlayWithShift{performpercent{\FOverticalalign}
1909       {\dimen@0.01\baselineskip\multiply\dimen@\percentval\relax}%
1910    {\dimen@\FOverticalalign}}
1911 %

4.16. Fonts

We show here some commands that deal with fonts. This is bit longish... This defines some values for the sizes.

1912 \expandafter\def\csname size-xx-small\endcsname{7pt}
1913 \expandafter\def\csname size-x-small\endcsname{8pt}
1914 \expandafter\def\csname size-small\endcsname{9pt}
1915 \expandafter\def\csname size-medium\endcsname{10pt}
1916 \expandafter\def\csname size-large\endcsname{14.4pt}
1917 \expandafter\def\csname size-x-large\endcsname{18pt}
1918 \expandafter\def\csname size-xx-large\endcsname{20pt}

This puts in \FOfontsizefinal a size (could be 10pt, 100% or medium).

1919 \def\computeFOfontsize{%
1920   \expandafter\ifx\csname size-\FOfontsize\endcsname\relax
1921     \PlayWithFSize\FOfontsize
1922   \else
1923     \edef\FOfontsizefinal{\csname size-\FOfontsize\endcsname}%
1924   \fi}

The mlnames.tex file defines \Family@foo, for different values of foo, for instance monospace, sansserif, serif, or Arial, Helvetica, or Avant-Garde, New-Century-Schoolbook, or cmr, cmss, etc.

1925 \def\FOSetFont#1{%
1926  \FOSetHyphenation
1927  \edef\LaTeXshape{\csname Width@\FOfontstretch\endcsname
1928       \csname Weight@\FOfontweight\endcsname}%
1929  \ifx\LaTeXshape\@empty\def\LaTeXshape{m}\fi
1930  \edef\fFamName{\FOfontfamily}%
1931  \edef\f@series{\LaTeXshape}%
1932  \edef\f@shape{\csname Posture@\FOfontstyle\endcsname}%
1933  \ifx\FOfontvariant\att@smallcaps \def\f@shape{sc}\fi
1934  \let\f@family\relax
1935  \@for\FOfoo:=\FOfontfamily\do{%
1936     \ifx\f@family\relax
1937     \expandafter\let\expandafter\f@family
1938          \csname Family@\FOfoo\endcsname
1939     \fi}%
1940     \ifx\f@family\relax
1941       \def\f@family{\csname Family@\Defaultx@fontfamily\endcsname}%
1942     \fi
1943  \FOSetFontSize
1944  \selectfont
1945  \ifx\FOcolor\@empty \else \color{\FOcolor}\fi
1946 }

This command computes some parameters for font changing. If no line-height is given, we use the font size plus twenty percent.

1947 \def\FOSetFontSize{%
1948  \computeFOfontsize
1949  \ifx\FOlineheight\att@normal
1950    \@tempdima\FOfontsizefinal
1951    \multiply\@tempdima by 12
1952    \divide\@tempdima by 10
1953    \set@fontsize\baselinestretch{\FOfontsizefinal}{\@tempdima}%
1954  \else
1955    \set@fontsize\baselinestretch{\FOfontsizefinal}{\FOlineheight}%
1956  \fi}

Same code as above. However \set@fontsize is not executed, but saved, as well as its argument in the command \FORestoreFontSize.

1957 \def\FOSaveFontSize{%
1958  \computeFOfontsize
1959  \ifx\FOlineheight\att@normal
1960    \@tempdima\FOfontsizefinal
1961    \multiply\@tempdima by 12
1962    \divide\@tempdima by 10
1963    \xdef\FORestoreFontSize{\noexpand\set@fontsize
1964        \noexpand\baselinestretch{\FOfontsizefinal}{\the\@tempdima}}%
1965  \else
1966    \xdef\FORestoreFontSize{\noexpand\set@fontsize
1967        \noexpand\baselinestretch{\FOfontsizefinal}{\FOlineheight}}%
1968  \fi
1969 }

Declarations and attributes.

1970 \XMLNSAX{fo}{line-height}{\FOlineheight}{\inherit}
1971 \XMLNSAX{fo}{font-weight}{\FOfontweight}{\inherit}
1972 \XMLNSAX{fo}{font}{\FOfont}{\inherit}
1973 \XMLNSAX{fo}{font-family}{\FOfontfamily}{\inherit}
1974 \XMLNSA{fo}{font-size}{\FOfontsize}{\inherit}
1975 \XMLNSAX{fo}{font-size-adjust}{\FOfontsizeadjust}{\inherit}
1976 \XMLNSAX{fo}{font-stretch}{\FOfontstretch}{\inherit}
1977 \XMLNSAX{fo}{font-style}{\FOfontstyle}{\inherit}
1978 \XMLNSAX{fo}{font-variant}{\FOfontvariant}{\inherit}
1979 \gdef\FOlineheight{normal}
1980 \gdef\FOfontweight{normal}
1981 \gdef\Defaultx@fontfamily{Times-Roman}
1982 \gdef\FOfont{}
1983 \gdef\FOfontfamily{Times-Roman}
1984 \gdef\FOfontsizeadjust{none}
1985 \gdef\FOfontsize{medium}
1986 \gdef\FOfontstretch{normal}
1987 \gdef\FOfontstyle{normal}
1988 \gdef\FOfontvariant{normal}
1989 \XMLstringX\att@smallcaps<>small-caps</>

All definitions in the remaining of this section come from mlnames.sty. We start with the Family.

1990 \def\Family@monospace{pcr}     \def\Family@sansserif{phv}
1991 \expandafter\def\csname Family@sans-serif\endcsname{phv}
1992 \def\Family@serif{ptm}         \def\Family@cursive{uzc}
1993 \def\Family@fantasy{uzc}       \def\Family@unknown{<unknown>}
1994 \def\Family@Arial{phv}         \def\Family@Helvetica{phv}
1995 \def\Family@Palatino{ppl}      \def\Family@Bookman{pbk}
1996 \def\Family@BaskervilleMT{mbv} \def\Family@Courier{pcr}
1997 \def\Family@Symbol{psy}        \def\Family@Wingdings{pzd}
1998 \def\Family@WingDings{pzd}     \def\Family@LucidaSans{hls}
1999 \def\Family@LucidaBright{hlh}  \def\Family@LucidaTypewriter{hlst}
2000 \def\Family@Savoy{usb}         \def\Family@Luxi{ul9}
2001 \def\Family@ACaslon{pca}       \def\Family@Caslon{uca}
2002 \def\Family@Formata{pfa}       \def\Family@FranklinGothic{pfg}
2003 \def\Family@OCRAbyBT{boa}      \def\Family@AGaramond{pad}
2004 \expandafter\def\csname Family@Avant-Garde\endcsname{pag}
2005 \expandafter\def\csname Family@Courier New\endcsname{pcr}
2006 \expandafter\def\csname Family@New-Century-Schoolbook\endcsname{pnc}
2007 \expandafter\def\csname Family@Times-Roman\endcsname{ptm}
2008 \expandafter\def\csname Family@Trade-Gothic\endcsname{ptg}
2009 \expandafter\def\csname Family@Times-New-Roman\endcsname{ptm}
2010 \expandafter\def\csname Family@Times New Roman\endcsname{ptm}
2011 \expandafter\def\csname Family@Times Roman\endcsname{ptm}
2012 \expandafter\def\csname Family@Times-NR-MT\endcsname{mnt}
2013 \expandafter\def\csname Family@Courier-New\endcsname{pcr}
2014 \expandafter\def\csname Family@Zapf-Dingbats\endcsname{pzd}
2015 \expandafter\def\csname Family@Gill-Sans\endcsname{pgs}
2016 \expandafter\def\csname Family@iso-serif\endcsname{ptm}
2017 \expandafter\def\csname Family@sans-serif\endcsname{phv}
2018 \expandafter\def\csname Family@iso-sanserif\endcsname{phv}
2019 \expandafter\def\csname Family@iso-monospace\endcsname{pcr}
2020 \expandafter\def\csname Family@LetterGothic12PitchBT\endcsname{blg}
2021 \expandafter\def\csname Family@NewsGothic\endcsname{bng}
2022 \expandafter\def\csname Family@NewsGothicBT\endcsname{bng}
2023 \expandafter\def\csname Family@Humanist521\endcsname{bgs}
2024 \expandafter\def\csname Family@Humanist521BT\endcsname{bgs}
2025 \expandafter\def\csname Family@Monospace821\endcsname{bhvt}
2026 \expandafter\def\csname Family@Monospace821BT\endcsname{bhvt}
2027 \expandafter\def\csname Family@OCRB10PitchBT\endcsname{bob}
2028 \expandafter\def\csname Family@OCR-A\endcsname{boa}
2029 \expandafter\def\csname Family@OCR-B-10PitchBT\endcsname{bob}
2030 \expandafter\def\csname Family@Computer-Modern-Typewriter\endcsname{aett}
2031 \expandafter\def\csname Family@Computer-Modern-Sans\endcsname{aess}
2032 \expandafter\def\csname Family@Computer-Modern\endcsname{aer}
2033 \expandafter\def\csname Family@Computer-Modern-Caps-And-Small-Caps\endcsname
2034 {cmcsc}
2035 \def\Family@cmr{cmr}              \def\Family@cmss{cmss}
2036 \def\Family@cmtt{cmtt}            \def\Family@cmcsc{cmcsc}
2037 \def\Family@ectt{ectt}            \def\Family@Utopia{put}
2038 \def\Family@ZapfChancery{pzc}     \def\Family@Fibonacci{cmfib}
2039 \def\Family@Funny{cmfr}           \def\Family@Dunhill{cmdh}
2040 \def\Family@Concrete{ccr}         \def\Family@Charter{bch}
2041 \def\Family@Fontpxr{pxr}          \def\Family@Fontaer{aer}
2042 \def\Family@Fontaess{aess}        \def\Family@Fontaett{aett}
2043 \def\Family@Fontlcmss{lcmss}      \def\Family@Fontlcmtt{lcmtt}
2044 \def\Family@Fontcmvtt{cmvtt}      \def\Family@Fontcmbr{cmbr}
2045 \def\Family@Fontcmtl{cmtl}        \def\Family@Fontpxss{pxss}
2046 \def\Family@Fonttxss{txss}        \def\Family@Fonttxr{txr}

We define some postures.

2047 \def\Posture@upright{n}
2048 \def\Posture@normal{n}
2049 \def\Posture@math{it}
2050 \def\Posture@oblique{sl}
2051 \def\Posture@backslantedoblique{ui}
2052 \def\Posture@italic{it}
2053 \def\Posture@backslanteditalic{ui}

We define some weights.

2054 \def\Weight@ultralight{ul}
2055 \def\Weight@extralight{el}
2056 \def\Weight@light{l}
2057 \def\Weight@semilight{sl}
2058 \def\Weight@medium{}
2059 \def\Weight@normal{}
2060 \def\Weight@semibold{sb}
2061 \def\Weight@bold{bx}
2062 \def\Weight@extrabold{eb}
2063 \def\Weight@ultrabold{ub}
2064 \def\Weight@false{}

We define some widths.

2065 \expandafter\def\csname Width@ultra-condensed\endcsname{uc}
2066 \expandafter\def\csname Width@extra-condensed\endcsname{ec}
2067 \expandafter\def\csname Width@condensed\endcsname{c}
2068 \expandafter\def\csname Width@semi-condensed\endcsname{sc}
2069 \expandafter\def\csname Width@normal\endcsname{}
2070 \expandafter\def\csname Width@semi-expanded\endcsname{sx}
2071 \expandafter\def\csname Width@expanded\endcsname{x}
2072 \expandafter\def\csname Width@extra-expanded\endcsname{ex}
2073 \expandafter\def\csname Width@ultra-expanded\endcsname{ux}
2074 \def\Width@ultracondensed{uc}
2075 \def\Width@extracondensed{ec}
2076 \def\Width@condensed{c}
2077 \def\Width@semicondensed{sc}
2078 \def\Width@medium{}
2079 \def\Width@semiexpanded{sx}
2080 \def\Width@expanded{x}
2081 \def\Width@extraexpanded{ex}
2082 \def\Width@ultraexpanded{ux}

4.17. Links

The XSL/Format standard defines three attributes: target-presentation-context, target-processing-context, and target-stylesheet, but they are ignored. The code make use of a variable that is not defined. We removed the test. I don´t understand these two \let\xx\empty, hence commented them out. Note: the code was modified in January 2007, using \url to typeset the argument; this removes overful hboxes for long URLs; however the \urlstyle has be to changed to `same´, so as to use the current font, and the url package has to be loaded with the `obeyspaces´ option, so as to keep spaces.

2083 \XMLelement{fo:basic-link}
2084   { }
2085   {\xmlgrab}
2086   {
2087   \ifx\FOverticalalign\att@auto
2088      \let\FOverticalalign\FObaselineshift
2089   \fi
2090    \protectCS{\FOinternaldestination}%
2091    \protectCS{\FOexternaldestination}%
2092    \ifx\FOexternaldestination\@empty
2093     \hyperlink{\FOinternaldestination}{\FO@inlinesequence{#1}}%
2094     %\let\FOinternaldestination\@empty  %% JG
2095    \else
2096       \href{\FOexternaldestination}{\FO@inlinesequence{#1}}
2097     %\let\FOexternaldestination\@empty  %% JG
2098     \fi
2099   }

These are the attributes used above.

2100 \XMLNSAX{fo}{external-destination}{\FOexternaldestination}{}
2101 \XMLNSAX{fo}{internal-destination}{\FOinternaldestination}{}

4.18. Footnotes

Case of <fo:footnote>mark text</fo:footnote>. The specifications say that the first child is a <fo:inline> formatting object that gives the citation, and the second is a <fo:footnote-body>, containing the body of the note. In version V2, we handle the case where the footnote is in a table: since cells are evaluated twice, the command \FOfoottext has a meaning depending on the context. New in V2: \FOplainfoottext renamed to \FOfoottext.

2102 \XMLelement{fo:footnote}
2103   {}
2104   {\xmlgrab}
2105   {\FOSaveFontSize\xmltextwochildren\FOplainfootmark\FOfoottext#1}

This is transparent.

2106 \XMLelement{fo:footnote-body}
2107   {}  {}   {}
2108 \XMLname{fo:footnote-body}{\FOFootnoteBody}

This saves some parameters. All these \global prefixes are useless. Note that we move the content of the \@labels box, we do not copy it (said otherwise, the box is empty while typesetting the footnote). All these parameters have something to do with the \item command, whose code is shown above, so that I wonder if the easier solution would not be a complete rewrite of the \item command, without all these ugly hacks.

2109 \def\jg@save@footnote{%
2110   \xdef\Sav@FOListBlocks{\the\FOListBlocks}
2111   \global\let\sav@if@inlabel\if@inlabel
2112   \global\let\sav@if@nobreak\if@nobreak
2113   \global\let\sav@if@newlist\if@newlist
2114   \global\setbox\sav@labels\box\@labels
2115   \expandafter\global\expandafter\sav@everypar\expandafter{\the\everypar}
2116 }

This restores the parameters saved above. Question: is it safe to restore \everypar? Is it wise to do it globally?

2117 \def\jg@restore@footnote{%
2118   \global\FOListBlocks\Sav@FOListBlocks\relax
2119   \global\let\if@inlabel\sav@if@inlabel
2120   \global\let\if@nobreak\sav@if@nobreak
2121   \global\let\if@newlist\sav@if@newlist
2122   \global\setbox\@labels\box\sav@labels
2123   \expandafter\global\expandafter\everypar\expandafter{\the\sav@everypar}
2124 }

This modifies some commands that are saved above. The \relax tokens are useless. Same question as above for \everypar. Is global modification needed?

2125 \def\jg@set@footnote{%
2126   \FOListBlocks0\relax
2127   \global\everypar{}\relax
2128   \FOinList0\relax
2129   \FOListBodyfalse
2130   \InInsertiontrue
2131 }

The command that typesets footnotes is a modification of the standard LaTeX command, shown here. The command \@makefntext is defined in a class file, it should typeset the argument, plus the mark found in \@makefnmark. There are two major changes in the fotex implementation: no label is defined, and the mark is not printed (the text should start with a copy of the mark).

\long\def\@footnotetext#1{\insert\footins{%
    \reset@font\footnotesize
    \interlinepenalty\interfootnotelinepenalty
    \splittopskip\footnotesep
    \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
    \hsize\columnwidth \@parboxrestore
    \protected@edef\@currentlabel{%
       \csname p@footnote\endcsname\@thefnmark
    }%
    \color@begingroup
      \@makefntext{%
        \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
    \color@endgroup}}%

This is now the code.

2132 \long\def\FOplainfoottext#1{%
2133   \insert\footins{\relax
2134     \reset@font\footnotesize
2135     \FORestoreFontSize
2136     \size@update
2137     \interlinepenalty\interfootnotelinepenalty
2138     \splittopskip0pt\relax
2139     \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
2140     \hsize\columnwidth\@parboxrestore
2141     \color@begingroup
2142     \jg@save@footnote
2143     \jg@set@footnote
2144     #1%
2145     \ifhmode\nobreak\fi
2146     \jg@restore@footnote \relax
2147     \color@endgroup}%
2148 }

We define here two other commands. The first one is used in the first pass of a table: the text of the footnote is ignored. The other one is used for the second pass, where the text and the typesetting command is put in a token register. Note: we have seen in section 2.7 how to add tokens at the end of a token list \T. The idea is to put the value of the token list in a command \t defined via \edef, then to fill \T with \t and additional material (for instance \W{#1}). For some strange reason, the command \W is inserted in \t, hence must be preceded by \noexpand.

2149 \def\FOnofoottext#1{}
2150  
2151 \def\FOboxedfoottext#1{
2152   \edef\boxedfootnotetext{\the\BoxedFootnotes\noexpand\FOplainfoottext}%
2153   \global\BoxedFootnotes=\expandafter{\boxedfootnotetext{#1}}%
2154 }

Useful function. It inserts a vertical rule, whose vertical dimensions are those of the \strutbox.

2155 \def\start@strut{%
2156   \vrule height \ht\strutbox depth \dp\strutbox width \z@\relax
2157 }

Bootstrap code. We declare a token list that contain the copy of the \everypar, a box that contains a copy of the unprocessed item labels. The command with a long name holds the name of a XSL region: the one between normal text and a footnote.

2158 \let\FOfoottext\FOplainfoottext
2159 \newtoks\sav@everypar
2160 \newbox\sav@labels
2161 \XMLstringX\att@xsl@footnote@separator<>xsl-footnote-separator</>

Changes in V2: the command \@makecol was redefined, without the line that sets \@elt to \relax. This is strange.

4.19. Inline material

Handling of <fo:inline att>body</fo:inline>. We call one of two alternatives, depending on whether the border is solid or not. As usual, we evaluate `thin´, `thick´ or `medium´.

2162 \XMLelement{fo:inline}
2163   {}
2164   {\xmlgrab}
2165   {
2166   \ifx\FOverticalalign\att@auto \let\FOverticalalign\FObaselineshift \fi
2167   \FOlabel
2168   \ifx\FOborderstyle\att@solid
2169       \interpretwidth
2170       \FOboxedsequence{#1}%
2171   \else
2172       \FO@inlinesequence{#1}%
2173   \fi}

Helper function for letter spacing added in V2. The recommendation says that the attribute letter-spacing is either `normal´, a 〈length〉 or a 〈space〉 (this is something like a TeX glue, with conditionality and precedence). This handles only the case of a length, using the \sodef command of the soul package. Note that the last three arguments of the command are glues (the first one is a font switch, unless empty), so that the case of 〈space〉 could be implemented. The last two parameters define inter-word spacing. Are the values given here the good ones? The test seems strange to me: what if the command is already defined with a different value of the attribute?

2174 \def\jg@so#1{%
2175    \ifx\FOletterspacing\att@normal
2176        \def\pre@sequence{{#1}}%
2177    \else
2178        \def\pre@sequence{%
2179            \@ifundefined{thisso}
2180               {\sodef\thisso{}{\FOletterspacing}{.4em}{.5em}}%
2181               {}
2182            {\thisso{#1}}}%
2183    \fi
2184 }

Second helper function. This applies a function depending on \FOtextdecoration to the \FOlabel and text computed above.

2185 \jg@apply@deco{%
2186   \csname DECO@\FOtextdecoration\endcsname{\FOlabel\pre@sequence}

Normal (non-boxed) inline sequence. We take into account three attributes: letter spacing, decoration, and vertical alignment. The alignment can be `baseline´, this is the normal behavior; it can be `super´ or `sub´, case where we raise or lower using special command; otherwise alignment is a dimension (or a percentage), and we use \raisebox to raise the box. Other possibilities, not yet implemented, are `middle´ (equivalent of \vcenter in TeX), `text-top´, `text-bottom´, `top´, or `bottom´.

We use \csname for the decoration. Question: do we really need the \FOlabel command after the \csname? Maybe we could put it after the last \fi.

2187 \def\FO@inlinesequence#1{%
2188  \FOSetFont{normal}%
2189  \jg@so
2190  \ifx\FOverticalalign\att@baseline
2191    \jg@apply@deco
2192  \else \ifx\FOverticalalign\att@super
2193     \textsuperscript{\jg@apply@deco}}%
2194  \else \ifx\FOverticalalign\att@sub
2195       \textsubscript{\jg@apply@deco}}%
2196  \else
2197    \PlayWithShift
2198    \raisebox{\dimen@}{\jg@apply@deco}%
2199  \fi\fi\fi
2200 }

The original code uses two booleans \ifFOSuper and \ifFOSub. They are never defined, hence we removed the code that uses them. However, the code should be the same as before, with a frame. So, is this a bug? Letter spacing should be added here also.

2201 \def\FOboxedsequence#1{%
2202   \FOSetFont{normal}%
2203   \ifx\FOborderwidth\@empty\else\interpretwidth\fboxrule\FOborderwidth\fi
2204   \ifx\FOverticalalign\att@baseline
2205      \fbox{\csname DECO@\FOtextdecoration\endcsname{\FOlabel#1}}%
2206   \else
2207        \PlayWithShift \fbox{\raisebox{\dimen@}{\FOlabel#1}}%
2208   \fi}

This declares the attribute.

2209 \XMLNSAX{fo}{text-decoration}{\FOtextdecoration}{none}
2210 \XMLNSAX{fo}{baseline-shift}{\FObaselineshift}{baseline}
2211 \XMLstringX\att@sub<>sub</>
2212 \XMLstringX\att@super<>super</>
2213 \XMLstringX\att@baseline<>baseline</>

The following decorations are known. Notice the first: if no decoration is given, the argument is typeset, without the braces. The recommendation says that, for each foo in `blink´, `underline´, `overline´, `strike-out´, there is also no-foo; this is not implemented.

2214 \def\DECO@{\@firstofone}
2215 \def\DECO@blink{\uwave}
2216 \def\DECO@underline{\uline}
2217 \expandafter\def\csname DECO@line-through\endcsname{\sout}
2218 \def\DECO@overline{\oline}
2219 \def\oline#1{$\overline{\mbox{#1}}$}

4.20. Floats and images

Support for .gif format. Is this needed?

2220 \g@addto@macro\Gin@extensions{,.gif}
2221 \@namedef{Gin@rule@.gif}#1{{png}{.png}{`giftopng #1}}

The fotex file defines Gin/scale in the same way as graphicx.sty. We do not repeat the code here.

2222 \define@key{Gin}{scale}{ ... }

Comment by S. Rahtz: “Taken from Heiko Oberdiek´s epstopdf.sty but the redefinitions need to be global”. This allows on the fly conversions from one image type to another. For instance, this may call giftopng.

2223 \global\let\orgGin@setfile\Gin@setfile
2224 \global\def\Gin@setfile#1#2#3{%
2225   \if`\@car #3\relax\@nil
2226     \let\Gin@base\filename@base
2227     \immediate\write18{\@cdr #3\@empty\@nil}%
2228     \orgGin@setfile{#1}{#2}{\filename@base #2}%
2229   \else
2230     \orgGin@setfile{#1}{#2}{#3}%
2231   \fi}

This is trivial.

2232 \XMLelement{fo:float}
2233   {\XMLattributeX{float}{\FOfloat}{float}}
2234   {\ifx\FOfloat\att@none \begin{figure}[!htp] \else  \begin{figure} \fi
2235    \FOlabel}
2236   {\end{figure}}

The following is a bit more complicated. One problem is that we have to merge content-height and height, the same for the width. Question: is this the desired result? In order to make the code easier to understand, we have added three auxiliary functions. The first function sets \FOcontentheight and \FOcontentwidth to the values of \FOheight and \FOwidth, unless both values are `auto´.

2237 \def\jg@merge@aux{%
2238     \ifx\FOwidth\att@auto
2239       \ifx\FOheight\att@auto        \relax
2240       \else
2241         \def\FOcontentheight{\FOheight}%
2242         \def\FOcontentwidth{auto}%
2243        \fi
2244     \else
2245       \def\FOcontentwidth{\FOwidth}%
2246       \ifx\FOheight\att@auto
2247         \def\FOcontentheight{auto}%
2248       \else
2249         \def\FOcontentheight{\FOheight}%
2250       \fi
2251     \fi
2252 }

These commands perform a non trivial action if the value of the attribute is not `auto´. It can be `scale-to-fit´ or a dimension, or percentage (using code shown above).

2253 \def\jg@mergeW{%
2254     \ifx\FOcontentwidth\att@scaletofit
2255       \setkeys{Gin}{width=\hsize}%
2256     \else
2257       \ifx\FOcontentwidth\att@auto\else\FOSetGWidth\fi
2258     \fi
2259 }
2260 \def\jg@mergeH{%
2261     \ifx\FOcontentheight\att@scaletofit
2262        \setkeys{Gin}{height=\vsize}%
2263     \else
2264        \ifx\FOcontentheight\att@auto\else\FOSetGHeight\fi
2265     \fi
2266 }

This piece of code considers text-align but we could also take into account display-align, that can be `before´, `after´ or `center´ (as well as `auto´). Note that text-align can be `start´ or `end´ as well.

If scaling is `uniform´, the aspect ratio should be preserved; is the default value of the Gin variable true?

2267 \XMLelement{fo:external-graphic}
2268    {
2269       \XMLattributeX{content-height}{\FOcontentheight}{auto}
2270       \XMLattributeX{content-width}{\FOcontentwidth}{auto}
2271    }
2272    {
2273     \jg@filetest
2274     \jg@merge@aux
2275     \jg@mergeW
2276     \jg@mergeH
2277     \def\aligntype{center}
2278     \ifthenelse{\equal{\FOtextalign}{right}}{\def\aligntype{flushright}}{}
2279     \ifthenelse{\equal{\FOtextalign}{left}}{\def\aligntype{flushleft}}{}
2280     \def\Picscaled{\begin{\aligntype}%
2281        \includegraphics{\FOsrcname}\end{\aligntype}}
2282     \ifx\FOscaling\att@uniform\else\setkeys{Gin}{keepaspectratio=false}\fi
2283     \ifx\FOborderstyle\att@solid\fbox{\Picscaled}\else\Picscaled\fi
2284     }
2285     {}

Attributes used here.

2286 \XMLNSAX{fo}{scaling}{\FOscaling}{uniform}
2287 \XMLNSAX{fo}{height}{\FOheight}{auto}
2288 \XMLstringX\att@scaletofit<>scale-to-fit</>
2289 \XMLstringX\att@uniform<>uniform</>

This makes the string canonical. This is used in some places; it has an alternate name elsewhere.

2290 \def\protectCS#1{%
2291  \begingroup
2292        \utfeight@protect@chars
2293        \xdef\FOtempCS{#1}%
2294  \endgroup
2295  \let#1\FOtempCS}%

This function does something if the argument starts with `url´. Otherwise, it removes a prefix of the form `file://´ or `file:´. The result is in \FOsrcname.

2296 \def\FOfiletest#1#2#3#4#5#6#7#8\@{%
2297   \def\@tempa{#1#2#3#4#5#6#7}%
2298   \def\@tempb{#1#2#3#4#5}%
2299   \def\@tempc{#1#2#3#4}%
2300   \ifx\@tempa\file@prefix
2301     \xdef\FOsrcname{#8}%
2302   \else
2303    \ifx\@tempb\file@shortprefix
2304       \xdef\FOsrcname{#6#7#8}%
2305    \else
2306     \ifx\@tempc\file@urlprefix
2307     %%   \expandafter\FOurlfiletest#5#6#7#8%
2308     %% \@empty\@empty\@empty\@empty\@empty\@empty\@empty\@empty\@empty\@empty
2309     \jg@filetestaux#5#6#7#8)\@
2310     \else
2311       \xdef\FOsrcname{#1#2#3#4#5#6#7#8}%
2312     \fi  \fi  \fi}

These lines were added instead of lines 2307 and 2208. Guess why.

2313 \def\jg@filetestaux#1)#2\@{%
2314   \FOurlfiletest#1\@empty\@empty\@empty\@empty\@empty\@empty\@empty\@empty)}

Version with all the arguments.

2315 \def\jg@filetest{%
2316    {\utfeight@protect@chars
2317     \expandafter\FOfiletest\FOsrc\@empty
2318        \@empty\@empty\@empty\@empty\@empty\@empty\@}}

This function puts foo in \FOsrcname if the argument is url(file://foo) or url(file:foo) or url(foo) (the prefix `url(´ has already been removed).

2319 \def\FOurlfiletest#1#2#3#4#5#6#7#8){%
2320   \def\@tempa{#1#2#3#4#5#6#7}%
2321   \def\@tempb{#1#2#3#4#5}%
2322   \ifx\file@prefix\@tempa
2323     \xdef\FOsrcname{#8}%
2324   \else
2325    \ifx\@tempb\file@shortprefix
2326       \xdef\FOsrcname{#6#7#8}%
2327    \else
2328       \xdef\FOsrcname{#1#2#3#4#5#6#7#8}%
2329    \fi \fi}

These are the strings needed by the function above.

2330 \XMLstring\file@urlprefix<>url(</>
2331 \XMLstring\file@prefix<>file://</>
2332 \XMLstring\file@shortprefix<>file:</>

4.21. Markers

We consider here a list of the form X1Y1X2Y2...XnYn. The list ends with Xn being \relax. This command puts in the token list \toks@ all pairs {Xi}{Yi} for which Xi is not equal to the value of the attribute marker-class-name. The name of the command is misleading; after this command has been evaluated, we are ready to add a marker.

2333 \gdef\FOaddmarker#1#2{%
2334  \ifx\relax#1
2335  \else
2336    \def\FOtemp{#1}%
2337    \ifx\FOtemp\FOmarkerclassname
2338    \else \toks@\expandafter{\the\toks@{#1}{#2}}  \fi
2339    \expandafter\FOaddmarker
2340  \fi}

Handling of <fo:marker marker-class-name=X>mark</fo:marker>. We consider the content of \FOmarks, apply the command defined above, then add a new pair at the end; the pair is defined by X and mark. We copy the token list into the \FOmarks command (using full expansion, assignment is global), and then put it in a TeX mark.

2341 \XMLelement{fo:marker}
2342  {}
2343  {\xmlgrab}
2344  {\toks@{}%
2345   \expandafter\FOaddmarker\FOmarks\relax{}%
2346   \toks@\expandafter{\the\expandafter\toks@\expandafter{\FOmarkerclassname}{#1}}%
2347   \xdef\FOmarks{\the\toks@}%
2348   \mark{\FOmarks}}

Here we assume that the list is terminated by a double \relax. The command finds and typesets the value associated to \FOthisretrieveclassname. In fact, we assume that Xi is in #1, Yi in #2. If the first argument is \relax, this is the end of the list, and we are done. If it is not the desired marker, we continue. Otherwise, we call a command that reads everything up to the double \relax at high speed. This will first read #2, this is Yi with a pair of additional braces that will disappear as argument #1 of the next routine. It will then read \fi, two tokens, a second \fi and the list. The two \fi tokens are read again.

2349 \gdef\FOgetmarker#1#2{%
2350   \ifx\relax#1
2351   \else
2352    \def\FOtemp{#1}%
2353     \ifx\FOtemp\FOthisretrieveclassname
2354       \FOmarkergobble{#2}%
2355      \fi
2356    \expandafter\FOgetmarker
2357   \fi}
2358 \gdef\FOmarkergobble#1#2\relax\relax{\fi\fi#1}

Handling of <fo:retrieve-marker retrieve-class-name=X retrieve-position=Y/>. We fetch one of the marks (\firstmark or \botmark), and extract what is needed. Changes in V2: commands \FirstOnPage and \LastOnPage replaced by others with longer names, same value; \topmark replaced by \firstmark

2359 \XMLelement{fo:retrieve-marker}
2360  {}
2361  {\xmlgrab}
2362  {\begingroup
2363     \utfeight@protect@chars
2364     \ifx\FOretrieveposition\att@first@starting@within@page
2365        \xdef\FOthismark{\firstmark}%
2366     \else \ifx\FOretrieveposition\att@last@starting@within@page
2367        \xdef\FOthismark{\botmark}%
2368     \else
2369        \xdef\FOthismark{\firstmark}%
2370     \fi \fi
2371    \xdef\FOthisretrieveclassname{\FOretrieveclassname}
2372    \endgroup
2373    \expandafter\FOgetmarker\FOthismark\relax\relax}

Constants and attributes used in the code above.

2374 \XMLNSAX{fo}{retrieve-class-name}{\FOretrieveclassname}{}
2375 \XMLNSAX{fo}{retrieve-position}
2376      {\FOretrieveposition}{first-starting-within-page}
2377 \XMLNSAX{fo}{marker-class-name}{\FOmarkerclassname}{}
2378 \XMLstring\FirstOnPage<>first-starting-within-page</>
2379 \XMLstringX\att@first@starting@within@page<>first-starting-within-page</>
2380 \XMLstringX\att@last@starting@within@page<>last-starting-within-page</>
2381 \XMLstring\LastOnPage<>last-starting-within-page</>
2382 \gdef\FOmarks{}

4.22. Page numbers and anchors

The command \FOlabel will be explained later, it defines the anchor associated to a label A. This defines two quantities: a static and a dynamic one. If a LaTeX file contains a \pageref command, associated to a label A, then the printed document will contain some number, say 17, we call this the static quantity associated to the label; this number is written in the auxiliary file, and read at the start of the job, allowing forward references. If you read the document using a computer (in dvi, PostScript, or Pdf format), it can happen that the region containing the number is active, and you can click on it. What happens exactly depends on the software used, and is controlled by the \hyperref package; we call this the dynamic part. It happens that the static part is formed of two token lists in standard LaTeX, five lists when using the hyperref package. These are in the command \r@A. The \pageref command extracts the second item in the list.

The XSL/Format equivalent of \pageref is a <fo:page-number-citation> defining the static part, in a <fo:basic-link> defining the dynamic part. These elements have an attribute X and Y, containing the identification of the anchor. The attribute names are different, but the values are the same. The code shown here makes the assumption that the static part is used only for getting the correct page number. Hence, all fields but the second are empty, and all we need to do is evaluate the whole thing, it is in \r@A for the anchor A.

2383 \XMLelement{fo:page-number-citation}
2384    {\XMLattributeX{ref-id}{\FOrefid}{}}
2385    {}
2386    {\fopagecitation}
2387 %\def\fopagecitation{\pageref{\FOrefid}}
2388 \def\fopagecitation{\csname r@\FOrefid\endcsname}

Handling of <fotex:sort>...</fotex:sort>. The content is a sequence of page-number-citation elements; we want to typeset the numbers, in increasing order, removing duplicates, and compacting them. The idea is the following: We redefine \fopagecitation, the command that handles the citations, it will construct a sorted list. When the end tag is seen, we shall compact and print the list.

2389 \XMLelement{fotex:sort}
2390    {\XMLattributeX{range-char}{\FOrangechar}{\textendash}}
2391    {\let\fopagecitation\fosortpagecitation
2392     \global\sorttoks{}}
2393    {\global\sortcount-2\let\@elt\focompress@elt
2394     \let\fosep\@empty
2395     \let\foheld\relax
2396     \the\sorttoks
2397     \ifx\foheld\relax\else\FOrangechar\fi
2398     \foheld}

We are faced here with the following problem: insert a number in an ordered list (increasing order). Assume that the list contains X 1 , X 2 , X 3 , etc., and the number to insert is Y. The idea is to consider each X i , renaming it locally X. There are three cases to consider. If X<Y, it is too early, if X=Y we do nothing, if X>Y we insert Y here. Note that, if X i >Y, then X i+1 >Y. As a consequence, we shall replace Y by ∞ after insertion. At the end of the loop, we can consult the value of Y: if it is not ∞, we have to insert it at the end.

In practice, we proceed as follows. First, each X i is of the form \@elt{3} or \@elt{12}. These quantities are in the token list \sorttoks. We shall see in a minute how to evaluate this list in such a way that, at the start of the evaluation, the list is empty. Moreover we change the meaning of \@elt to \fosort@elt. The quantity Y is in the counter \sortcount. In the case X<Y, we have to re-insert \@elt{X} in the list (line 2408). In the case X>Y, we insert \@elt{Y} and \@elt{X} in the list. The non trivial point is to evaluate Y (there is no problem for X, since this is in #1), this requires four \expandafter commands on lines 2403 and 2404. Remember: since \sorttoks is a reference to a token list, if you say \global\sorttoks\foo, then \foo is expanded, but the tokens in the list are not. Here we have \expandafter instead of \foo, so that the \the after the brace is expanded. Since \the fully expands what follows, its effect is first to expand the \expandafter (and as a consequence the next \the) and second, to replace \sorttoks by its value (this is a bit unusual).

2399 \newcount\sortcount
2400 \newtoks\sorttoks
2401 \def\fosort@elt#1{%
2402  \ifnum#1>\sortcount
2403    \global\sorttoks\expandafter{\the\expandafter\sorttoks\expandafter\@elt
2404        \expandafter{\the\sortcount}\@elt{#1}}%
2405   \global\sortcount\maxdimen
2406   \else
2407    \ifnum#1<\sortcount
2408    \global\sorttoks\expandafter{\the\sorttoks\@elt{#1}}%
2409    \fi
2410  \fi}

The \fosortpagecitation is used to add a page reference into a sorted list. Assume that \label{foo} has been executed somewhere. This defines \r@foo, to be a command that can be used by \ref or \pageref. In what follows, we want the number used by \pageref. For the case where \pageref is used before \label, LaTeX provides a mechanism in which information is printed in the auxiliary file, and read at the start of the job (and also at the end; sometimes you will see “labels may have changed”). If you compile a file for the first time, the \r@foo command is undefined, and \pageref has to consider this case; this is the reason why we cannot use this command directly. We shall assume here that the hyperref package has been loaded, so that, when defined, \r@foo contains a list of five items, the second one being the page number. On line 2413 we call the command that returns this second argument. On the line that follows, we insert five \relax tokens, in order to make sure that there are at least five tokens. On the preceding line, there are three \expandafter: if we had only one, the effect would be to replace \csname by \r@foo; since we have three, the effect is to replace it by the value of \r@foo. There is a little trick. If the command is undefined, \csname sets \r@foo to \relax, and \@secondoffive produces \relax. In some cases, the command might produce some junk. We can avoid the “missing number” error by inserting a zero in front of the token list. We get rid of the junk by evaluating everything else in a \hbox, that is copied in \box0, and discarded. Thus, this converts our page number in an integer, stored in \sortcount.

Our second job is then to sort. What we do is: we define \sortoks to be the empty token list, with an \expandafter that puts the content of the token list in the input stream. This means that we evaluate this token list in a context where the list is empty. Evaluating the list may have as side effect to insert this new element and replace the value by \maxdimen. Otherwise, we must insert it at the end.

2411 \def\fosortpagecitation{%
2412    \setbox0\hbox{\global\sortcount=0\expandafter\expandafter\expandafter
2413    \@secondoffive\csname r@\FOrefid\endcsname
2414       \relax\relax\relax\relax\relax}%
2415     \let\@elt\fosort@elt
2416     \global\sorttoks\expandafter{\expandafter}\the\sorttoks
2417     \ifnum\sortcount<\maxdimen
2418    \global\sorttoks\expandafter{%
2419        \the\expandafter\sorttoks\expandafter\@elt\expandafter{\the\sortcount}}%
2420   \fi}

Let´s compress the list. Consider the case where we have a list of numbers, say 1, 2, 3, 6, 8, and 9. We apply the next command to every element, in order. We assume that our numbers are positive, the counter is initialized to -2, so that the initial test is false. This means that the first number, 1, is typeset and remembered. The original code was wrong. We give here a correct version.

2421 \gdef\focompress@elt#1{%
2422  \global\advance\sortcount\@ne
2423  \ifnum#1=\sortcount\relax
2424     \edef\foheld{\#1}%
2425   \else
2426     \ifx\foheld\relax\else\FOrangechar\fi
2427     \foheld\fosep#1\relax
2428     \let\foheld\relax
2429  \fi
2430  \global\sortcount#1\relax
2431  \def\fosep{, }}

This converts a XSLT format into a LaTeX command. There are examples in chapter 7 of this feature. It can be used to convert a section reference (defined by some numbers) into something like IV.7-2. If you say format = `[1.a]´, and if the numbers are 4 and 2, the result is `[4.b]´. If we have only one number, the result is `[4]´. This mechanism is very complicated. We need only to typeset pages numbers (everything else is done by the XSLT processor), so that only one number has to be converted.

2432 \expandafter\let\csname Format-1\endcsname\@arabic
2433 \expandafter\let\csname Format-i\endcsname\@roman
2434 \expandafter\let\csname Format-I\endcsname\@Roman
2435 \expandafter\let\csname Format-a\endcsname\@alph
2436 \expandafter\let\csname Format-A\endcsname\@Alph

Handling of <fo:page-number/>. We call a command that formats the page number.

2437 \XMLelement{fo:page-number}
2438   {}
2439   {}
2440   {\expandafter\FOgeneratePage\FOformat\@null}

The call to the \FOgeneratePage command is a bit strange. The arguments #1#2 is the result of the expansion of the format. Hence, #1 is the first character of the format. This piece of code works if the format has the form `1.´: it applies \@arabic to the page number and puts a dot after it. For later use, we put the interesting part in a command.

2441 \def\FOgeneratePage#1#2\@null{\csname Format-#1\endcsname{\c@page}#2}
2442 \def\jgFOlabel#1{\csname Format-#1\endcsname{\c@page}}

We define now \FOlabel. The idea of the command is to create a label associated to the current id, stored in \FOid, provided that this is not empty (the command may be called more than once for the same id, but only one label will be created). We do not execute the \label command, but instead, we write directly something in the .aux file, and create an anchor. As explained above, what we print is the command \newlabel, followed by the id, followed by a list of five items, all empty but the second one, containing the formatted page number. Note: the sort-page-citation shown above assumes that integer values are used,

The implementation was modified. Originally, the quantity printed on the .aux file was the same as the body of <fo:page-number>. The trouble is that all quantities in the \write command are expanded; thus \@arabic is expanded; its value is \number, so that the current page number (from \c@page) is used. This is wrong. The \protected@write command redefines temporarily \thepage to be \relax, so that, in the case of \label, the page number is not evaluated (it will be later, when the page is shipped out). We corrected this in the following way. We add a local redefinition of \jgFOlabel to \relax. As a consequence, the \write will store the command and the value of the format attribute, the command will be expanded later. There is no need to this \@null hacking.

2443 \def\FOlabel{%
2444  \ifx\@empty\FOid\else
2445   \@bsphack
2446   \protected@write\@mainaux{\let\jgFOlabel\relax}%
2447     {\string\newlabel{\FOid}{{}{\jgFOlabel\FOformat}{}{}{}}}%
2448   \@esphack
2449   \hyper@@anchor{\FOid}{\relax}%
2450   \global\let\FOid\@empty
2451  \fi
2452 }

4.23. Other elements

The fotex.sty file defines a command \@declaredcolor that is unused. It defines this one:

2453 \def\HTMLColor#1#2#3#4#5#6#7#8{%
2454  \definecolor{#1}{RGB}{"#3#4, "#5#6, "#7#8}}

This predefines some colors.

2455 \HTMLColor{aqua}.00FFFF
2456 \HTMLColor{black}.000000
2457 \HTMLColor{blue}.0000FF
2458 \HTMLColor{fuchsia}.FF00FF
2459 \HTMLColor{gray}.808080
2460 \HTMLColor{green}.008000
2461 \HTMLColor{lime}.00FF00
2462 \HTMLColor{maroon}.800000
2463 \HTMLColor{navy}.000080
2464 \HTMLColor{olive}.808000
2465 \HTMLColor{purple}.800080
2466 \HTMLColor{red}.FF0000
2467 \HTMLColor{silver}.C0C0C0
2468 \HTMLColor{teal}.008080
2469 \HTMLColor{white}.FFFFFF
2470 \HTMLColor{yellow}.FFFF00
2471 \definecolor{orange}{cmyk}{0,0.61,0.87,0}

Leaders: This might produce [this command not implemented in the HTML version] in the case where the style is dashed, or dotted, or if the thickness is 1pt. If the width is zero, we emit the leader command, otherwise put it in a hbox of the desired width.

2472 \XMLelement{fo:leader}
2473   {}
2474   {
2475  \leavevmode
2476   \ifx\FOleaderpattern\leader@pattern@rule
2477    \ifx\FOrulestyle\rule@style@dashed
2478     \def\w@t{\cleaders\hbox{$\m@th \mkern1.5mu-\mkern1.5mu$}\hfil}%
2479    \else
2480     \ifx\FOrulestyle\rule@style@dotted
2481       \def\w@t{\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfil}%
2482     \else
2483       \ifdim\FOrulethickness>\z@
2484         \def\w@t{\leaders\hrule height \FOrulethickness\hfill}%
2485       \else
2486         \def\w@t{\hfill}%
2487       \fi
2488     \fi
2489    \fi
2490   \else
2491   \ifx\FOleaderpattern\leader@pattern@dots
2492       \def\w@t{\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill}%
2493   \else % space
2494       \def\w@t{\hfill}%
2495   \fi
2496  \fi
2497  \jg@leaderaux
2498    }
2499   {}

Changes in V2. This computes the leader width correctly, using minimum, optimum and maximum values. The macro \w@t contains the leader box.

2500 \def\jg@leaderaux{
2501  \ifx\@empty\FOleaderlength
2502    \PercentToDimen{\FOleaderlengthoptimum}%
2503    \edef\leaderopt{\the\@tempdima}%
2504    \PercentToDimen{\FOleaderlengthminimum}%
2505    \edef\leadermin{\the\@tempdima}%
2506    \PercentToDimen{\FOleaderlengthmaximum}%
2507    \edef\leadermax{\the\@tempdima}%
2508    \@tempdima\leaderopt\relax
2509    \advance\@tempdima-\leadermin\relax
2510    \@tempdimb\leadermax\relax
2511    \advance\@tempdimb-\leaderopt\relax
2512    \LeaderLength\leaderopt plus \@tempdimb minus \@tempdima\relax
2513  \else
2514    \PercentToDimen{\FOleaderlength}%
2515    \LeaderLength\@tempdima\relax
2516  \fi
2517  \ifdim\LeaderLength=\z@
2518    \w@t
2519  \else
2520    \hbox to \LeaderLength{\w@t}%
2521 \fi}

Attributes and commands for handling leaders.

2522 \XMLNSAX{fo}{leader-alignment}{\FOleaderalignment}{\inherit}
2523 \XMLNSAX{fo}{leader-length}{\FOleaderlength}{\inherit}
2524 \XMLNSAX{fo}{leader-pattern}{\FOleaderpattern}{\inherit}
2525 \XMLNSAX{fo}{leader-pattern-width}{\FOleaderpatternwidth}{\inherit}
2526 \XMLNSAX{fo}{rule-style}{\FOrulestyle}{\inherit}
2527 \XMLNSAX{fo}{rule-thickness}{\FOrulethickness}{\inherit}
2528 \XMLNSAX{fo}{leader-length.maximum}{\FOleaderlengthmaximum}{\textwidth}
2529 \XMLNSAX{fo}{leader-alignment}{\FOleaderalignment}{\inherit}
2530 \XMLNSAX{fo}{leader-length}{\FOleaderlength}{\inherit}
2531 \XMLNSAX{fo}{leader-pattern}{\FOleaderpattern}{\inherit}
2532 \XMLNSAX{fo}{leader-pattern-width}{\FOleaderpatternwidth}{\inherit}
2533 \XMLNSA{fo}{leader-length.optimum}{\FOleaderlengthoptimum}{0pt} % no X?
2534 \XMLNSAX{fo}{leader-length.minimum}{\FOleaderlengthminimum}{\z@}
2535 \gdef\FOleaderalignment{none}
2536 \gdef\FOleaderlength{}
2537 \gdef\FOleaderpattern{space}
2538 \gdef\FOleaderpatternwidth{}
2539 \gdef\FOrulestyle{solid}
2540 \gdef\FOrulethickness{1.0pt}
2541 \XMLstringX\rule@style@dashed<>dashed</>
2542 \XMLstringX\rule@style@dotted<>dotted</>
2543 \XMLstringX\leader@p@attern@space<>space</>
2544 \XMLstringX\leader@pattern@rule<>rule</>
2545 \XMLstringX\leader@pattern@dots<>dots</>
2546 \newskip\LeaderLength

These are trivial.

2547 \XMLelement{fo:block-container}
2548   {}  {}   {}
2549 \XMLelement{fo:inline-container}
2550   {}  {}   {}
2551 \XMLelement{fo:wrapper}
2552   {}
2553   {\FOSetFont{wrapper}\FOlabel}
2554   {}

These are undefined.

2555 \XMLelement{fo:bidi-override}
2556 \XMLelement{fo:initial-property-set}
2557 \XMLelement{fo:instream-foreign-object}
2558 \XMLelement{fo:multi-case}
2559 \XMLelement{fo:multi-properties}
2560 \XMLelement{fo:multi-property-set}
2561 \XMLelement{fo:multi-switch}
2562 \XMLelement{fo:multi-toggle}
2563 \XMLelement{fo:table-footer}

Handling of <fotex:bookmark FB-level=A FB-label=B>text</fotex:bookmark>. We have written FB instead of `fotex-bookmark´, it´s shorter. The translation is \pdfbookmark[A]{text}{B}.

2564 \XMLelement{fotex:bookmark}
2565  {
2566   \XMLattributeX{fotex-bookmark-level}{\FOTEXbookmarklevel}{0}
2567   \XMLattributeX{fotex-bookmark-label}{\FOTEXbookmarklabel}{}
2568  }
2569  {\xmlgrab}
2570  {\protectCS\FOTEXbookmarklabel
2571    \let\ignorespaces\@empty
2572    \pdfbookmark[\FOTEXbookmarklevel]{#1}{\FOTEXbookmarklabel}}

What is the purpose of this?

2573 \let\@@ReadBookmarks\ReadBookmarks
2574 \def\ReadBookmarks{{\let\InputIfFileExists\@input\@@ReadBookmarks}}

Implementation of <fo:character character=C/>. This is a bit strange. We use more or less the same method as <fo:inline>.

2575 \XMLNSA{fo}{character}{\FOcharacter}{}
2576 \XMLelement{fo:character}
2577   {}
2578   {
2579   \ifx\FOverticalalign\att@auto \let\FOverticalalign\FObaselineshift \fi
2580   \FO@character{\FOcharacter}}
2581   {}

What we do is look at the vertical alignment attribute, and use some more or less standard functions for vertical placement.

2582 \def\FO@character#1{%
2583  \ifx\FOverticalalign\att@baseline #1%
2584  \else \ifx\FOverticalalign\att@super \textsuperscript{#1}%
2585  \else \ifx\FOverticalalign\att@sub  \textsubscript{#1}%
2586  \else \PlayWithShift \raisebox{\dimen@}{#1}%
2587  \fi \fi \fi}

The \textsuperscript command is standard, \textsubscript is not. We use the same idea. Call to \fontsize removed in both commands.

2588 \DeclareRobustCommand*\textsubscript[1]{%
2589   \@textsubscript{\selectfont#1}}
2590 \def\@textsubscript#1{%
2591   {\m@th\ensuremath{_{\mbox{#1}}}}}
2592 \def\@textsuperscript#1{%
2593   {\m@th\ensuremath{^{\mbox{#1}}}}}

This piece of code redefines \obeyspaces, so as to make space an active character, with value \FOdiscretionary. This fonction considers the value of \FOwrapoption. If it is `nowrap´, then space is a discretionary character, if a line is split at this position, an arrow with a hook pointing to the left is printed. Otherwise, a normal space is used.

2594 \gdef\FOdiscretionary{%
2595  \ifx\FOwrapoption\att@nowrap
2596      \discretionary{\kern-.5ex\lower1ex\hbox{$\hookleftarrow$}}{}{\kern1ex}%
2597  \else\space\fi}
2598 \def\obeyspaces{\catcode`\ =\active}
2599 {\obeyspaces\global\let =\FOdiscretionary}

4.24. Bootstrap code

Some integers, boxes and dimensions.

2600 \newcount\FOTableNesting  \FOTableNesting0  % unused...
2601 \newcount\FOinList        \FOinList0
2602 \newdimen\FOspaceleft
2603 \newdimen\MasterBottomMargin     \MasterBottomMargin\z@
2604 \newdimen\MasterLeftMargin       \MasterLeftMargin\z@
2605 \newdimen\MasterRightMargin      \MasterRightMargin\z@
2606 \newdimen\MasterTopMargin        \MasterTopMargin\z@
2607 \newdimen\XFOendindent  \newdimen\XFOstartindent % unused
2608 \newdimen\bottommargin
2609 \newdimen\FOtempdim
2610 \newdimen\@default \@default=10pt
2611 \newsavebox\BlockBox
2612 \newsavebox\CellBox
2613 \newsavebox\FOBOX

Some conditionals.

2614 \newif\ifFOBlockGrab   \FOBlockGrabfalse
2615 \newif\ifFODebug       \FODebugfalse
2616 \newif\ifFOListBody    \FOListBodyfalse
2617 \newif\ifFOListInnerPar\FOListInnerParfalse
2618 \newif\ifFOinOutput    \FOinOutputfalse
2619 \def\DEBUG#1{%
2620  \ifFODebug \typeout{#1, at \the\inputlineno} \fi
2621 }

These are defined, but currently ignored.

2622 \def\usewhitespace{%
2623  \UnicodeCharacter{13}{ \ignorespaces}%
2624  \UnicodeCharacter{32}{ \ignorespaces}%
2625  \UnicodeCharacter{9}{ \ignorespaces}%
2626 }
2627 \def\ignorewhitespace{%
2628  \UnicodeCharacter{13}{}%
2629  \UnicodeCharacter{32}{}%
2630  \UnicodeCharacter{9}{}%
2631 }

Some strings, used everywhere.

2632 \XMLstring\LINK<>LINK</>
2633 \XMLstringX\att@all<>all</>
2634 \XMLstringX\att@any<>any</>
2635 \XMLstringX\att@auto<>auto</>
2636 \XMLstringX\att@blank<>blank</>
2637 \XMLstringX\att@black<>black</>
2638 \XMLstringX\att@bottom<>bottom</>
2639 \XMLstringX\att@centered<>center</>
2640 \XMLstringX\att@false<>false</>
2641 \XMLstringX\att@first<>first</>
2642 \XMLstringX\att@no<>no</>
2643 \XMLstringX\att@none<>none</>
2644 \XMLstringX\att@normal<>normal</>
2645 \XMLstringX\att@page<>page</>
2646 \XMLstringX\att@pre<>pre</>
2647 \XMLstringX\att@repeat<>repeat</>
2648 \XMLstringX\att@true<>true</>

Some attributes.

2649 \XMLNSA{fo}{color}{\FOcolor}{\inherit}    \gdef\FOcolor{black}
2650 \XMLNSAX{fo}{id}{\FOid}{}
2651 \XMLNSAX{fo}{role}{\FOrole}{none}
2652 \XMLNSAX{fo}{size}{\FOsize}{auto}
2653 \XMLNSAX{fo}{src}{\FOsrc}{}
2654 \XMLNSAX{fo}{text-indent}{\FOtextindent}{\inherit} \gdef\FOtextindent{\z@}
2655 \XMLNSAX{fo}{top}{\FOtop}{auto}
2656 \XMLNSA{fo}{vertical-align}{\FOverticalalign}{auto}
2657 \XMLNSAX{fo}{width}{\FOwidth}{auto}
2658 \XMLNSAX{fotex}{column-align}{\FOcolumnalign}{}
2659 \XMLNSAX{fo}{format}{\FOformat}{\inherit}    \gdef\FOformat{1}

Some names.

2660 \XMLname{fo:list-item-label}{\FOListItemLabel}
2661 \XMLname{fo:list-item-body}{\FOListItemBody}
2662 \XMLname{fo:table-cell}{\FOTableCell}
2663 \XMLname{fo:table-row}{\FOTableRow}

This is executed when we load the file. Comments of the form D=foo indicate the default value in LaTeX. Changes in V2: \widowpenalty and \clubpenalty changed from 8000 to 0. We think that a value like 0pt plus 2pt is better for the \parskip glue.

2664 \def\fps@table{!htbp} %D=tbp
2665 \def\fps@figure{!htbp} %D=tbp
2666 \parindent\z@      %D=20pt
2667 \parskip\z@        %D=0pt plus 1pt
2668 \emergencystretch 3em  %D=0.0pt
2669 \tabcolsep3pt      %D=6pt
2670 \hbadness=4000     %D=1000
2671 \hyphenpenalty=400 %D=50
2672 \pretolerance=500  %D=100
2673 \relpenalty=500
2674 \tolerance=1000    %D=200
2675 \vbadness=3000     %D=1000
2676 \widowpenalty=0 %D=150
2677 \clubpenalty=0  %D=150
2678 \@twosidetrue
2679 \fboxsep0pt        %D=3pt
2680 \setcounter{topnumber}{5}        %D=2
2681 \renewcommand\topfraction{.9}    %D=.7
2682 \setcounter{bottomnumber}{12}    %D=1
2683 \renewcommand\bottomfraction{.9} %D=.3
2684 \setcounter{totalnumber}{6}      %D=3
2685 \renewcommand\textfraction{.1}   %D=.2
2686 \DefineCharacter{8232}{2028}{\newline}
2687 \DefineCharacter{8208}{2010}{-\/}
2688 \@ifundefined{pdfoutput}{}{\def\pdfBorderAttrs{/Border [0 0 0]}}
2689 \long\def\@firstoffive#1#2#3#4#5{#1}%
2690 \long\def\@secondoffive#1#2#3#4#5{#2}%
2691 \long\def\@thirdoffive#1#2#3#4#5{#3}%
2692 \long\def\@fourthoffive#1#2#3#4#5{#4}%
2693 \long\def\@fifthoffive#1#2#3#4#5{#5}%
2694 \def\supppdf{supp-pdf}
2695 \let\FOinputIfFileExists\InputIfFileExists
2696 \def\InputIfFileExists#1#2#3{%
2697  {\def\@tempa{#1}\ifx\@tempa\supppdf\else
2698    \FOinputIfFileExists{#1}{#2}{#3}\fi}}
2699 \providecommand\textasciitilde{~}

Some booleans.

2700 \newif\ifFODefiningPage  \FODefiningPagefalse
2701 \newif\ifFOinLayout      \FOinLayoutfalse
2702 \newif\ifMulticolPending \MulticolPendingfalse
2703 \newif\ifStartWithOmit   \StartWithOmitfalse
2704 \newif\ifForcePageSetup
2705 \newif\ifBlankPage
2706 \newif\ifInInsertion
previous
TOC
next
Back to main page