Tralics, a LaTeX to XML translator; Part II

3. Interpreting MathML and related stuff in TeX

In the previous chapter, we have seen that TeX is able to read and evaluate an XML file. The Raweb is not typeset directly: there is a stylesheet that converts it into XSL/Format, see Chapter 7. The purpose of the next chapter is to explain how XSL/Format has to be interpreted by TeX; in this chapter we explain everything else, the big part being MathML, described in [3].

We describe here the file raweb-cfg.sty. It starts with the following lines

\immediate\write20{Loading mathml support and raweb extensions
$ Revision: 2.14 $}

It is not a real style file, so that the category code of the `@´ character is not known, and we do not want to use the \ProvidesPackage command for the identification. The revision number given above is computed by RCS, it is likely that the Tralics distribution comes with another version of this file.

This file was obtained by some additions to a file named mathml2.xmt, and it starts with the following copyright notice.

1 % patch to xmltex.tex plus mathml2.xmt plus other stuff
2 %% Copyright 2000 David Carlisle, for the original mathml part
3 %% Copyright 2004, 2006 Jos\'e Grimm
5 %% This file is distributed under the LaTeX Project Public License
6 %% (LPPL) as found at
7 %% Either version 1.0, or at your option, any later version.

We have seen in the previous chapter that, if xmltex.tex is loaded and LaTeX reads an XML file, then the first occurence of an element in a name space `xx´ provokes loading of file yy.xmt, assuming that `xx´ and `yy´ are associated in the catalogue. In our case, the root element is in the `fo´ namespace, some file is loaded, and the interpretation of the root element provokes loading of all required packages, as well as \begin{document}. After that, it is not possible to load other packages, so that the yy.xmt file cannot be a real LaTeX package.

For some unknown reason, in some cases, this autoloading mechanism did not work with the file mathml2.xmt, so that we decided to load it systematically, using a hook. At the end of the previous chapter we have explained that, if your file is called foo.tex, then foo.cfg is loaded. Thus this file is loaded if it has foo.cfg as alternate name (in Chapter 8, we give an example where a Perl script makes a symbolic link from foo.cfg to raweb-cfg.sty). As a consequence, the file is loaded before anything else (in particular before the class file), but we can use the begin-document hook.

3.1. Local patches to xmltex.tex

Redefinition of \utfeight@protect@chars. Compare this with the definition on page 2.2, line 123. The idea is that using \let rather than \def should be more efficient. Some tests show that the speedup factor is nearly 10 percent.

8 \def\utfeight@protect@chars{%
9   \let\utfeightax\string
10   \let\utfeightay\string
11   \let\utfeightaz\string
12   \let\utfeightb\utfeightb@jg@
13   \let\utfeightc\utfeightc@jg@
14   \let\utfeightd\utfeightd@jg@}

Three auxiliary definitions used above.

15 \def\utfeightb@jg@#1#2{#1\string#2}
16 \def\utfeightc@jg@#1#2#3{#1\string#2\string#3}
17 \def\utfeightd@jg@#1#2#3#4{#1\string#2\string#3\string#4}

We redefine this also (original definition on page 2.2, line 96).

18 \begingroup
19 \catcode`<\active
20 \catcode`&\active
21 \gdef\utfeight@protect@internal{%
22   \let\utfeightax\noexpand
23   \let\utfeightay\noexpand
24   \let\utfeightaz\utfeightaz@jg@int
25   \let<\relax\let&\relax
26   \let\utfeightb\utfeightb@jg@int
27   \let\utfeightc\utfeightc@jg@int
28   \let\utfeightd\utfeightd@jg@int}

These are the auxiliary commands.

29 \def\utfeightaz@jg@int{\noexpand\utfeightaz\noexpand}
30 \def\utfeightb@jg@int#1#2{\noexpand\utfeightb#1\string#2}
31 \def\utfeightc@jg@int#1#2#3{\noexpand\utfeightc#1\string#2\string#3}
32 \def\utfeightd@jg@int#1#2#3#4{\noexpand\utfeightd#1\string#2\string#3\string#4}

This is redefined (original on page 2.16, line 885); we locally change the meaning of the ampersand character, using the command \XML@amp@markup shown below.

33 \gdef\utfeight@chardef#1{%
34   \begingroup
35   \utfeight@protect@chars
36   \let&\XML@amp@markup@jg      % <-  modified
37   \xdef\x@temp{#1}%
38   \endgroup
39   \let#1\x@temp}
40 \endgroup

The fotex.xmt file contains a declaration of the form `\XMLnamespaceattributeX {fo} {external-destination} {FOexternaldestination} {}´ The `X´ after the command name means that the argument is evaluated in an \xdef. In the case where we want a & in an URL, this does not work. Thus we redefine the meaning of &: in the case of &amp; the expansion is &, otherwise the standard behavior is used.

41 \def\XML@amp@markup@jg#1;{%
42   \XML@amp@markup@jgw#1;amp;\@nil}
43 \def\XML@amp@markup@jgw#1amp;#2\@nil{%
44   \ifx b#2b\XML@amp@markup#1;\else\string&\fi}

3.2. Support for MathML

We pretend here that mathml2.xmt has been loaded (we do not want the original file to be loaded later).

45 \global\expandafter\let\csname xmt:mathml2.xmt\endcsname\@ne

We declare the namespaces.

46 \DeclareNamespace{m}{}
47 \DeclareNamespace{fotex}{}
48 \DeclareNamespace{fo}{}

Let´s start with simple things: <m:mrow>text</m:mrow> translates to \bgroup text \egroup. This differs from the original coding, allowing constructions like ${x^2}^3$.

49 \XMLelement{m:mrow}
50   {}
51   {\bgroup}
52   {\egroup}

Processing of <m:msub> base subscript </m:msub>. The translation is base_{subscript}. The MathML standard says that there is a subscriptshift attribute that specifies the minimum amount to shift the baseline of subscript down. This is not implemented.

53 \XMLelement{m:msub}
54   {}
55   {\xmlgrab}
56   {\xmltextwochildren\@firstofone\sb#1}

Processing of <m:msup> base supscript </m:msup>. The translation is base^{supscript}. The attribute superscriptshift defined by the standard is ignored.

57 \XMLelement{m:msup}
58   {}
59   {\xmlgrab}
60   {\xmltextwochildren\@firstofone\sp#1}

Processing of <m:msubsup> base subscript superscript </m:msubsup>: the translation is base_{subscript}^{supercript}. The attributes subscriptshift and superscriptshift defined by the standard are ignored.

61 \XMLelement{m:msubsup}
62   {}
63   {\xmlgrab}
64   {\xmltexthreechildren\@firstofone\sb\sp#1}

Processing of <m:mstyle atts> text </m:mstyle>. The translation is text. However, the attributes of the element influence typesetting of it. The attributes veryverythinmathspaceverythinmathspacethinmathspacemediummathspacethickmathspaceverythickmathspace, and veryverythickmathspace can be modified (default value k/18em, for k=1 to 7). TeX provides only three values: thin, medium and thick. The attribute scriptsizemultiplier gives the quotient of the font size at level N and N+1 and scriptminsize indicates the minimum size (TeX has three levels of math fonts: text, script, and scriptscript; there is no such limit in MathML, however there is a limit on the size). The default value of the multiplier is 0.71. If the main font is a 10pt, then the script size will be 7pt, and scriptscript size will be 5pt (these are the default values or TeX; however the default scriptminsize is 8pt). We ignore the background attribute.

In this piece of code, we consider the value of the displaystyle attribute. If it is true, we evaluate \displaystyle. If it is neither true nor false, nothing happens. If it is false, we look at the scriptlevel attribute. We execute \textstyle, or \scriptstyle, or \scriptscriptstyle, if it is 0, 1 or 2. If the attribute is not provided, we use 0 as default value; if the value is out of range, we use 2.

65 \XMLelement{m:mstyle}
66  {\XMLattribute{displaystyle}{\XML@att@displaystyle}{foo} %
67    \XMLattribute{scriptlevel}{\XML@scriptlevel}{0}%
68  }
69  {\xmlgrab}
70  {{\ifx\XML@att@displaystyle\att@true\displaystyle
71    \else\ifx\XML@att@displaystyle\att@false
72     \ifx\XML@scriptlevel\att@dzero\textstyle
73      \else\ifx\XML@scriptlevel\att@done\scriptstyle
74       \else \scriptscriptstyle\fi\fi
75    \fi %do nothing if neither true nor false
76    \fi#1}}

Processing of <m:mroot> base index </m:mroot>. We call \mathmlroot with base and index as arguments (note that the empty group {} disappears when this calls the intermediate command). The MathML norm says that the scriptlevel of index should be increased by two (thus, it will be as small as the TeX version).

77 \XMLelement{m:mroot}
78   {}
79   {\xmlgrab}
80   {\xmltextwochildren\mathmlroot{}#1}
82 \def\mathmlroot#1#2{\root#2\of{#1}}

Processing of <m:msqrt> base </m:msqrt>. We just call \sqrt.

83 \XMLelement{m:msqrt}
84   {}
85   {\xmlgrab}
86   {\sqrt{#1}}

Processing of <m:mtext>...</m:mtext>. That´s easy, we use \text.

87 \XMLelement{m:mtext}
88   {}
89   {\xmlgrab}
90   {\text{#1}}

Processing of <m:ms>...</m:ms>. Not yet implemented. The MathML doc says: The <m:ms> element is used to represent “string literals” in expressions meant to be interpreted by computer algebra systems.

91 % \XMLelement{m:ms} {} {"} {"}

Processing of <m:mn>...</m:mn>. The MathML doc says: Unlike <mi>, <mn> elements are (typically) rendered in an unslanted font by default, regardless of their content.

92 \XMLelement{m:mn}
93   {}
94   {\xmlgrab}
95   {\mathrm{#1}}

Processing of <m:mi mathvariant=xx>...</m:mi>. The MathML doc says that the fontstyle attribute is deprecated, and the mathvariant attribute can take one of the following values: normal, bold, italic, bold-italic, double-struck, bold-fraktur, script, bold-script, fraktur, sans-serif, bold-sans-serif, sans-serif-italic, sans-serif-bold-italic, monospace.

96 \XMLelement{m:mi}
97   {\XMLattribute{mathvariant}{\XML@mathmlvariant}{normal}}
98   {\xmlgrab}
99   {\mi@test#1\relax}

As you can see, not all variants are implemented here. On the other hand, the test done on line 107 is false in the case where the content of the element is a letter plus some space. (The MathML norm does not say how to get a single letter using an upright variant).

100 \gdef\mi@test#1#2\relax{
101  \ifx\XML@mathmlvariant\att@mathml@bold
102   \mathbf{#1#2}\else
103  \ifx\XML@mathmlvariant\att@mathml@sansserif
104   \mathsf{#1#2}\else
105  \ifx\XML@mathmlvariant\att@mathml@tt
106   \texttt{#1#2}\else
107   \ifx\mi@test#2\mi@test
108    \expandafter#1
109   \else
110    \mathrm{#1#2}
111   \fi\fi\fi\fi}

These are used in the code above.

112 \XMLstring\att@mathml@bold<>bold</>
113 \XMLstring\att@mathml@sansserif<>sans-serif</>
114 \XMLstring\att@mathml@tt<>monospace</>

Processing of <m:mspace atts></m:mspace>. The MathML doc says that attributes width, height, depth, linebreak are allowed. Here we consider only the width. The \@defaultunits command is called for the case where a dimension is given without a unit.

115 \XMLelement{m:mspace}
116   {\XMLattribute{width}{\XML@mspacewidth}{0}}
117   {}
118   {\@defaultunits\dimen@\XML@mspacewidth pt\relax\@nnil
119    \ifnum\dimen@=\z@\else\kern\dimen@\fi}

3.2.1. Fences

Processing of <m:mfenced open=A close=B separators=...>content</m:mfenced>. We ignore the separators. The translation is \left A content \right B. However, what \left and \right want are numbers (to be precise, slots into math fonts that indicate how large delimiters can be made from smaller pieces); what TeX wants is a character with a \delcode, what the XML file contains is a character. We hack a bit, because we cannot expand all these Unicode characters.

120 \XMLelement{m:mfenced}
121   { \XMLattribute{open}{\XML@fenceopen}{(}
122     \XMLattribute{close}{\XML@fenceclose}{)}
123   }
124   {\jg@hacko\left\XML@fenceopen}
125   {\jg@hackc\right\XML@fenceclose}

This code is easy: for instance, if the character is U+2329, we replace it by \langle.

126 \def\jg@hacko{%
127   \ifx\XML@fenceopen\jg@lt\let\XML@fenceopen\langle\fi
128   \ifx\XML@fenceopen\jg@lbra\let\XML@fenceopen\langle\fi
129   \ifx\XML@fenceopen\jg@xlbra\let\XML@fenceopen\langle\fi
130   \ifx\XML@fenceopen\jg@gt\let\XML@fenceopen\rangle\fi
131   \ifx\XML@fenceopen\jg@rbra\let\XML@fenceopen\rangle\fi
132   \ifx\XML@fenceopen\jg@xrbra\let\XML@fenceopen\rangle\fi
133   \ifx\XML@fenceopen\jg@verbar\let\XML@fenceopen\|\fi
134   \ifx\XML@fenceopen\jg@Verbar\let\XML@fenceopen\|\fi
135   \ifx\XML@fenceopen\jg@lfloor\let\XML@fenceopen\lfloor\fi
136   \ifx\XML@fenceopen\jg@rfloor\let\XML@fenceopen\rfloor\fi
137   \ifx\XML@fenceopen\jg@lceil\let\XML@fenceopen\lceil\fi
138   \ifx\XML@fenceopen\jg@rceil\let\XML@fenceopen\rceil\fi
139   \ifx\XML@fenceopen\jg@lmoustache\let\XML@fenceopen\lmoustache\fi
140   \ifx\XML@fenceopen\jg@rmoustache\let\XML@fenceopen\rmoustache\fi
141   \ifx\XML@fenceopen\jg@lgroup\let\XML@fenceopen\lgroup\fi
142   \ifx\XML@fenceopen\jg@rgroup\let\XML@fenceopen\rgroup\fi
143   \ifx\XML@fenceopen\jg@uparrow\let\XML@fenceopen\uparrow\fi
144   \ifx\XML@fenceopen\jg@downarrow\let\XML@fenceopen\downarrow\fi
145   \ifx\XML@fenceopen\jg@Uparrow\let\XML@fenceopen\Uparrow\fi
146   \ifx\XML@fenceopen\jg@Downarrow\let\XML@fenceopen\Downarrow\fi
147   \ifx\XML@fenceopen\jg@updownarrow\let\XML@fenceopen\updownarrow\fi
148   \ifx\XML@fenceopen\jg@Updownarrow\let\XML@fenceopen\Updownarrow\fi
149 }

Same code for closing delimiters.

150 \def\jg@hackc{%
151   \ifx\XML@fenceclose\jg@gt\let\XML@fenceclose\rangle\fi
152   \ifx\XML@fenceclose\jg@rbra\let\XML@fenceclose\rangle\fi
153   \ifx\XML@fenceclose\jg@xrbra\let\XML@fenceclose\rangle\fi
154   \ifx\XML@fenceclose\jg@lt\let\XML@fenceclose\langle\fi
155   \ifx\XML@fenceclose\jg@lbra\let\XML@fenceclose\langle\fi
156   \ifx\XML@fenceclose\jg@xlbra\let\XML@fenceclose\langle\fi
157   \ifx\XML@fenceclose\jg@verbar\let\XML@fenceclose\|\fi
158   \ifx\XML@fenceclose\jg@Verbar\let\XML@fenceclose\|\fi
159   \ifx\XML@fenceclose\jg@lfloor\let\XML@fenceclose\lfloor\fi
160   \ifx\XML@fenceclose\jg@rfloor\let\XML@fenceclose\rfloor\fi
161   \ifx\XML@fenceclose\jg@lceil\let\XML@fenceclose\lceil\fi
162   \ifx\XML@fenceclose\jg@rceil\let\XML@fenceclose\rceil\fi
163   \ifx\XML@fenceclose\jg@lmoustache\let\XML@fenceclose\lmoustache\fi
164   \ifx\XML@fenceclose\jg@rmoustache\let\XML@fenceclose\rmoustache\fi
165   \ifx\XML@fenceclose\jg@lgroup\let\XML@fenceclose\lgroup\fi
166   \ifx\XML@fenceclose\jg@rgroup\let\XML@fenceclose\rgroup\fi
167   \ifx\XML@fenceclose\jg@uparrow\let\XML@fenceclose\uparrow\fi
168   \ifx\XML@fenceclose\jg@downarrow\let\XML@fenceclose\downarrow\fi
169   \ifx\XML@fenceclose\jg@Uparrow\let\XML@fenceclose\Uparrow\fi
170   \ifx\XML@fenceclose\jg@Downarrow\let\XML@fenceclose\Downarrow\fi
171   \ifx\XML@fenceclose\jg@updownarrow\let\XML@fenceclose\updownarrow\fi
172   \ifx\XML@fenceclose\jg@Updownarrow\let\XML@fenceclose\Updownarrow\fi
173 }

Here we put each delimiter in a string command.

174 \XMLstring\jg@verbar<>&#x2016;</>
175 \XMLstring\jg@Verbar<>&#8214;</>
176 \XMLstring\jg@lfloor<>&#x230A;</>
177 \XMLstring\jg@rfloor<>&#x230B;</>
178 \XMLstring\jg@lceil<>&#x2308;</>
179 \XMLstring\jg@rceil<>&#x2309;</>
180 \XMLstring\jg@lmoustache<>&#x23B0;</>
181 \XMLstring\jg@rmoustache<>&#x23B1;</>
182 \XMLstring\jg@lgroup<>&#x3014;</>
183 \XMLstring\jg@rgroup<>&#x3015;</>
184 \XMLstring\jg@uparrow<>&#x2191;</>
185 \XMLstring\jg@Uparrow<>&#x21D1;</>
186 \XMLstring\jg@downarrow<>&#x2193;</>
187 \XMLstring\jg@Downarrow<>&#x21D3;</>
188 \XMLstring\jg@updownarrow<>&#x2195;</>
189 \XMLstring\jg@Updownarrow<>&#x21D5;</>

The Unicode standard says that U+2329 and U+232A should not be used for math. For this reason, we add U+27E8 and U+27E9 in this list.

190 \XMLstring\jg@lbra<>&#x2329;</>
191 \XMLstring\jg@rbra<>&#x232A;</>
192 \XMLstring\jg@xlbra<>&#x27E8;</>
193 \XMLstring\jg@xrbra<>&#x27E9;</>

3.2.2. Accents

The translation by Tralics of $\vec x$ is <mover accent='true'> <mi>x</mi> <mo>&rightarrow;</mo> </mover>. A non obvious point is how to translate this back. This idea is that we evaluate the accent in a context (defined by \notinover), this will set the two commands \cur@mo@content and \jg@cur@acc. Let´s declare them here.

194 \let\notinover\relax
195 \def\cur@mo@content{TOTO}
196 \let\jg@cur@acc\relax

Processing of <m:munderover accent=bool accentunder=boolbase underscript overscript</m:munderover>. This is wrong. Moreover, attributes are ignored.

197 \XMLelement{m:munderover}
198   { }
199   {\xmlgrab}
200   {\xmltexthreechildren\@firstofone\sb\sp#1}

Processing of <m:mover accent=bool> base overscript</m:mover>. We use an intermediate command. If no accent, we use \stackrel. Otherwise, we call a command, say \jg@bindings, evaluate the accent in an environment where \notinover is \over, then execute two commands \cur@mo@content and \jg@cur@acc (\X and \Y for simplicity). Evaluating the overscript should define \X, and evaluating \X should define \Y, in such a way that \Y applied to the base should put an accent on it.

201 \XMLelement{m:mover}
202   {\XMLattribute{accent}{\XML@overaccent}{none}}
203   {\xmlgrab}
204   {\xmltextwochildren\xml@implement@over{}#1}

The auxiliary function.

205 \def\xml@implement@over#1#2{%
206  \ifx\XML@overaccent\att@true {%
207    \jg@bindings
208    \let\notinover\over #2\let\notinover\relax \cur@mo@content\jg@cur@acc{#1}%
209  }\else\stackrel{#2}{#1}\fi}

Processing of <m:munder accentunder=bool> base underscript</m:munder>. We use an intermediate command: same idea as above. If no accent, we use \underset.

210 \XMLelement{m:munder}
211   {\XMLattribute{accentunder}{\XML@underaccent}{none}}
212   {\xmlgrab}
213   {\xmltextwochildren\xml@implement@under{}#1}
214 \def\xml@implement@under#1#2{%
215  \ifx\XML@underaccent\att@true {%
216    \jg@ubindings
217    \let\notinover\over #2\let\notinover\relax \cur@mo@content\jg@cur@acc{#1}%
218  }\else \underset{#2}{#1}\fi}

Processing of <m:mo atts>...</m:mo>. The MathML norm says that the following attributes are recognized: form, fence, separator, lspace, rspace, stretchy, symmetric, maxsize, minsize, largeop, movablelimits, and accent. We implement only two attributes. We assume that, if form = `prefix´ is given, that our operator is like log or sin, and never used as an accent. Thus, we generate a \mathop with an operator font. We set \limits or \nolimits, depending on the value of the movablelimits attribute. Otherwise, some command is called.

