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.   <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>
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 `ߠ´, 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}
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}}
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}
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 }
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 {}
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 }
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}
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 {}
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}}
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}{}
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}}%
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}}%
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 }
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 }
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 }
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 , 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 , and . If (different optimum values), then the one with lowest optimum value is discarded. Otherwise, the result is .
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 , the stretch part is . This code uses 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.
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.
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}
899 \def\QuaddingEnd{% 900 \ifx\FOtextalignlast\att@relative 901 \csname endQ@\FOtextalign\endcsname 902 \else 903 \csname endQ@\FOtextalignlast\endcsname 904 \fi}
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 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
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}
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 ). 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 }
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 and a width (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}
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}{}
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 }
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</>
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 . 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 and . When the label is finally printed, TeX will use the current \parskip, hence P. This gives a total of : the old glue plus the old \parskip. Note that the code above inserts .
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 , 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 , 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 .
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}
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}
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}
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 }
1867 \XMLNSAX{fo}{break-before}{\FObreakbefore}{auto} 1868 \XMLNSAX{fo}{break-after}{\FObreakafter}{auto}
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 %
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 }
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}
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}{}
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}
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}}%
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.
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}
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}}$}
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}
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 {}
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:</>
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{}
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 , , , etc., and the number to insert is Y. The idea is to consider each , renaming it locally X. There are three cases to consider. If , it is too early, if we do nothing, if we insert Y here. Note that, if , then . 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 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 , we have to re-insert \@elt{X} in the list (line 2408). In the case , 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 , 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 }
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
2547 \XMLelement{fo:block-container} 2548 {} {} {} 2549 \XMLelement{fo:inline-container} 2550 {} {} {} 2551 \XMLelement{fo:wrapper} 2552 {} 2553 {\FOSetFont{wrapper}\FOlabel} 2554 {}
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}}
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}
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
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</>
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}
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