219 \XMLelement{m:mo}
220   {\XMLattribute{form}{\XML@mathmlform}{inline}%
221    \XMLattribute{movablelimits}{\XML@movablelimits}{false}}
222   {\xmlgrab}
223   {\ifx\XML@mathmlform\att@PREFIX
224      \ifx\XML@movablelimits\att@true
225        \mathop{\operator@font #1}\limits
226      \else
227        \mathop{\operator@font #1}\nolimits
228      \fi
229    \else\special@mo{#1}\fi}

For some strange reason, the default code does not produce a less than sign. Hence we hack a bit. In the case of accent, we have two commands, let´s call them \X and \Y. We define \X, so that it will define \Y. The definition is global (it must be seen by the caller of the <mo> element). In the case of grave accent, what we have here is a 7bit character, and we have to set \Y directly. In the case of 3 or 4 dots, we have to set this command.

230 \def\special@mo#1{%
231      \def\jg@tck{#1}% save the argument
232      \ifx\notinover\over% we cannot typeset here
233         \ifx\jg@tck\jg@accgrave % strange
234           \global\let\jg@cur@acc\jg@grave@acc
235           \global\let\cur@mo@content\relax
236         \else \ifx\jg@tck\jg@accdddot % strange
237           \global\let\jg@cur@acc\dddot
238           \global\let\cur@mo@content\relax
239         \else \ifx\jg@tck\jg@accddddot % strange
240           \global\let\jg@cur@acc\ddddot
241           \global\let\cur@mo@content\relax
242         \else\gdef\cur@mo@content{#1}\fi\fi\fi
243      \else % typeset the argument, handle < and > in the correct way
244      \ifx\jg@tck\jg@gt\string>\else
245      \ifx\jg@tck\jg@lt\string<\else
246      #1\fi\fi\fi}

Some declarations, needed above.

247 \XMLstring\jg@lt<>&lt;</>
248 \XMLstring\jg@gt<>&gt;</>
249 \XMLstring\jg@accgrave<>`</>
250 \XMLstring\jg@accdddot<>&#x20DB;</>
251 \XMLstring\jg@accddddot<>&#x20DC;</>

This is the big hack. Remember that, in the case of \vec, the accent is an arrow, in fact, a Unicode character, that typesets as an arrow. What we do is to redefine \rightarrow, in order to put in \Y (in fact in \jg@cur@acc) a command that behaves like \vec. In the case of a breve accent, the character 2D8 is defined to be \ifmmode \u\else \textasciibreve \fi, so that we have to redefine \u. In the case of the character 302, the definition is \ifmmode \hat{}\else \^{}\fi, so that we have to redefine \hat in such a way that it reads an argument, and evaluates to something that looks like \hat.

252 \def\jg@bindings{%
253    \def\texttildelow {\global\let\jg@cur@acc\jg@tilde@acc}%
254 %   \def\textasciimacron {\global\let\jg@cur@acc\jg@cur@accB}%
255     \def\textasciicircum{\global\let\jg@cur@acc\jg@hat@acc}
256    \def\textasciicaron {\global\let\jg@cur@acc\jg@check@acc}%
257    \def\u{\global\let\jg@cur@acc\jg@breve@acc}%
258    \def\hat##1{\global\let\jg@cur@acc\jg@hat@acc}%
259    \def\dot##1{\global\let\jg@cur@acc\jg@dot@acc}%
260    \def\mathring##1{\global\let\jg@cur@acc\jg@ring@acc}%
261    \def\textasciidieresis{\global\let\jg@cur@acc\jg@ddot@acc}%
262    \let\JGG@orig@rarrow\rightarrow
263    \let\JGG@orig@larrow\leftarrow
264    \def\rightarrow{\global\let\jg@cur@acc\jg@overRarrow@acc}%
265    \def\leftarrow{\global\let\jg@cur@acc\jg@overLarrow@acc}%
266    \def\textoverbrace{\global\let\jg@cur@acc\overbrace}
267    \def\textunderbrace{\global\let\jg@cur@acc\underbrace}
268    \def\textasciiacute{\global\let\jg@cur@acc\acute}
269    \def\textasciimacron{\global\let\jg@cur@acc\overline}
270    \def\ring{\global\let\jg@cur@acc\mathring}
271 }

The same idea is used in the case of underaccent.

272 \def\jg@ubindings{%
273 \let\JGG@orig@rarrow\rightarrow
274 \let\JGG@orig@larrow\leftarrow
275    \def\texttildelow {\global\let\jg@cur@acc\jg@tilde@acc}%
276    \def\textasciimacron {\global\let\jg@cur@acc\underline}%
277    \def\textasciicaron {\global\let\jg@cur@acc\jg@check@acc}%
278    \def\u{\global\let\jg@cur@acc\jg@breve@acc}%
279    \def\hat##1{\global\let\jg@cur@acc\jg@hat@acc}%
280    \def\dot##1{\global\let\jg@cur@acc\jg@dot@acc}%
281    \def\textasciidieresis{\global\let\jg@cur@acc\jg@ddot@acc}%
282    \let\JGG@orig@rarrow\rightarrow
283    \let\JGG@orig@larrow\leftarrow
284    \def\rightarrow{\global\let\jg@cur@acc\jg@underRarrow@acc}%
285    \def\leftarrow{\global\let\jg@cur@acc\jg@underLarrow@acc}%
286    \def\textoverbrace{\global\let\jg@cur@acc\overbrace}
287    \def\textunderbrace{\global\let\jg@cur@acc\underbrace}
288    \def\jgunderline{\global\let\jg@cur@acc\underline}
289 }

This defines braces as delimiters. The plain.tex file says: N.B. { and } should NOT get delcodes; otherwise parameter grouping fails!

290 \global\delcode`{"66308
291 \global\delcode`}"67309

This is the original definition of the accent commands.

292 \def\jg@tilde@acc{\mathaccent"707E }
293 \def\jg@check@acc{\mathaccent"7014 }
294 \def\jg@breve@acc{\mathaccent"7015 }
295 \def\jg@hat@acc{\mathaccent"705E }
296 \def\jg@dot@acc{\mathaccent"705F }
297 \def\jg@ddot@acc{\mathaccent"707F }
298 \def\jg@grave@acc{\mathaccent"7012 }
299 \def\jg@ring@acc{\protect \mathaccentV {mathring}017 }

Note that when \jg@overRarrow@acc is called, \rightarrow does something strange. We must redefine it here, because \rightarrowfill@ uses it.

300 \def\jg@overRarrow@acc{\let\rightarrow\JGG@orig@rarrow
301   \mathpalette{\overarrow@\rightarrowfill@}}
302 \def\jg@overLarrow@acc{\let\leftarrow\JGG@orig@larrow
303   \mathpalette{\overarrow@\leftarrowfill@}}
304 \def\jg@underRarrow@acc{\let\rightarrow\JGG@orig@rarrow
305    \mathpalette{\underarrow@\rightarrowfill@}}
306 \def\jg@underLarrow@acc{\let\leftarrow\JGG@orig@larrow
307   \mathpalette{\underarrow@\leftarrowfill@}}

3.2.3. More math

This is the main math element. Only the display attribute is taken into account. It can be `inline´ or `block´. If it is block, we use brackets, otherwise parentheses. The original code defined a command \GATHER.

308 \XMLelement{m:math}
309   {\XMLattribute{display}{\XML@mathmlmode}{inline}}
310   {
311      \ifx\XML@mathmlmode\att@BLOCK\[\else\(\fi
312    }
313   {
314      \ifx\XML@mathmlmode\att@BLOCK\]\else\)\fi
315   }

Processing of <m:mfrac linethickness=A numalign=B denomalign=C bevelled=D>num denom</m:mfrac>. We ignore the bevelled attribute. In the current version, we also ignore the horizontal alignment attributes.

316 \XMLelement{m:mfrac}
317   {\XMLattribute{linethickness}{\XML@linethickness}{true}%
318    \XMLattribute{numalign}{\XML@numalign}{center}%
319    \XMLattribute{denomalign}{\XML@denomalign}{center}%
320   }
321   {\xmlgrab}
322   {\xmltextwochildren\xml@implement@frac{}#1}

The auxiliary command.

323 \def\xml@implement@frac#1#2{%
324   \ifx\XML@linethickness\att@true\frac{#1}{#2}%
325   \else \genfrac{}{}\XML@linethickness{}{#1}{#2}\fi

3.2.4. Tables

Processing of <m:mtable atts>body</m:mtable>. The MathML specification says that the following attributes are allowed: align, rowalign, columnalign, groupalign, alignmentscope, columnwidth, width, rowspacing, columnspacing, rowlines, columnlines, frame, framespacing, equalrows, equalcolumns, displaystyle, side, and minlabelspacing. They are currently all ignored. New implementation, dated January 2005.

326 \XMLelement{m:mtable}
327   {}
328   {\xmlgrab }
329   {\jg@start@mtable#1\jg@end@mtable }

Processing of <m:mtr atts>body</m:mtr>. The attributes are: rowalign, columnalign, and groupalign.

330 \XMLelement{m:mtr}
331   {}
332   {\xmlgrab }
333   {\jg@start@mtr#1}

Processing of <m:mtd atts>body</m:mtd>. The attributes are: rowspan, columnspan, rowalign, columnalign, and groupalign.

334 \XMLelement{m:mtd}
335  {\XMLattribute{columnalign}{\XML@mtdalign}{center}
336   \XMLattribute{columnspan}{\XML@mtdspan}{1}}
337  {\xmlgrab}
338  {\jg@start@mtd{#1}}

The current implementation of math tables uses two token lists, one holds the table, the other one holds the current row. The same holds for normal tables, but since normal tables can contain math tables, we need four lists.

339 \newtoks\jg@mtable@toks
340 \newtoks\jg@mrow@toks
341 \newtoks\jg@table@toks
342 \newtoks\jg@row@toks

There is a command \addto@hook that inserts some tokens at the end of a token list; it is similar to \gaddto@hook without the \global. The command \merge@toks appends the current row to the table (action has to be global, because it is executed from the group that defines the row). We also need a command that adds the content of a command to the back of the token list, this is used by normal table when constructing the optional argument of \\.

343 \newcommand\merge@toks[2]{%
344   \expandafter\gaddto@hook\expandafter#1\expandafter{\the#2}}
345 \long\def\gaddto@hook#1#2{\global#1\expandafter{\the#1#2}}
346 \newcommand\merge@cmd[2]{%
347   \expandafter\gaddto@hook\expandafter#1\expandafter{#2}}

When we see the start of a table, we initialize the token list. What we will finally evaluate is an array, declared as *{99}{c}. In the current implementation, it is possible to count the number of columns, and replace 99 by a better value, but this would cost more than constructing a preamble of length 99. We shall see later that, for normal tables, we count the number of columns. Note that, in amsmath, matrices are declared in this way, using the counter MaxMatrixCols, with initial value 10, instead of the constant 99. We initialize the row token list to be empty, and \ifStartTable to true (this means that the next row is the first one).

348 \newif\ifStartTable\newif\ifStartRow
349 \newif\ifStartRowx\newif\ifStartTablex
350 \newcommand\jg@start@mtable{%
351  \jg@mtable@toks{\begin{array}{*{99}{c}}}%
352  \jg@mrow@toks{}%
353  \StartTabletrue}

When the end of the array is seen, we insert the last row and the \end{array} in the token list, then evaluate it.

354 \newcommand\jg@end@mtable{%
355  \merge@toks\jg@mtable@toks\jg@mrow@toks
356  \addto@hook\jg@mtable@toks{\end{array}}%
357  \the\jg@mtable@toks}

When we see the start of a row, we insert the previous row into the table; we reset it; we define the command \ifStartRow to true (this means that the next cell is the first in the row). In the case where \ifStartTable is true, we set it to false, otherwise we add a \\, the row separator, in the array.

358 \newcommand\jg@start@mtr{%
359   \merge@toks\jg@mtable@toks\jg@mrow@toks
360   \ifStartTable
361      \glbal\StartTablefalse
362   \else \gaddto@hook\jg@mtable@toks{\\}\fi
363   \jg@mrow@toks{}%
364   \StartRowtrue}

The main action associated to a cell consists in putting the content in the \jg@row@toks token list; in the case where \ifStartRow is true, we set it to false, otherwise we add a &, the cell separator, in the token list. In \temp, we put the content of our cell, plus some \hfill in the case where alignment is left or right; if alignment is `left´, we insert an empty group after the \hfill (the preamble of the array for our cell is \hfil\ignorespaces#\unskip\hfil). In the general case, there is no need to use a temporary command: we could add the tokens directly into the token list; however, in the case where the span is greater than one, the action is a bit more complicated, in this case, we use a temporary token register.

365 \newcommand\jg@start@mtd[1]{%
366    \ifStartRow
367      \global\StartRowfalse
368    \else\gaddto@hook\jg@mrow@toks{\tabcellsep}\fi
369    \ifx\XML@mtdalign\att@mtd@left
370       \def\temp{#1\hfill{}}%
371     \else\ifx\XML@mtdalign\att@mtd@right
372       \def\temp{\hfill#1}%
373         \else \def\temp{#1}\fi\fi%
374   \ifnum\XML@mtdspan=1\else
375    \toks0=\expandafter{\temp}%
376    \edef\temp{\noexpand\multicolumn{\XML@mtdspan}{c}{\the\toks0}}%
377   \fi
378   \expandafter\gaddto@hook\expandafter\jg@mrow@toks\expandafter{\temp}}

3.3. Other commands

3.3.1. Pictures

In this section, we define some elements that Tralics constructs when evaluating a command from the epic package. These elements are in the default namespace with `pic-´ prefix; in a future version, we will move them in another namespace.

Processing of <picture width=A height=B xpos=C ypos=D>...</picture>. This defines the picture environment. Translation is \begin{picture} (A,B)(C,D) ... \end{picture}.

379 \XMLelement{picture}
380   {\XMLattribute{width}{\XML@width}{1}
381    \XMLattribute{height}{\XML@height}{1}
382    \XMLattribute{xpos}{\XML@xpos}{0}
383    \XMLattribute{ypos}{\XML@ypos}{0}
384   }
385   {\begin{picture}(\XML@width,\XML@height)(\XML@xpos,\XML@ypos)}
386   {\end{picture}}

Processing of <pic-put xpos=A ypos=B>C</pic-put>. We translate this into \put(A,B){C}.

387 \XMLelement{pic-put}
388   {\XMLattribute{xpos}{\XML@xpos}{0}
389    \XMLattribute{ypos}{\XML@ypos}{0}}
390   {\xmlgrab}
391   {\put(\XML@xpos,\XML@ypos){#1}}

Processing of <pic-arc xpos=A ypos=B angle=C></pic-arc>. We translate this in an obvious manner into \arc(A,B){C}.

392 \XMLelement{pic-arc}
393   {\XMLattribute{xpos}{\XML@xpos}{0}
394    \XMLattribute{angle}{\XML@angle}{0}
395    \XMLattribute{ypos}{\XML@ypos}{0}}
396   {\xmlgrab}
397   {\arc(\XML@xpos,\XML@ypos){\XML@angle}}

Processing of <pic-scaleput xpos=A ypos=B  xscale=xs yscale=ys xscaley=xsy yscaley=ysy>C</pic-scaleput>. We translate this into \scaleput(A,B){C}. Other attributes are put in variables named \xscale, \yscale, \xscaley, and \yscalex.

398 \XMLelement{pic-scaleput}
399   {\XMLattribute{xscale}{\xscale}{1.0}
400    \XMLattribute{yscale}{\yscale}{1.0}
401    \XMLattribute{xscaley}{\xscaley}{0.0}
402    \XMLattribute{yscalex}{\yscalex}{0.0}
403    \XMLattribute{xpos}{\XML@xpos}{0}
404    \XMLattribute{ypos}{\XML@ypos}{0}}
405   {\xmlgrab}
406   {\scaleput(\XML@xpos,\XML@ypos){#1}}

Processing of <pic-thicklines/> and <pic-thinlines/>. We call a command, that is executed just after the group. In the case of <pic-linethickness size=V/>, the command takes an argument; we have to expand the value of the attribute, put this in a global variable, and ask for that variable to be expanded after the group. In a first version, we redefined the three commands \thinlines, \thicklines and \linethickness. The current code is simpler.

407 \XMLelement{pic-thicklines}
408   {}{}{\aftergroup\thicklines}

Case of thin lines.

409 \XMLelement{pic-thinlines}
410   {}{}{\aftergroup\thinlines}

Case of line thickness.

411 \XMLelement{pic-linethickness}
412   {\XMLattribute{size}{\XML@size}{1pt}}
413   {}
414   {\xdef\temp{\noexpand\linethickness{\XML@size}}\aftergroup\temp}

Processing of <pic-multiput xpos=A ypos=B repeat=C dx=D dy=E>obj</pic-multiput>. We translate this as \multiput(A,B)(D,E){C}{obj}.

415 \XMLelement{pic-multiput}
416   {\XMLattribute{xpos}{\XML@xpos}{0}
417    \XMLattribute{ypos}{\XML@ypos}{0}
418    \XMLattribute{repeat}{\XML@repeat}{1}
419    \XMLattribute{dx}{\XML@dx}{1}
420    \XMLattribute{dy}{\XML@dy}{1}}
421   {\xmlgrab}
422   {\multiput(\XML@xpos,\XML@ypos)(\XML@dx,\XML@dy){\XML@repeat}{#1}}

Processing of <pic-bezier a1=A1 a2=A2 b1=B1 b2=B2 c1=C1 c2=C2 repeat=D/>. Translation is \qbezier[D](A1,A2)(B1,B2),(C1,C2).

423 \XMLelement{pic-bezier}
424   {\XMLattribute{a1}{\XML@ai}{0}
425    \XMLattribute{a2}{\XML@aii}{0}
426    \XMLattribute{b1}{\XML@bi}{0}
427    \XMLattribute{b2}{\XML@bii}{0}
428    \XMLattribute{c1}{\XML@ci}{0}
429    \XMLattribute{c2}{\XML@cii}{0}
430    \XMLattribute{repeat}{\XML@repeat}{0}}
431   {}
432   {
433    \qbezier[\XML@repeat](\XML@ai,\XML@aii)(\XML@bi,\XML@bii)(\XML@ci,\XML@cii)
434   }

Processing of <pic-line xdir=A ydir=B width=C/>. The translation is \line(A,B){C}.

435 \XMLelement{pic-line}
436   {\XMLattribute{xdir}{\XML@xdir}{0}
437    \XMLattribute{ydir}{\XML@ydir}{0}
438    \XMLattribute{width}{\XML@width}{0}}
439   {}
440   {\line(\XML@xdir,\XML@ydir){\XML@width}}

Processing of <pic-vector xdir=A ydir=B width=C/>. The translation is \vector(A,B){C}.

441 \XMLelement{pic-vector}
442   {\XMLattribute{xdir}{\XML@xdir}{0}
443    \XMLattribute{ydir}{\XML@ydir}{0}
444    \XMLattribute{width}{\XML@width}{0}}
445   {}
446   {\vector(\XML@xdir,\XML@ydir){\XML@width}}

Processing of <pic-curve unit-length=A>B</pic-curve>. The translation is \curve(B). There are two hacks here: one is that \curve modifies \unitlength globally, so that we have to reset it. The other hack is that \ignorespaces must be ignored: the argument of \curve is a sequence of numbers, converted to dimensions by using \unitlength. Between a sequence of digits and a unit of measure, spaces are allowed (but here, spaces are active, there expansion is: space plus \ignorespaces).

447 \newdimen\jgunitlength
448 \newcommand\withulength[1]{%
449   {\def\ignorespaces{}%
450    \jgunitlength=\unitlength \setlength\unitlength{\XML@ulength pt}%
451    #1\global\unitlength\jgunitlength}}
453 \XMLelement{pic-curve}
454   {\XMLattribute{unit-length}{\XML@ulength}{1}}
455   {\xmlgrab}
456   {\withulength{\curve(#1)}}

Processing of <pic-closecurve unit-length=A>B</pic-closecurve>. With the same hack as above, the translation is \closecurve(B).

457 \XMLelement{pic-closecurve}
458   {\XMLattribute{unit-length}{\XML@ulength}{1}}
459   {\xmlgrab}
460   {\withulength{\closecurve(#1)}}

Processing of <pic-tagcurve unit-length=A>B</pic-tagcurve>. With the same hack as above, the translation is \tagcurve(B).

461 \XMLelement{pic-tagcurve}
462   {\XMLattribute{unit-length}{\XML@ulength}{1}}
463   {\xmlgrab}
464   {\withulength{\tagcurve(#1)}}

Processing of <pic-frame>X</pic-frame>. Translation is \frame{X}.

465 \XMLelement{pic-frame}
466  {}
467  {\xmlgrab}
468  {\frame{#1}}

Processing of <pic-circle size=A full=B/>. Translation is \circle{A} or \circle*{A}. A star is used B is given and not `false´.

469 \XMLelement{pic-circle}
470   {\XMLattribute{size}{\XML@size}{1}
471    \XMLattribute{full}{\XML@full}{false}}
472   {}
473   {\ifx\XML@full\att@false\circle{\XML@size}\else \circle*{\XML@size}\fi}

Processing of <pic-circle size=A unit-length=B/>. Translation is \bigcircle{A}. We locally change \unitlength.

474 \XMLelement{pic-bigcircle}
475   {\XMLattribute{size}{\XML@size}{1}
476    \XMLattribute{unit-length}{\XML@ulength}{1}}
477   {}
478   {\withulength{\bigcircle{\XML@size}}}

The strings defined here are needed in the next command.

479 \XMLstring\att@l<>l</>
480 \XMLstring\att@r<>r</>
481 \XMLstring\att@t<>t</>
482 \XMLstring\att@b<>b</>
483 \XMLstring\att@lt<>lt</>
484 \XMLstring\att@lb<>lb</>
485 \XMLstring\att@rt<>rt</>
486 \XMLstring\att@rb<>rb</>
487 \XMLstring\att@tl<>tl</>
488 \XMLstring\att@bl<>bl</>
489 \XMLstring\att@tr<>tr</>
490 \XMLstring\att@br<>br</>

Given a string A, in \XML@pos, we construct a string B, that has the same characters (order is irrelevant), with category code 11. Moreover, if we have a command \bar and an argument gee, we evaluate \bar[B]{gee} (in fact, we construct a command that does this; this command will be evaluated after all conditionals have been closed.)

491 \def\@att@to@rtb#1#2{%
492   \ifx\XML@pos\att@l \def\jg@tmp{#1[l]{#2}}
493   \else\ifx\XML@pos\att@r \def\jg@tmp{#1[r]{#2}}%
494   \else\ifx\XML@pos\att@t \def\jg@tmp{#1[t]{#2}}%
495   \else\ifx\XML@pos\att@b \def\jg@tmp{#1[b]{#2}}%
496   \else\ifx\XML@pos\att@lt \def\jg@tmp{#1[lt]{#2}}%
497   \else\ifx\XML@pos\att@lb \def\jg@tmp{#1[lb]{#2}}%
498   \else\ifx\XML@pos\att@rt \def\jg@tmp{#1[rt]{#2}}%
499   \else\ifx\XML@pos\att@rb \def\jg@tmp{#1[rb]{#2}}%
500   \else\ifx\XML@pos\att@tl \def\jg@tmp{#1[lt]{#2}}%
501   \else\ifx\XML@pos\att@bl \def\jg@tmp{#1[lb]{#2}}%
502   \else\ifx\XML@pos\att@tr \def\jg@tmp{#1[rt]{#2}}%
503   \else\ifx\XML@pos\att@br \def\jg@tmp{#1[rb]{#2}}%
504   \else \def\jg@tmp{#1{#2}}
505  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
506  \jg@tmp
507 }

Processing <pic-framebox width=A height=B position=C framed=D>obj</pic-framebox>. The translation is \framebox(A,B)[CC]{obj} (it could be \makebox if the attribute framed is false). Here CC is the value of C, processed as indicated above.

508 \XMLelement{pic-framebox}
509   {\XMLattribute{width}{\XML@width}{0}
510    \XMLattribute{height}{\XML@height}{0}
511    \XMLattribute{position}{\XML@pos}{}
512    \XMLattribute{framed}{\XML@framed}{false}
513   }
514  {\xmlgrab}
515  {\let\cmd\framebox\ifx\XML@framed\att@false\let\cmd\makebox\fi
516   \@att@to@rtb{\cmd(\XML@width,\XML@height)}{#1}}

Processing <pic-dashbox width=A height=B position=C dashdim=D> obj </pic-dashbox>. The translation is \dashbox{D}(A,B)[CC]{obj}, where CC is as above.

517 \XMLelement{pic-dashbox}
518   {\XMLattribute{width}{\XML@width}{0}
519    \XMLattribute{height}{\XML@height}{0}
520    \XMLattribute{position}{\XML@pos}{w}
521    \XMLattribute{dashdim}{\XML@dashdim}{1pt}
522   }
523  {\xmlgrab}
524  {\@att@to@rtb{\dashbox{\XML@dashdim}(\XML@width,\XML@height)}{#1}}

Processing of <pic-oval xpos=A ypos=B specs=C>obj</pic-oval>.

The translation is \oval(A,B)[CC]{obj}, where CC is as above.

525 \XMLelement{pic-oval}
526   {\XMLattribute{xpos}{\XML@xpos}{0}
527    \XMLattribute{specs}{\XML@pos}{}
528    \XMLattribute{ypos}{\XML@ypos}{0}}
529   {\xmlgrab}
530   {\@att@to@rtb{\oval(\XML@xpos,\XML@ypos)}{#1}}

3.3.2. Titlepage

We found no easy way to describe the title page of the Raweb using XSL/Format; thus additional elements were invented and described here. The \ra@atxy command adds a box (that occupies no space) at a give position in the page (the position is absolute).

531 \newbox\ra@atxybox
532 \def\ra@atxy(#1,#2)#3{\global\setbox\ra@atxybox=\hbox
533  {\unhbox\ra@atxybox
534   \vtop to 0pt{\kern #2\hbox to 0pt{\kern #1\relax #3\hss}\vss}}}

We use \@texttop (a command that does nothing)(note: ) for insertion of our box. After that, we kill our command. We have to shift horizontally by 1in plus \hoffset and the current margin, vertically by 1in, plus \voffset plus \headheight plus \headsep plus \topmargin.

535 \def\ra@useatxy{{%
536   \let\@themargin\oddsidemargin
537   \vtop to 0pt{\kern-\headsep \kern-\topmargin \kern-\headheight
538                \kern-1in \kern-\voffset
539     \hbox to 0pt{\kern-\@themargin \kern-1in \kern-\hoffset
540     \unhbox\ra@atxybox \hss}\vss}}%
541     \global\let\@texttop\relax}

The command \firstchar is nowadays useless. In the times when Inria themes were 1A, 1B, 2A, 2B etc, we used it to remove the letter. Nowadays themes are NUM, COG, etc, and we hope people give only the theme.(note: ) We insert the logo, and, above it, the theme with some rules.

542 \def\foratheme#1{\vskip8cm \vfil
543   \ra@atxy(74mm,175mm) {\hbox to 70mm{%
544        \hrulefill\hspace{8mm}
545        \def\firstchar##1##2\relax{##1##2} % ducon
546        \href{
547          _\firstchar#1\relax.en.html}{THEME \uppercase{#1}}%
548        \hspace{8mm}\hrulefill}}}

Start of the title page.

549 \def\foinria{%
550   \ra@atxy(7.8cm,2.5cm){\includegraphics[width=5.7cm]{Logo-INRIA-couleur}}%
551   \ra@atxy(55mm,173mm){\includegraphics{LogoRA\ra@year}}%
552  \setbox0\hbox to 14cm{%
553      \noindent\hskip3cm\hfill
554      {\fontencoding{T1}\fontfamily{ptm}\fontseries{m}%
555    \fontshape{n}\fontsize{10pt}{12pt}\selectfont
558       \hskip-5cm\hfill}%
559   \null\vskip0.7cm \leavevmode\hskip-3.5cm\box0\null\vskip2cm\vfil}

This is a hack: we just want \cleardoublepage. This is not used anymore.

560 \XMLelement{cleardoublepage}
561  {} {\cleardoublepage} {}

This is a hack: we want a rule below the page headings. We found no other way. This is not used anymore.

562 \XMLelement{pagestylehrule}
563  {} {\hbox to0pt{\rule[-1ex]{\textwidth}{.03cm}\hss}} {}

3.3.3. Images

For the HTML version of the Raweb, we convert all math formulas into images. The idea is to construct an XML file that contains a <formula> for each object to convert. This file is translated by TeX into a dvi file, containing one formula per page; after that the dvi is converted to PostScript then png, or some other image format recognized by HTML.

A non trivial problem is the size of the image. When TeX translates the formula, it creates a box, and prints the dimension of the box on the transcript file. We want the baseline of the image to be aligned with the baseline of the text, but HTML provides only `center´ or `bottom´ as alignment options; for this reason, if the alignment cannot be `bottom´, said otherwise, if the depth of the box is non-zero, we add some blank space so that the height and depth will be the same. If two much space is added, this is not a good thing to do.

Assume that x is (a bit more than) the maximum of the height and depth of \sizebox. We modify the height and depth to be x; we insert a vertical invisible rule of height x and depth x. This code is not used any more.

  \dimen1=\ifdim\ht\sizebox<\dp\sizebox \dp\sizebox\else\ht\sizebox\fi
  \advance\dimen1by.5pt \vrule width0pt height\dimen1 depth\dimen1

We noticed that if the images contains a single table, it is not vertically centered. In fact, the following code

$\vcenter{\vrule height 0pt depth5pt width2pt}$

produces a box of height 5pt, and depth 0pt (for details, see TeXbook, appendix G, rule 8: the distance between the center of the box and the baseline is parameter σ 22 of the current math font). In fact, the \vcenter command is designed for math mode only, and the the distance between the center of the box and the math axis is zero.

In a first version, we used the `E´ option of dvips; this produces a set of PostScript files, one for each formula, with the correct bounding box. This bounding box is computed by dvips, according to characters and rules of the dvi file. If the TeX file contains a \special command that asks a PostScript interpreter to draw a circle of radius R, and an empty box that has the size of the circle, followed by some text, then you will see the circle followed by the text when viewing the PostScript file; but dvips is not a PostScript interpreter and has no idea of the size of the circle.

We solve this problem by adding two rules, one at the left of the image and one below. If everything works correctly, conversion from PostScript to png will remove them, but this is not always the case. The code is taken from latex2html, it has a strange feature. In the case of overflow, only the vertical rule is added. This is the code that adds rules to the box in \sizebox.

 \hbox{\vrule width1pt\kern-.5pt\vtop{\vbox{%
  \kern1pt\kern0.6 pt\hbox{\hglue1.7pt\copy\sizebox\hglue0.6 pt}}\kern.3pt%
  \ifdim\dp\sizebox>0pt\kern1pt\fi \kern0.6 pt%
  \ifdim\hsize>\wd\sizebox \hrule depth1pt\fi}}%

Assume that (x,y) is the position of the upper left corner of the image, (X,Y) are the dimensions of the image. If ϵ is the width of the rule plus the distance to the image, then the bounding box of the page will be x-ϵ, x+X, y, y+Y+ϵ. These quantities can be computed by dvips; it is then obvious to remove the two rules.

We now use a different method. The bounding box is not computed anymore by dvips; we call an external program with the parameters x, y, X and Y. This program has a comment that says: should (x,y) be (78,72) or (72,72) ? but it uses (62,41); if pstoimg is unavailable, then convert is used with (64, 44). Remember that TeX puts its origin at 1in (this is 72pt) from the upper left corner, but we have no idea what the current margins could be. If we ask TeX what it puts on the dvi, we see that the main vertical box contains 16pt of glue, and a box shifted by 62pt, this one starts with a header, then 25pt of glue. After that we see a vbox containing some kerns: -25pt, -16pt, -12pt, and two kerns with sum 0, and absolute value 72.27pt. We also noticed that the message Underfull \hbox (badness 10000) has occurred while \output is active [][][][] printed on each page is a consequence of loading the hyperref package, that tries to put something in the header (which is empty, of course); as a consequence, we have patched the file, so that the hyperref package is not loaded in the case were we just want to convert a piece of XML into an image.

The result is cropped. This means: if Y is too big, a smaller value will be used; in particular this will remove the additional blank space added (as explained above for vertical centering). We simplified a bit the algorithm: no rules are printed, the size is no more adjusted.

There are two elements <formula> and <tree> that produce images. A formula contains a <math> element, and a tree contains a table (that defines the nodes and their layout) together with the connections. When we see a formula in a table, we simply ignore it (we typeset the math). Nothing special has to be done for math formulas, because they contain no tables, no trees (only MathML stuff).

Here we translate <formula id=A>math</formula>; the id attribute is the number of the image.

564 \XMLelement{formula}
565  {\XMLattribute{id}{\XML@formid}{none}}
566  {\formula@start}
567  {\formula@end}

The two commands \@inlinemathA and \@inlinemathZ are used to start and finish a math image; originally, they were used directly in the code of <formula>. When we evaluate a <tree>, we must change these two commands.

568 \def\formula@start{\@inlinemathA{\XML@formid}}
569 \let\formula@end\@inlinemathZ

There are two differences between a tree and a formula. To start with, we do not have a tree number, so that we invent one; in reality, the tree number is irrelevant. The second difference is that nodes in a tree can be connected by non-straight lines; as a consequence the size needed by the tree is bigger than the size of the table. We allow a kern at the left of the table and below the table.

570 \XMLelement{tree}
571  {\XMLattribute{hpos}{\XML@hpos}{0pt}
572    \XMLattribute{vpos}{\XML@vpos}{0pt}
573  }
574  {
575  \stepcounter{treecounter}
576  \let\formula@start\relax
577  \let\formula@end\relax
578  \startdimen=\XML@hpos
579  \enddimen=\XML@vpos
580  \@inlinemathA{\thetreecounter}}
581  {\@inlinemathZ}

It may happen that space must be added around the object. Currently, we need space on the left and bottom, thus we declare these two variables. Since assignment is local, there is no need to reset them.

582 \newdimen\startdimen
583 \newdimen\enddimen

For some strange reasons, the fotex.sty file says that eps files should be included by converting them into pdf; this works for pdfTeX, but not for LaTeX. We make sure here that this rule is never applied.

584 \newbox\sizebox
585 \AtBeginDocument{
586 \@namedef{Gin@rule@.eps}#1{{eps}{.eps}{#1}}

We redefine \normalsize, in the same way as latex2html. This is really, really, strange.

587 \let\realnormalsize=\relax
588 \def\adjustnormalsize{%
589   \def\normalsize{\mathsurround=0pt \realnormalsize
590    \parindent=0pt\abovedisplayskip=0pt\belowdisplayskip=0pt}%
591   \def\phantompar{\csname par\endcsname}%
592   \normalsize}}

The action at the start of a formula is the following: we remember the id somewhere, we start a new page, and we construct a box; this box will start with a strut and some space.

593 \def\@inlinemathA#1{%
594   \xdef\@mathenv{#1}%
595   \adjustnormalsize \newpage\clearpage
596   \setbox\sizebox=\hbox\bgroup
597   \vrule height1.5ex width0pt
598   \kern\startdimen }

This is done at the end. The action is the following: we terminate the box, we modify the depth of the box in the case additional vertical space is needed, and print the dimensions on the log file. We insert the box on the current page and start a new one.

599 \def\@inlinemathZ{%
600   \egroup
601   \ifdim\enddimen>0pt
602     \dimen1=\dp\sizebox\advance\dimen1by \enddimen\dp\sizebox=\dimen1
603   \fi
604   \typeout{l2hSize %
605     :\@mathenv:\the\ht\sizebox::\the\dp\sizebox::\the\wd\sizebox.}
606   \box\sizebox
607   \clearpage
608 }

3.3.4. Trees

A tree is defined by a set of nodes, together with connections. The elements here are handled by the tree-dvips package, using commands described in part I of this report. All elements, except <node> have an empty content. Translation of element <foo> is in general \foo, with arguments depending on the attributes.

The content of a <node> is typeset normally, it has an a name attribute, that identifies it uniquely (On each page in the PostScript file, there is a unique node with a given name).

609 \XMLelement{node}
610  {\XMLattribute{name}{\XML@name}{somename}}
611  {\xmlgrab}
612  {\node{\XML@name}{#1}}

A <nodepoint> element has a name, and two optional attributes xpos, ypos.

613 \XMLelement{nodepoint}
614  {\XMLattribute{name}{\XML@name}{somenode}
615   \XMLattribute{xpos}{\XML@xpos}{0pt}
616   \XMLattribute{ypos}{\XML@ypos}{0pt}}
617  {\xmlgrab}
618  {\nodepoint{\XMl@name}[\XML@xpos][\XML@ypos]}

A <nodebox> element has a nameA attribute. The effect is to add a frame around the node defined by the name.

619 \XMLelement{nodebox}
620  {\XMLattribute{nameA}{\XML@nameA}{somenode}
621  }
622  {\xmlgrab}
623  {\nodebox{\XML@nameA}}

A <nodeoval> element has a nameA attribute. The effect is to put an oval around the node defined by the name.

624 \XMLelement{nodeoval}
625  {\XMLattribute{nameA}{\XML@nameA}{somenode}
626  }
627  {\xmlgrab}
628  {\nodeoval{\XML@nameA}}

A <nodecircle> element has a nameA attribute. The effect is to put an circle around the node defined by the name. There is another attribute depth that specifies a parameter of the circle.

629 \XMLelement{nodecircle}
630  {\XMLattribute{nameA}{\XML@nameA}{somenode}
631   \XMLattribute{depth}{\XML@depth}{0pt}
632  }
633  {\xmlgrab}
634  {\nodecircle[\XML@depth]{\XML@nameA}}

A <nodetriangle> element has two names, nameA and nameB. The effect is to insert a triangle between the nodes defined by the names.

635 \XMLelement{nodetriangle}
636  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
637   \XMLattribute{nameB}{\XML@nameB}{nodeB}
638  }
639  {\xmlgrab}
640  {\nodetriangle{\XML@nameA}{\XML@nameB}}

Both elements <nodeconnect> and <anodeconnect> have a nameA and nameB attributes; the effect is to connect the nodes defined by the names; if the first letter of the element is a, there will be an arrow. The attributes posA and posB explain the positions of the connection, it can be one of top, bottom, left, right, or a combination. For instance `br´ stands for bottom right. This is the reverse order of that chosen for pictures in section 3.3.1, but we check nothing here.

641 \XMLelement{nodeconnect}
642  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
643   \XMLattribute{nameB}{\XML@nameB}{nodeB}
644   \XMLattribute{posA}{\XML@posA}{b}
645   \XMLattribute{posB}{\XML@posB}{t}
646  }
647  {\xmlgrab}
648  {\nodeconnect[\XML@posA]{\XML@nameA}[\XML@posB]{\XML@nameB}}
650 \XMLelement{anodeconnect}
651  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
652   \XMLattribute{nameB}{\XML@nameB}{nodeB}
653   \XMLattribute{posA}{\XML@posA}{b}
654   \XMLattribute{posB}{\XML@posB}{t}
655  }
656  {\xmlgrab}
657  {\anodeconnect[\XML@posA]{\XML@nameA}[\XML@posB]{\XML@nameB}}

Both elements <barnodeconnect> and <abarnodeconnect> have a nameA and nameB attributes; the effect is to connect the nodes defined by the names; if the first letter of the element is a, there will be an arrow. The attribute depth is optional.

658 \XMLelement{barnodeconnect}
659  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
660   \XMLattribute{nameB}{\XML@nameB}{nodeB}
661   \XMLattribute{depth}{\XML@depth}{5pt}
662  }
663  {\xmlgrab}
664  {\barnodeconnect[\XML@depth]{\XML@nameA}{\XML@nameB}}
666 \XMLelement{abarnodeconnect}
667  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
668   \XMLattribute{nameB}{\XML@nameB}{nodeB}
669   \XMLattribute{depth}{\XML@depth}{5pt}
670  }
671  {\xmlgrab}
672  {\abarnodeconnect[\XML@depth]{\XML@nameA}{\XML@nameB}}

Both elements <nodecurve> and <anodecurve> have a nameA and nameB attributes; the effect is to connect the nodes defined by the names; if the first letter of the element is a, there will be an arrow. The attributes depthA and depthB are optional.

673 \XMLelement{nodecurve}
674  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
675   \XMLattribute{nameB}{\XML@nameB}{nodeB}
676   \XMLattribute{posA}{\XML@posA}{b}
677   \XMLattribute{posB}{\XML@posB}{t}
678   \XMLattribute{depthA}{\XML@depthA}{5pt}
679   \XMLattribute{depthB}{\XML@depthB}{5pt}
680  }
681  {\xmlgrab}
682  {\nodecurve[\XML@posA]{\XML@nameA}[\XML@posB]{\XML@nameB}{\XML@depthA}[\XML@depthB]}
684 \XMLelement{anodecurve}
685  {\XMLattribute{nameA}{\XML@nameA}{nodeA}
686   \XMLattribute{nameB}{\XML@nameB}{nodeB}
687   \XMLattribute{posA}{\XML@posA}{b}
688   \XMLattribute{posB}{\XML@posB}{t}
689   \XMLattribute{depthA}{\XML@depthA}{5pt}
690   \XMLattribute{depthB}{\XML@depthB}{5pt}
691  }
692  {\xmlgrab}
693  {\anodecurve[\XML@posA]{\XML@nameA}[\XML@posB]{\XML@nameB}{\XML@depthA}[\XML@depthB]}

3.3.5. Tables

We use the same method for normal tables as for math table, said otherwise, we read everything, construct the code, and finally evaluate it. This piece of code is only used for trees, so that we assume that cells have no borders. We could handle all attributes.

A <table> has a unique attribute vpos, currently unused.

694 \XMLelement{table}
695   {\XMLattribute{vpos}{\XML@vpos}{b}}
696   {\xmlgrab }
697   {\jg@start@table#1\jg@end@table }

A <row> can have lots of attributes, but we consider only one; it defines the vertical space after the current row.

698 \XMLelement{row}
699   {\XMLattribute{spaceafter}{\XML@spaceafter}{0pt}}
700   {\xmlgrab }
701   {\jg@start@tr#1}

Attributes right-border, left-border, halign and rows are declared for a <cell>, but only cols is used (this is the number of effective columns spanned by the cell).

702 \XMLelement{cell}
703  {\XMLattribute{cols}{\XML@cols}{1}
704   \XMLattribute{rows}{\XML@rows}{1}
705   \XMLattribute{halign}{\XML@halign}{center}
706   \XMLattribute{right-border}{\XML@rightborder}{false}
707   \XMLattribute{left-border}{\XML@leftborder}{false}
708  }
709  {\xmlgrab}
710  {\jg@start@td{#1}}

Action when we start a table. We kill the two token lists, and say that we are at the start of the table. For our application, we need a lot of space between rows, so that \arraystretch is redefined to some value; an intermediate macro is used, it can be redefined, for instance at begin-document, by a config file. The redefinition is local.

711 \def\@myarraystretch{1.7}%
712 \newcounter{localcolcounter}
713 \newcounter{globalcolcounter}
715 \newcommand\jg@start@table{%
716  \let\arraystretch\@myarraystretch
717  \jg@table@toks{}%
718  \jg@row@toks{}%
719  \setcounter{globalcolcounter}{1}%
720  \StartTablextrue}

Action when we see the end of a table. Since we are at the end of the table, we know the number of columns of the last row, so that we can compute the number of columns of the table. After that, we insert the last row to the table. We insert the \begin and \end commands, then evaluate everything.

721 \newcommand\jg@end@table{%
722  \ifnum\value{localcolcounter}>\value{globalcolcounter}%
723  \setcounter{globalcolcounter}{\value{localcolcounter}}\fi
724  \merge@toks\jg@table@toks\jg@row@toks
725  \addto@hook\jg@table@toks{\end{tabular}}%
726  \edef\foo{\noexpand\begin{tabular}{*{\theglobalcolcounter}{c}}%
727    \the\jg@table@toks}%
728  \foo}

Action when we see the start of a row. We insert the content of the row token list to the table, and clear it. If this is not the first row of the table, we insert a double backslash, plus its optional argument; the current column counter is the number of columns of this row, and from this we deduce the current number of columns of the table. In any case, we compute the optional argument to be inserted at the end of the row, we say that the number of columns of this row is zero, and we are at the start of the row.

729 \newcommand\jg@start@tr{%
730   \merge@toks\jg@table@toks\jg@row@toks
731   \ifStartTablex
732      \global\StartTablexfalse
733   \else
734     \gaddto@hook\jg@table@toks{\\}%
735     \merge@cmd\jg@table@toks\Rowsep
736     \ifnum\value{localcolcounter}>\value{globalcolcounter}%
737     \setcounter{globalcolcounter}{\value{localcolcounter}}\fi
738   \fi
739   \jg@row@toks{}%
740   \ifdim\XML@spaceafter=0pt  \gdef\Rowsep{}\else
741   \xdef\Rowsep{[\XML@spaceafter]}\fi
742   \setcounter{localcolcounter}{0}%
743   \global\StartRowxtrue}

Action when we see a cell (in the argument of the command). If this not the first cell of the row, we insert an ampersand character (in \tabcellsep). We increment the current column number by N, the span; if this is not one, we must use \multicolumn.

744 \newcommand\jg@start@td[1]{%
745    \ifStartRowx\global\StartRowxfalse
746    \else \gaddto@hook\jg@row@toks{\tabcellsep}\fi
747   \addtocounter{localcolcounter}{\XML@cols}%
748    \ifx\XML@mtdalign\att@mtd@left
749       \def\temp{#1\hfill{}}%
750     \else\ifx\XML@mtdalign\att@mtd@right
751       \def\temp{\hfill#1}%
752         \else \def\temp{#1}\fi\fi%
753   \ifnum\XML@cols=1 \else
754    \toks0=\expandafter{\temp}%
755    \edef\temp{\noexpand\multicolumn{\XML@cols}{c}{\the\toks0}}%
756   \fi
757   \expandafter\gaddto@hook\expandafter\jg@row@toks\expandafter{\temp}}

3.3.6. Other commands

The <hi> element has a rend attribute that indicates how to typeset the content; we use \csname for dispatching.

758 \XMLelement{hi}
759  {\XMLattribute{rend}{\XML@rend}{rm}}
760  {\xmlgrab}
761  {\csname rend@\XML@rend\endcsname{#1}}

In order to be complete, we should implement all font commands.

762 \let\rend@it\textit
763 \let\rend@bf\textbf
764 \let\rend@rm\textrm
765 \def\rend@small#1{{\small #1}}
766 \def\rend@sub#1{\textsubscript{#1}}
767 \let\rend@sup\textsuperscriptscript

We want TeX and LaTeX to typeset properly.

768 \XMLelement{TeX}
769   {}{\TeX{}}{}
771 \XMLelement{LaTeX}
772   {}{\LaTeX{}}{}

We use this for producing little images.

773 \XMLelement{preview}
774   {}
775   {\begin{preview}}
776   {\end{preview}}

Some attribute definitions.

777 \XMLstring\att@true<>true</>
778 \XMLstring\att@false<>false</>
779 \XMLstring\jg@OverBrace<>&#xFE37;</>
780 \XMLstring\jg@UnderBrace<>&#xFE38;</>
781 \XMLstring\jg@OverBar<>&#xAF;</>
782 \XMLstring\jg@UnderBAr<>&#x332;</>
783 \XMLstring\att@mtd@left<>left</>
784 \XMLstring\att@mtd@right<>right</>
785 \XMLstring\att@mtd@center<>center</>
786 \XMLstring\att@none<>none</>
787 \XMLstring\att@dzero<>0</>
788 \XMLstring\att@done<>1</>
789 \XMLstring\att@dtwo<>2</>
790 \XMLstring\att@mathml@rm<>rm</>
791 \XMLstring\att@BLOCK<>block</>
792 \XMLstring\att@PREFIX<>prefix</>
793 \XMLstring\att@EQUATION<>equation</>
794 \XMLstring\att@sub<>sub</>

Some commands must be redefined at start of document. Note: the Unicode character 3F5 is `greek unate epsilon symbol´, we translate it as ϵ, the character 3B5 `greek small letter epsilon´ is translated as ε.

795 \AtBeginDocument{
796   \UnicodeCharacter{x332}{\jgunderline}
797   \UnicodeCharacter{x3F5}{\epsilon}
798   \UnicodeCharacter{x3B5}{\varepsilon}
799   \let\downslopeellipsis\ddots
800   \mathchardef\Rightarrow="3229
801   \let\@texttop\ra@useatxy
802   \let\XURL\relax
803   \selectlanguage{english}
804   \let\@item\jg@item
805 }

3.4. The fotex.cfg file

The fotex.cfg file contains the definitions of some elements. Two of them are used by the Raweb. The action associated to these elements is shown above.

806 \XMLelement{fo:RATHEME}
807   {}
808   {\xmlgrab}
809   {\foratheme{#1}}
811 \XMLelement{fo:INRIA}
812   {\XMLattribute{year}{\ra@@year}{2001}}
813   {}
814   {\xdef\ra@year{\ra@@year}\foinria}
Back to main page