1 /*
2 blahtex: a TeX to MathML converter designed with MediaWiki in mind
3 blahtexml: an extension of blahtex with XML processing in mind
4 http://gva.noekeon.org/blahtexml
5
6 Copyright (c) 2006, David Harvey
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
10
11 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
13 * Neither the names of the authors nor the names of their affiliation may be used to endorse or promote products derived from this software without specific prior written permission.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 */
17
18 #include <stdexcept>
19 #include "ParseTree.h"
20
21 using namespace std;
22
23 namespace blahtex
24 {
25
26 pair<wstring, wchar_t> lowercaseGreekArray[] =
27 {
28 make_pair(L"\\alpha", L'\U000003B1'),
29 make_pair(L"\\beta", L'\U000003B2'),
30 make_pair(L"\\gamma", L'\U000003B3'),
31 make_pair(L"\\delta", L'\U000003B4'),
32 make_pair(L"\\epsilon", L'\U000003F5'), // straightepsilon
33 make_pair(L"\\varepsilon", L'\U000003B5'), // varepsilon
34 make_pair(L"\\zeta", L'\U000003B6'),
35 make_pair(L"\\eta", L'\U000003B7'),
36 make_pair(L"\\theta", L'\U000003B8'),
37 make_pair(L"\\vartheta", L'\U000003D1'),
38 make_pair(L"\\iota", L'\U000003B9'),
39 make_pair(L"\\kappa", L'\U000003BA'),
40 make_pair(L"\\varkappa", L'\U000003F0'),
41 make_pair(L"\\lambda", L'\U000003BB'),
42 make_pair(L"\\mu", L'\U000003BC'),
43 make_pair(L"\\nu", L'\U000003BD'),
44 make_pair(L"\\pi", L'\U000003C0'),
45 make_pair(L"\\varpi", L'\U000003D6'),
46 make_pair(L"\\rho", L'\U000003C1'),
47 make_pair(L"\\varrho", L'\U000003F1'),
48 make_pair(L"\\sigma", L'\U000003C3'),
49 make_pair(L"\\varsigma", L'\U000003C2'),
50 make_pair(L"\\tau", L'\U000003C4'),
51 make_pair(L"\\upsilon", L'\U000003C5'),
52 make_pair(L"\\phi", L'\U000003D5'), // straightphi
53 make_pair(L"\\varphi", L'\U000003C6'),
54 make_pair(L"\\chi", L'\U000003C7'),
55 make_pair(L"\\psi", L'\U000003C8'),
56 make_pair(L"\\omega", L'\U000003C9'),
57 make_pair(L"\\xi", L'\U000003BE'),
58 make_pair(L"\\digamma", L'\U000003DD')
59 };
60 wishful_hash_map<wstring, wchar_t> lowercaseGreekTable(
61 lowercaseGreekArray,
62 END_ARRAY(lowercaseGreekArray)
63 );
64
65
66 pair<wstring, wchar_t> uppercaseGreekArray[] =
67 {
68 make_pair(L"\\Gamma", L'\U00000393'),
69 make_pair(L"\\Delta", L'\U00000394'),
70 make_pair(L"\\Theta", L'\U00000398'),
71 make_pair(L"\\Lambda", L'\U0000039B'),
72 make_pair(L"\\Pi", L'\U000003A0'),
73 make_pair(L"\\Sigma", L'\U000003A3'),
74 make_pair(L"\\Upsilon", L'\U000003A5'),
75 make_pair(L"\\Phi", L'\U000003A6'),
76 make_pair(L"\\Psi", L'\U000003A8'),
77 make_pair(L"\\Omega", L'\U000003A9'),
78 make_pair(L"\\Xi", L'\U0000039E')
79 };
80 wishful_hash_map<wstring, wchar_t> uppercaseGreekTable(
81 uppercaseGreekArray,
82 END_ARRAY(uppercaseGreekArray)
83 );
84
85
86 pair<wstring, int> spaceArray[] =
87 {
88 make_pair(L"\\!", -3),
89 make_pair(L"\\,", 3),
90 make_pair(L"\\>", 4),
91 make_pair(L"\\;", 5),
92 make_pair(L"\\quad", 18),
93 make_pair(L"\\qquad", 36),
94 // These last two aren't quite right, but hopefully they're close
95 // enough. TeX's rules are too complicated for me to care :-)
96 make_pair(L"~", 6),
97 make_pair(L"\\ ", 6)
98 };
99 wishful_hash_map<wstring, int> spaceTable(
100 spaceArray,
101 END_ARRAY(spaceArray)
102 );
103
104
105 struct OperatorInfo
106 {
107 wstring mText;
108 LayoutTree::Node::Flavour mFlavour;
109 LayoutTree::Node::Limits mLimits;
110
OperatorInfoblahtex::OperatorInfo111 OperatorInfo(
112 const wstring& text,
113 LayoutTree::Node::Flavour flavour,
114 LayoutTree::Node::Limits limits =
115 LayoutTree::Node::cLimitsDisplayLimits
116 ) :
117 mText(text),
118 mFlavour(flavour),
119 mLimits(limits)
120 { }
121 };
122
123 // Here is a list of all commands that get translated as operators,
124 // together with their MathML translation and flavour.
125 pair<wstring, OperatorInfo> operatorArray[] =
126 {
127 make_pair(L"(", OperatorInfo(L"(", LayoutTree::Node::cFlavourOpen)),
128 make_pair(L")", OperatorInfo(L")", LayoutTree::Node::cFlavourClose)),
129 make_pair(L"[", OperatorInfo(L"[", LayoutTree::Node::cFlavourOpen)),
130 make_pair(L"]", OperatorInfo(L"]", LayoutTree::Node::cFlavourClose)),
131 make_pair(L"<", OperatorInfo(L"<", LayoutTree::Node::cFlavourRel)),
132 make_pair(L">", OperatorInfo(L">", LayoutTree::Node::cFlavourRel)),
133 make_pair(L"+", OperatorInfo(L"+", LayoutTree::Node::cFlavourBin)),
134 make_pair(L"-", OperatorInfo(L"-", LayoutTree::Node::cFlavourBin)),
135 make_pair(L"=", OperatorInfo(L"=", LayoutTree::Node::cFlavourRel)),
136 make_pair(L"|", OperatorInfo(L"|", LayoutTree::Node::cFlavourOrd)),
137 make_pair(L";", OperatorInfo(L";", LayoutTree::Node::cFlavourPunct)),
138 make_pair(L":", OperatorInfo(L":", LayoutTree::Node::cFlavourRel)),
139 make_pair(L",", OperatorInfo(L",", LayoutTree::Node::cFlavourPunct)),
140 make_pair(L".", OperatorInfo(L".", LayoutTree::Node::cFlavourOrd)),
141 make_pair(L"/", OperatorInfo(L"/", LayoutTree::Node::cFlavourOrd)),
142 make_pair(L"?", OperatorInfo(L"?", LayoutTree::Node::cFlavourClose)),
143 make_pair(L"!", OperatorInfo(L"!", LayoutTree::Node::cFlavourClose)),
144 make_pair(L"@", OperatorInfo(L"@", LayoutTree::Node::cFlavourOrd)),
145 make_pair(L"*", OperatorInfo(L"*", LayoutTree::Node::cFlavourBin)),
146 make_pair(L"\\_", OperatorInfo(L"_", LayoutTree::Node::cFlavourOrd)),
147 make_pair(L"\\&", OperatorInfo(L"&", LayoutTree::Node::cFlavourOrd)),
148 make_pair(L"\\$", OperatorInfo(L"$", LayoutTree::Node::cFlavourOrd)),
149 make_pair(L"\\#", OperatorInfo(L"#", LayoutTree::Node::cFlavourOrd)),
150 make_pair(L"\\%", OperatorInfo(L"%", LayoutTree::Node::cFlavourOrd)),
151 make_pair(L"\\{", OperatorInfo(L"{", LayoutTree::Node::cFlavourOpen)),
152 make_pair(L"\\}", OperatorInfo(L"}", LayoutTree::Node::cFlavourClose)),
153 make_pair(L"\\ast", OperatorInfo(L"*", LayoutTree::Node::cFlavourBin)),
154 make_pair(L"\\lbrace", OperatorInfo(L"{", LayoutTree::Node::cFlavourOpen)),
155 make_pair(L"\\rbrace", OperatorInfo(L"}", LayoutTree::Node::cFlavourClose)),
156 make_pair(L"\\vert", OperatorInfo(L"|", LayoutTree::Node::cFlavourOrd)),
157 make_pair(L"\\lvert", OperatorInfo(L"|", LayoutTree::Node::cFlavourOpen)),
158 make_pair(L"\\rvert", OperatorInfo(L"|", LayoutTree::Node::cFlavourClose)),
159 make_pair(L"\\lbrack", OperatorInfo(L"[", LayoutTree::Node::cFlavourOpen)),
160 make_pair(L"\\rbrack", OperatorInfo(L"]", LayoutTree::Node::cFlavourClose)),
161 make_pair(L"\\Vert", OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourOrd)),
162 make_pair(L"\\lVert", OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourOpen)),
163 make_pair(L"\\rVert", OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourClose)),
164 make_pair(L"\\lfloor", OperatorInfo(L"\U0000230A", LayoutTree::Node::cFlavourOpen)),
165 make_pair(L"\\rfloor", OperatorInfo(L"\U0000230B", LayoutTree::Node::cFlavourClose)),
166 make_pair(L"\\lceil", OperatorInfo(L"\U00002308", LayoutTree::Node::cFlavourOpen)),
167 make_pair(L"\\rceil", OperatorInfo(L"\U00002309", LayoutTree::Node::cFlavourClose)),
168 make_pair(L"\\langle", OperatorInfo(L"\U00002329", LayoutTree::Node::cFlavourOpen)),
169 make_pair(L"\\rangle", OperatorInfo(L"\U0000232A", LayoutTree::Node::cFlavourClose)),
170 make_pair(L"\\forall", OperatorInfo(L"\U00002200", LayoutTree::Node::cFlavourOrd)),
171 make_pair(L"\\exists", OperatorInfo(L"\U00002203", LayoutTree::Node::cFlavourOrd)),
172 make_pair(L"\\leftarrow", OperatorInfo(L"\U00002190", LayoutTree::Node::cFlavourRel)),
173 make_pair(L"\\rightarrow", OperatorInfo(L"\U00002192", LayoutTree::Node::cFlavourRel)),
174
175 // FIX: The first version below has the correct MathML characters.
176 // They seem to be missing in the fonts currently shipped with
177 // Firefox, so we just map them to their short counterparts (second
178 // version) for the moment.
179 // FIX: perhaps it's possible to do this with the "stretchy" attribute
180 // instead?
181 #if 0
182 make_pair(L"\\longleftarrow", OperatorInfo(L"\U000027F5", LayoutTree::Node::cFlavourRel)),
183 make_pair(L"\\longrightarrow", OperatorInfo(L"\U000027F6", LayoutTree::Node::cFlavourRel)),
184 make_pair(L"\\Longleftarrow", OperatorInfo(L"\U000027F8", LayoutTree::Node::cFlavourRel)),
185 make_pair(L"\\Longrightarrow", OperatorInfo(L"\U000027F9", LayoutTree::Node::cFlavourRel)),
186 make_pair(L"\\longmapsto", OperatorInfo(L"\U000027FC", LayoutTree::Node::cFlavourRel)),
187 make_pair(L"\\longleftrightarrow", OperatorInfo(L"\U000027F7", LayoutTree::Node::cFlavourRel)),
188 make_pair(L"\\Longleftrightarrow", OperatorInfo(L"\U000027FA", LayoutTree::Node::cFlavourRel)),
189 #else
190 make_pair(L"\\longleftarrow", OperatorInfo(L"\U00002190", LayoutTree::Node::cFlavourRel)),
191 make_pair(L"\\longrightarrow", OperatorInfo(L"\U00002192", LayoutTree::Node::cFlavourRel)),
192 make_pair(L"\\Longleftarrow", OperatorInfo(L"\U000021D0", LayoutTree::Node::cFlavourRel)),
193 make_pair(L"\\Longrightarrow", OperatorInfo(L"\U000021D2", LayoutTree::Node::cFlavourRel)),
194 make_pair(L"\\longmapsto", OperatorInfo(L"\U000021A6", LayoutTree::Node::cFlavourRel)),
195 make_pair(L"\\longleftrightarrow", OperatorInfo(L"\U00002194", LayoutTree::Node::cFlavourRel)),
196 make_pair(L"\\Longleftrightarrow", OperatorInfo(L"\U000021D4", LayoutTree::Node::cFlavourRel)),
197 #endif
198
199 make_pair(L"\\Leftarrow", OperatorInfo(L"\U000021D0", LayoutTree::Node::cFlavourRel)),
200 make_pair(L"\\Rightarrow", OperatorInfo(L"\U000021D2", LayoutTree::Node::cFlavourRel)),
201 make_pair(L"\\mapsto", OperatorInfo(L"\U000021A6", LayoutTree::Node::cFlavourRel)),
202 make_pair(L"\\leftrightarrow", OperatorInfo(L"\U00002194", LayoutTree::Node::cFlavourRel)),
203 make_pair(L"\\Leftrightarrow", OperatorInfo(L"\U000021D4", LayoutTree::Node::cFlavourRel)),
204 make_pair(L"\\uparrow", OperatorInfo(L"\U00002191", LayoutTree::Node::cFlavourRel)),
205 make_pair(L"\\Uparrow", OperatorInfo(L"\U000021D1", LayoutTree::Node::cFlavourRel)),
206 make_pair(L"\\downarrow", OperatorInfo(L"\U00002193", LayoutTree::Node::cFlavourRel)),
207 make_pair(L"\\Downarrow", OperatorInfo(L"\U000021D3", LayoutTree::Node::cFlavourRel)),
208 make_pair(L"\\updownarrow", OperatorInfo(L"\U00002195", LayoutTree::Node::cFlavourRel)),
209 make_pair(L"\\Updownarrow", OperatorInfo(L"\U000021D5", LayoutTree::Node::cFlavourRel)),
210 make_pair(L"\\searrow", OperatorInfo(L"\U00002198", LayoutTree::Node::cFlavourRel)),
211 make_pair(L"\\nearrow", OperatorInfo(L"\U00002197", LayoutTree::Node::cFlavourRel)),
212 make_pair(L"\\swarrow", OperatorInfo(L"\U00002199", LayoutTree::Node::cFlavourRel)),
213 make_pair(L"\\nwarrow", OperatorInfo(L"\U00002196", LayoutTree::Node::cFlavourRel)),
214 make_pair(L"\\hookrightarrow", OperatorInfo(L"\U000021AA", LayoutTree::Node::cFlavourRel)),
215 make_pair(L"\\hookleftarrow", OperatorInfo(L"\U000021A9", LayoutTree::Node::cFlavourRel)),
216 make_pair(L"\\upharpoonright", OperatorInfo(L"\U000021BE", LayoutTree::Node::cFlavourRel)),
217 make_pair(L"\\upharpoonleft", OperatorInfo(L"\U000021BF", LayoutTree::Node::cFlavourRel)),
218 make_pair(L"\\downharpoonright", OperatorInfo(L"\U000021C2", LayoutTree::Node::cFlavourRel)),
219 make_pair(L"\\downharpoonleft", OperatorInfo(L"\U000021C3", LayoutTree::Node::cFlavourRel)),
220 make_pair(L"\\rightharpoonup", OperatorInfo(L"\U000021C0", LayoutTree::Node::cFlavourRel)),
221 make_pair(L"\\rightharpoondown", OperatorInfo(L"\U000021C1", LayoutTree::Node::cFlavourRel)),
222 make_pair(L"\\leftharpoonup", OperatorInfo(L"\U000021BC", LayoutTree::Node::cFlavourRel)),
223 make_pair(L"\\leftharpoondown", OperatorInfo(L"\U000021BD", LayoutTree::Node::cFlavourRel)),
224 make_pair(L"\\nleftarrow", OperatorInfo(L"\U0000219A", LayoutTree::Node::cFlavourRel)),
225 make_pair(L"\\nrightarrow", OperatorInfo(L"\U0000219B", LayoutTree::Node::cFlavourRel)),
226 make_pair(L"\\supset", OperatorInfo(L"\U00002283", LayoutTree::Node::cFlavourRel)),
227 make_pair(L"\\subset", OperatorInfo(L"\U00002282", LayoutTree::Node::cFlavourRel)),
228 make_pair(L"\\supseteq", OperatorInfo(L"\U00002287", LayoutTree::Node::cFlavourRel)),
229 make_pair(L"\\subseteq", OperatorInfo(L"\U00002286", LayoutTree::Node::cFlavourRel)),
230 make_pair(L"\\sqsupset", OperatorInfo(L"\U00002290", LayoutTree::Node::cFlavourRel)),
231 make_pair(L"\\sqsubset", OperatorInfo(L"\U0000228F", LayoutTree::Node::cFlavourRel)),
232 make_pair(L"\\sqsupseteq", OperatorInfo(L"\U00002292", LayoutTree::Node::cFlavourRel)),
233 make_pair(L"\\sqsubseteq", OperatorInfo(L"\U00002291", LayoutTree::Node::cFlavourRel)),
234 make_pair(L"\\supsetneq", OperatorInfo(L"\U0000228B", LayoutTree::Node::cFlavourRel)),
235 make_pair(L"\\subsetneq", OperatorInfo(L"\U0000228A", LayoutTree::Node::cFlavourRel)),
236 make_pair(L"\\in", OperatorInfo(L"\U00002208", LayoutTree::Node::cFlavourRel)),
237 make_pair(L"\\ni", OperatorInfo(L"\U0000220B", LayoutTree::Node::cFlavourRel)),
238 make_pair(L"\\notin", OperatorInfo(L"\U00002209", LayoutTree::Node::cFlavourRel)),
239 make_pair(L"\\mid", OperatorInfo(L"|", LayoutTree::Node::cFlavourRel)),
240 make_pair(L"\\sim", OperatorInfo(L"\U0000223C", LayoutTree::Node::cFlavourRel)),
241 make_pair(L"\\simeq", OperatorInfo(L"\U00002243", LayoutTree::Node::cFlavourRel)),
242 make_pair(L"\\approx", OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
243 make_pair(L"\\propto", OperatorInfo(L"\U0000221D", LayoutTree::Node::cFlavourRel)),
244 make_pair(L"\\equiv", OperatorInfo(L"\U00002261", LayoutTree::Node::cFlavourRel)),
245 make_pair(L"\\cong", OperatorInfo(L"\U00002245", LayoutTree::Node::cFlavourRel)),
246 make_pair(L"\\neq", OperatorInfo(L"\U00002260", LayoutTree::Node::cFlavourRel)),
247 make_pair(L"\\ll", OperatorInfo(L"\U0000226A", LayoutTree::Node::cFlavourRel)),
248 make_pair(L"\\gg", OperatorInfo(L"\U0000226B", LayoutTree::Node::cFlavourRel)),
249 make_pair(L"\\geq", OperatorInfo(L"\U00002265", LayoutTree::Node::cFlavourRel)),
250 make_pair(L"\\leq", OperatorInfo(L"\U00002264", LayoutTree::Node::cFlavourRel)),
251 make_pair(L"\\triangleleft", OperatorInfo(L"\U000025C3", LayoutTree::Node::cFlavourBin)),
252 make_pair(L"\\triangleright", OperatorInfo(L"\U000025B9", LayoutTree::Node::cFlavourBin)),
253 make_pair(L"\\models", OperatorInfo(L"\U000022A7", LayoutTree::Node::cFlavourRel)),
254 make_pair(L"\\vdash", OperatorInfo(L"\U000022A2", LayoutTree::Node::cFlavourRel)),
255 make_pair(L"\\Vdash", OperatorInfo(L"\U000022A9", LayoutTree::Node::cFlavourRel)),
256 make_pair(L"\\vDash", OperatorInfo(L"\U000022A8", LayoutTree::Node::cFlavourRel)),
257 make_pair(L"\\lesssim", OperatorInfo(L"\U00002272", LayoutTree::Node::cFlavourRel)),
258 make_pair(L"\\nless", OperatorInfo(L"\U0000226E", LayoutTree::Node::cFlavourRel)),
259 make_pair(L"\\ngeq", OperatorInfo(L"\U00002271", LayoutTree::Node::cFlavourRel)),
260 make_pair(L"\\nleq", OperatorInfo(L"\U00002270", LayoutTree::Node::cFlavourRel)),
261
262 // FIX: the fonts shipped with Firefox 1.5 don't know about
263 // 0x2a2f (⨯). So I'm mapping it to 0xd7 (×) for now.
264 #if 0
265 make_pair(L"\\times", OperatorInfo(L"\U00002A2F", LayoutTree::Node::cFlavourBin)),
266 #else
267 make_pair(L"\\times", OperatorInfo(L"\U000000D7", LayoutTree::Node::cFlavourBin)),
268 #endif
269
270 make_pair(L"\\div", OperatorInfo(L"\U000000F7", LayoutTree::Node::cFlavourBin)),
271 make_pair(L"\\wedge", OperatorInfo(L"\U00002227", LayoutTree::Node::cFlavourBin)),
272 make_pair(L"\\vee", OperatorInfo(L"\U00002228", LayoutTree::Node::cFlavourBin)),
273 make_pair(L"\\oplus", OperatorInfo(L"\U00002295", LayoutTree::Node::cFlavourBin)),
274 make_pair(L"\\otimes", OperatorInfo(L"\U00002297", LayoutTree::Node::cFlavourBin)),
275 make_pair(L"\\cap", OperatorInfo(L"\U00002229", LayoutTree::Node::cFlavourBin)),
276 make_pair(L"\\cup", OperatorInfo(L"\U0000222A", LayoutTree::Node::cFlavourBin)),
277 make_pair(L"\\sqcap", OperatorInfo(L"\U00002293", LayoutTree::Node::cFlavourBin)),
278 make_pair(L"\\sqcup", OperatorInfo(L"\U00002294", LayoutTree::Node::cFlavourBin)),
279 make_pair(L"\\smile", OperatorInfo(L"\U00002323", LayoutTree::Node::cFlavourRel)),
280 make_pair(L"\\frown", OperatorInfo(L"\U00002322", LayoutTree::Node::cFlavourRel)),
281 // FIX: how to make these smiles/frowns smaller?
282 make_pair(L"\\smallsmile", OperatorInfo(L"\U00002323", LayoutTree::Node::cFlavourRel)),
283 make_pair(L"\\smallfrown", OperatorInfo(L"\U00002322", LayoutTree::Node::cFlavourRel)),
284 make_pair(L"\\setminus", OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourBin)),
285 // FIX: how to make smallsetminus smaller?
286 make_pair(L"\\smallsetminus", OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourBin)),
287 make_pair(L"\\star", OperatorInfo(L"\U000022C6", LayoutTree::Node::cFlavourBin)),
288 make_pair(L"\\triangle", OperatorInfo(L"\U000025B3", LayoutTree::Node::cFlavourOrd)),
289 make_pair(L"\\wr", OperatorInfo(L"\U00002240", LayoutTree::Node::cFlavourBin)),
290 make_pair(L"\\circ", OperatorInfo(L"\U00002218", LayoutTree::Node::cFlavourBin)),
291 make_pair(L"\\lnot", OperatorInfo(L"\U000000AC", LayoutTree::Node::cFlavourOrd)),
292 make_pair(L"\\nabla", OperatorInfo(L"\U00002207", LayoutTree::Node::cFlavourOrd)),
293 make_pair(L"\\prime", OperatorInfo(L"\U00002032", LayoutTree::Node::cFlavourOrd)),
294 make_pair(L"\\backslash", OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourOrd)),
295 make_pair(L"\\pm", OperatorInfo(L"\U000000B1", LayoutTree::Node::cFlavourBin)),
296 make_pair(L"\\mp", OperatorInfo(L"\U00002213", LayoutTree::Node::cFlavourBin)),
297 make_pair(L"\\angle", OperatorInfo(L"\U00002220", LayoutTree::Node::cFlavourOrd)),
298 make_pair(L"\\nmid", OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
299 make_pair(L"\\square", OperatorInfo(L"\U000025A1", LayoutTree::Node::cFlavourOrd)),
300 make_pair(L"\\Box", OperatorInfo(L"\U000025A1", LayoutTree::Node::cFlavourOrd)),
301 make_pair(L"\\checkmark", OperatorInfo(L"\U00002713", LayoutTree::Node::cFlavourOrd)),
302 make_pair(L"\\complement", OperatorInfo(L"\U00002201", LayoutTree::Node::cFlavourOrd)),
303 make_pair(L"\\flat", OperatorInfo(L"\U0000266D", LayoutTree::Node::cFlavourOrd)),
304 make_pair(L"\\sharp", OperatorInfo(L"\U0000266F", LayoutTree::Node::cFlavourOrd)),
305 make_pair(L"\\natural", OperatorInfo(L"\U0000266E", LayoutTree::Node::cFlavourOrd)),
306 make_pair(L"\\bullet", OperatorInfo(L"\U00002022", LayoutTree::Node::cFlavourBin)),
307 make_pair(L"\\dagger", OperatorInfo(L"\U00002020", LayoutTree::Node::cFlavourBin)),
308 make_pair(L"\\ddagger", OperatorInfo(L"\U00002021", LayoutTree::Node::cFlavourBin)),
309 make_pair(L"\\clubsuit", OperatorInfo(L"\U00002663", LayoutTree::Node::cFlavourOrd)),
310 make_pair(L"\\spadesuit", OperatorInfo(L"\U00002660", LayoutTree::Node::cFlavourOrd)),
311 make_pair(L"\\heartsuit", OperatorInfo(L"\U00002665", LayoutTree::Node::cFlavourOrd)),
312 make_pair(L"\\diamondsuit", OperatorInfo(L"\U00002666", LayoutTree::Node::cFlavourOrd)),
313 make_pair(L"\\top", OperatorInfo(L"\U000022A4", LayoutTree::Node::cFlavourOrd)),
314 make_pair(L"\\bot", OperatorInfo(L"\U000022A5", LayoutTree::Node::cFlavourOrd)),
315 make_pair(L"\\perp", OperatorInfo(L"\U000022A5", LayoutTree::Node::cFlavourRel)),
316 make_pair(L"\\cdot", OperatorInfo(L"\U000022C5", LayoutTree::Node::cFlavourBin)),
317 make_pair(L"\\vdots", OperatorInfo(L"\U000022EE", LayoutTree::Node::cFlavourOrd)),
318 make_pair(L"\\ddots", OperatorInfo(L"\U000022F1", LayoutTree::Node::cFlavourInner)),
319 make_pair(L"\\cdots", OperatorInfo(L"\U000022EF", LayoutTree::Node::cFlavourInner)),
320 make_pair(L"\\ldots", OperatorInfo(L"\U00002026", LayoutTree::Node::cFlavourInner)),
321 // FIX: these next two aren't right. The amsmath package does tricky
322 // things so that the dots change their vertical position depending
323 // on the surrounding operators. We chicken out and just map them
324 // to the same as \cdots and \ldots respectively.
325 make_pair(L"\\dotsb", OperatorInfo(L"\U000022EF", LayoutTree::Node::cFlavourInner)),
326 make_pair(L"\\dots", OperatorInfo(L"\U00002026", LayoutTree::Node::cFlavourInner)),
327 make_pair(L"\\sum", OperatorInfo(L"\U00002211", LayoutTree::Node::cFlavourOp)),
328 make_pair(L"\\prod", OperatorInfo(L"\U0000220F", LayoutTree::Node::cFlavourOp)),
329 make_pair(L"\\int", OperatorInfo(L"\U0000222B", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
330 make_pair(L"\\iint", OperatorInfo(L"\U0000222C", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
331 make_pair(L"\\iiint", OperatorInfo(L"\U0000222D", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
332 make_pair(L"\\iiiint", OperatorInfo(L"\U00002A0C", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
333 make_pair(L"\\oint", OperatorInfo(L"\U0000222E", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
334 make_pair(L"\\bigcap", OperatorInfo(L"\U000022C2", LayoutTree::Node::cFlavourOp)),
335 make_pair(L"\\bigodot", OperatorInfo(L"\U00002A00", LayoutTree::Node::cFlavourOp)),
336 make_pair(L"\\bigcup", OperatorInfo(L"\U000022C3", LayoutTree::Node::cFlavourOp)),
337 make_pair(L"\\bigotimes", OperatorInfo(L"\U00002A02", LayoutTree::Node::cFlavourOp)),
338 make_pair(L"\\coprod", OperatorInfo(L"\U00002210", LayoutTree::Node::cFlavourOp)),
339 make_pair(L"\\bigsqcup", OperatorInfo(L"\U00002A06", LayoutTree::Node::cFlavourOp)),
340 make_pair(L"\\bigoplus", OperatorInfo(L"\U00002A01", LayoutTree::Node::cFlavourOp)),
341 make_pair(L"\\bigvee", OperatorInfo(L"\U000022C1", LayoutTree::Node::cFlavourOp)),
342 make_pair(L"\\biguplus", OperatorInfo(L"\U00002A04", LayoutTree::Node::cFlavourOp)),
343 make_pair(L"\\bigwedge", OperatorInfo(L"\U000022C0", LayoutTree::Node::cFlavourOp)),
344 make_pair(L"\\ulcorner", OperatorInfo(L"\U0000231C", LayoutTree::Node::cFlavourOrd)),
345 make_pair(L"\\urcorner", OperatorInfo(L"\U0000231D", LayoutTree::Node::cFlavourOrd)),
346 make_pair(L"\\llcorner", OperatorInfo(L"\U0000231E", LayoutTree::Node::cFlavourOrd)),
347 make_pair(L"\\lrcorner", OperatorInfo(L"\U0000231F", LayoutTree::Node::cFlavourOrd)),
348 make_pair(L"\\dashrightarrow", OperatorInfo(L"\U0000290F", LayoutTree::Node::cFlavourRel)),
349 make_pair(L"\\dashleftarrow", OperatorInfo(L"\U0000290E", LayoutTree::Node::cFlavourRel)),
350 make_pair(L"\\backprime", OperatorInfo(L"\U00002035", LayoutTree::Node::cFlavourOrd)),
351 make_pair(L"\\vartriangle", OperatorInfo(L"\U000025B5", LayoutTree::Node::cFlavourRel)),
352 make_pair(L"\\blacktriangle", OperatorInfo(L"\U000025B4", LayoutTree::Node::cFlavourOrd)),
353 make_pair(L"\\triangledown", OperatorInfo(L"\U000025BF", LayoutTree::Node::cFlavourOrd)),
354 make_pair(L"\\blacktriangledown", OperatorInfo(L"\U000025BE", LayoutTree::Node::cFlavourOrd)),
355 make_pair(L"\\blacksquare", OperatorInfo(L"\U000025FC", LayoutTree::Node::cFlavourOrd)),
356 make_pair(L"\\lozenge", OperatorInfo(L"\U000025CA", LayoutTree::Node::cFlavourOrd)),
357 make_pair(L"\\blacklozenge", OperatorInfo(L"\U000029EB", LayoutTree::Node::cFlavourOrd)),
358 make_pair(L"\\bigstar", OperatorInfo(L"\U00002605", LayoutTree::Node::cFlavourOrd)),
359 make_pair(L"\\sphericalangle", OperatorInfo(L"\U00002222", LayoutTree::Node::cFlavourOrd)),
360 make_pair(L"\\measuredangle", OperatorInfo(L"\U00002221", LayoutTree::Node::cFlavourOrd)),
361 make_pair(L"\\dotplus", OperatorInfo(L"\U00002214", LayoutTree::Node::cFlavourOrd)),
362 make_pair(L"\\ltimes", OperatorInfo(L"\U000022C9", LayoutTree::Node::cFlavourBin)),
363 make_pair(L"\\rtimes", OperatorInfo(L"\U000022CA", LayoutTree::Node::cFlavourBin)),
364 make_pair(L"\\Cap", OperatorInfo(L"\U000022D2", LayoutTree::Node::cFlavourBin)),
365 make_pair(L"\\leftthreetimes", OperatorInfo(L"\U000022CB", LayoutTree::Node::cFlavourBin)),
366 make_pair(L"\\rightthreetimes", OperatorInfo(L"\U000022CC", LayoutTree::Node::cFlavourBin)),
367 make_pair(L"\\Cup", OperatorInfo(L"\U000022D3", LayoutTree::Node::cFlavourBin)),
368 make_pair(L"\\barwedge", OperatorInfo(L"\U00002305", LayoutTree::Node::cFlavourBin)),
369 make_pair(L"\\curlywedge", OperatorInfo(L"\U000022CF", LayoutTree::Node::cFlavourBin)),
370 make_pair(L"\\veebar", OperatorInfo(L"\U000022BB", LayoutTree::Node::cFlavourBin)),
371 make_pair(L"\\curlyvee", OperatorInfo(L"\U000022CE", LayoutTree::Node::cFlavourBin)),
372 make_pair(L"\\doublebarwedge", OperatorInfo(L"\U00002306", LayoutTree::Node::cFlavourBin)),
373 make_pair(L"\\boxminus", OperatorInfo(L"\U0000229F", LayoutTree::Node::cFlavourBin)),
374 make_pair(L"\\circleddash", OperatorInfo(L"\U0000229D", LayoutTree::Node::cFlavourBin)),
375 make_pair(L"\\boxtimes", OperatorInfo(L"\U000022A0", LayoutTree::Node::cFlavourBin)),
376 make_pair(L"\\circledast", OperatorInfo(L"\U0000229B", LayoutTree::Node::cFlavourBin)),
377 make_pair(L"\\boxdot", OperatorInfo(L"\U000022A1", LayoutTree::Node::cFlavourBin)),
378 make_pair(L"\\circledcirc", OperatorInfo(L"\U0000229A", LayoutTree::Node::cFlavourBin)),
379 make_pair(L"\\boxplus", OperatorInfo(L"\U0000229E", LayoutTree::Node::cFlavourBin)),
380 make_pair(L"\\centerdot", OperatorInfo(L"\U000022C5", LayoutTree::Node::cFlavourBin)),
381 make_pair(L"\\divideontimes", OperatorInfo(L"\U000022C7", LayoutTree::Node::cFlavourBin)),
382 make_pair(L"\\intercal", OperatorInfo(L"\U000022BA", LayoutTree::Node::cFlavourBin)),
383 make_pair(L"\\leqq", OperatorInfo(L"\U00002266", LayoutTree::Node::cFlavourRel)),
384 make_pair(L"\\geqq", OperatorInfo(L"\U00002267", LayoutTree::Node::cFlavourRel)),
385 make_pair(L"\\leqslant", OperatorInfo(L"\U00002A7D", LayoutTree::Node::cFlavourRel)),
386 make_pair(L"\\geqslant", OperatorInfo(L"\U00002A7E", LayoutTree::Node::cFlavourRel)),
387 make_pair(L"\\eqslantless", OperatorInfo(L"\U00002A95", LayoutTree::Node::cFlavourRel)),
388 make_pair(L"\\eqslantgtr", OperatorInfo(L"\U00002A96", LayoutTree::Node::cFlavourRel)),
389 make_pair(L"\\gtrsim", OperatorInfo(L"\U00002273", LayoutTree::Node::cFlavourRel)),
390 make_pair(L"\\lessapprox", OperatorInfo(L"\U00002A85", LayoutTree::Node::cFlavourRel)),
391 make_pair(L"\\gtrapprox", OperatorInfo(L"\U00002A86", LayoutTree::Node::cFlavourRel)),
392 make_pair(L"\\approxeq", OperatorInfo(L"\U0000224A", LayoutTree::Node::cFlavourRel)),
393 make_pair(L"\\eqsim", OperatorInfo(L"\U00002242", LayoutTree::Node::cFlavourRel)),
394 make_pair(L"\\lessdot", OperatorInfo(L"\U000022D6", LayoutTree::Node::cFlavourBin)),
395 make_pair(L"\\gtrdot", OperatorInfo(L"\U000022D7", LayoutTree::Node::cFlavourBin)),
396 make_pair(L"\\lll", OperatorInfo(L"\U000022D8", LayoutTree::Node::cFlavourRel)),
397 make_pair(L"\\ggg", OperatorInfo(L"\U000022D9", LayoutTree::Node::cFlavourRel)),
398 make_pair(L"\\lessgtr", OperatorInfo(L"\U00002276", LayoutTree::Node::cFlavourRel)),
399 make_pair(L"\\gtrless", OperatorInfo(L"\U00002277", LayoutTree::Node::cFlavourRel)),
400 make_pair(L"\\lesseqgtr", OperatorInfo(L"\U000022DA", LayoutTree::Node::cFlavourRel)),
401 make_pair(L"\\gtreqless", OperatorInfo(L"\U000022DB", LayoutTree::Node::cFlavourRel)),
402 make_pair(L"\\lesseqqgtr", OperatorInfo(L"\U00002A8B", LayoutTree::Node::cFlavourRel)),
403 make_pair(L"\\gtreqqless", OperatorInfo(L"\U00002A8C", LayoutTree::Node::cFlavourRel)),
404 make_pair(L"\\doteqdot", OperatorInfo(L"\U00002251", LayoutTree::Node::cFlavourRel)),
405 make_pair(L"\\eqcirc", OperatorInfo(L"\U00002256", LayoutTree::Node::cFlavourRel)),
406 make_pair(L"\\risingdotseq", OperatorInfo(L"\U00002253", LayoutTree::Node::cFlavourRel)),
407 make_pair(L"\\circeq", OperatorInfo(L"\U00002257", LayoutTree::Node::cFlavourRel)),
408 make_pair(L"\\fallingdotseq", OperatorInfo(L"\U00002252", LayoutTree::Node::cFlavourRel)),
409 make_pair(L"\\triangleq", OperatorInfo(L"\U0000225C", LayoutTree::Node::cFlavourRel)),
410 make_pair(L"\\backsim", OperatorInfo(L"\U0000223D", LayoutTree::Node::cFlavourRel)),
411 make_pair(L"\\thicksim", OperatorInfo(L"\U0000223C", LayoutTree::Node::cFlavourRel)),
412 make_pair(L"\\backsimeq", OperatorInfo(L"\U000022CD", LayoutTree::Node::cFlavourRel)),
413 make_pair(L"\\thickapprox", OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
414 make_pair(L"\\subseteqq", OperatorInfo(L"\U00002AC5", LayoutTree::Node::cFlavourRel)),
415 make_pair(L"\\supseteqq", OperatorInfo(L"\U00002AC6", LayoutTree::Node::cFlavourRel)),
416 make_pair(L"\\Subset", OperatorInfo(L"\U000022D0", LayoutTree::Node::cFlavourRel)),
417 make_pair(L"\\Supset", OperatorInfo(L"\U000022D1", LayoutTree::Node::cFlavourRel)),
418 make_pair(L"\\preccurlyeq", OperatorInfo(L"\U0000227C", LayoutTree::Node::cFlavourRel)),
419 make_pair(L"\\succcurlyeq", OperatorInfo(L"\U0000227D", LayoutTree::Node::cFlavourRel)),
420 make_pair(L"\\curlyeqprec", OperatorInfo(L"\U000022DE", LayoutTree::Node::cFlavourRel)),
421 make_pair(L"\\curlyeqsucc", OperatorInfo(L"\U000022DF", LayoutTree::Node::cFlavourRel)),
422 make_pair(L"\\precsim", OperatorInfo(L"\U0000227E", LayoutTree::Node::cFlavourRel)),
423 make_pair(L"\\succsim", OperatorInfo(L"\U0000227F", LayoutTree::Node::cFlavourRel)),
424 make_pair(L"\\precapprox", OperatorInfo(L"\U00002AB7", LayoutTree::Node::cFlavourRel)),
425 make_pair(L"\\succapprox", OperatorInfo(L"\U00002AB8", LayoutTree::Node::cFlavourRel)),
426 make_pair(L"\\Vvdash", OperatorInfo(L"\U000022AA", LayoutTree::Node::cFlavourRel)),
427 make_pair(L"\\shortmid", OperatorInfo(L"\U00002223", LayoutTree::Node::cFlavourRel)),
428 make_pair(L"\\shortparallel", OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourRel)),
429 make_pair(L"\\bumpeq", OperatorInfo(L"\U0000224F", LayoutTree::Node::cFlavourRel)),
430 make_pair(L"\\between", OperatorInfo(L"\U0000226C", LayoutTree::Node::cFlavourRel)),
431 make_pair(L"\\Bumpeq", OperatorInfo(L"\U0000224E", LayoutTree::Node::cFlavourRel)),
432 make_pair(L"\\varpropto", OperatorInfo(L"\U0000221D", LayoutTree::Node::cFlavourRel)),
433 make_pair(L"\\backepsilon", OperatorInfo(L"\U000003F6", LayoutTree::Node::cFlavourRel)),
434 make_pair(L"\\blacktriangleleft", OperatorInfo(L"\U000025C0", LayoutTree::Node::cFlavourRel)),
435 make_pair(L"\\blacktriangleright", OperatorInfo(L"\U000025B6", LayoutTree::Node::cFlavourRel)),
436 make_pair(L"\\therefore", OperatorInfo(L"\U00002234", LayoutTree::Node::cFlavourRel)),
437 make_pair(L"\\because", OperatorInfo(L"\U00002235", LayoutTree::Node::cFlavourRel)),
438 make_pair(L"\\ngtr", OperatorInfo(L"\U0000226F", LayoutTree::Node::cFlavourRel)),
439 make_pair(L"\\nleqslant", OperatorInfo(L"\U00002A7D\U00000338", LayoutTree::Node::cFlavourRel)),
440 make_pair(L"\\ngeqslant", OperatorInfo(L"\U00002A7E\U00000338", LayoutTree::Node::cFlavourRel)),
441 make_pair(L"\\nleqq", OperatorInfo(L"\U00002266\U00000338", LayoutTree::Node::cFlavourRel)),
442 make_pair(L"\\ngeqq", OperatorInfo(L"\U00002267\U00000338", LayoutTree::Node::cFlavourRel)),
443 make_pair(L"\\lneqq", OperatorInfo(L"\U00002268", LayoutTree::Node::cFlavourRel)),
444 make_pair(L"\\gneqq", OperatorInfo(L"\U00002269", LayoutTree::Node::cFlavourRel)),
445 make_pair(L"\\lvertneqq", OperatorInfo(L"\U00002268\U0000FE00", LayoutTree::Node::cFlavourRel)),
446 make_pair(L"\\gvertneqq", OperatorInfo(L"\U00002269\U0000FE00", LayoutTree::Node::cFlavourRel)),
447 make_pair(L"\\lnsim", OperatorInfo(L"\U000022E6", LayoutTree::Node::cFlavourRel)),
448 make_pair(L"\\gnsim", OperatorInfo(L"\U000022E7", LayoutTree::Node::cFlavourRel)),
449 make_pair(L"\\lnapprox", OperatorInfo(L"\U00002A89", LayoutTree::Node::cFlavourRel)),
450 make_pair(L"\\gnapprox", OperatorInfo(L"\U00002A8A", LayoutTree::Node::cFlavourRel)),
451 make_pair(L"\\nprec", OperatorInfo(L"\U00002280", LayoutTree::Node::cFlavourRel)),
452 make_pair(L"\\nsucc", OperatorInfo(L"\U00002281", LayoutTree::Node::cFlavourRel)),
453 make_pair(L"\\npreceq", OperatorInfo(L"\U00002AAF\U00000338", LayoutTree::Node::cFlavourRel)),
454 make_pair(L"\\nsucceq", OperatorInfo(L"\U00002AB0\U00000338", LayoutTree::Node::cFlavourRel)),
455 make_pair(L"\\precneqq", OperatorInfo(L"\U00002AB5", LayoutTree::Node::cFlavourRel)),
456 make_pair(L"\\succneqq", OperatorInfo(L"\U00002AB6", LayoutTree::Node::cFlavourRel)),
457 make_pair(L"\\precnsim", OperatorInfo(L"\U000022E8", LayoutTree::Node::cFlavourRel)),
458 make_pair(L"\\succnsim", OperatorInfo(L"\U000022E9", LayoutTree::Node::cFlavourRel)),
459 make_pair(L"\\precnapprox", OperatorInfo(L"\U00002AB9", LayoutTree::Node::cFlavourRel)),
460 make_pair(L"\\succnapprox", OperatorInfo(L"\U00002ABA", LayoutTree::Node::cFlavourRel)),
461 make_pair(L"\\nsim", OperatorInfo(L"\U00002241", LayoutTree::Node::cFlavourRel)),
462 make_pair(L"\\ncong", OperatorInfo(L"\U00002247", LayoutTree::Node::cFlavourRel)),
463 make_pair(L"\\nshortmid", OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
464 make_pair(L"\\nshortparallel", OperatorInfo(L"\U00002226", LayoutTree::Node::cFlavourRel)),
465 make_pair(L"\\nmid", OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
466 make_pair(L"\\nparallel", OperatorInfo(L"\U00002226", LayoutTree::Node::cFlavourRel)),
467 make_pair(L"\\nvdash", OperatorInfo(L"\U000022AC", LayoutTree::Node::cFlavourRel)),
468 make_pair(L"\\nvDash", OperatorInfo(L"\U000022AD", LayoutTree::Node::cFlavourRel)),
469 make_pair(L"\\nVdash", OperatorInfo(L"\U000022AE", LayoutTree::Node::cFlavourRel)),
470 make_pair(L"\\nVDash", OperatorInfo(L"\U000022AF", LayoutTree::Node::cFlavourRel)),
471 make_pair(L"\\ntriangleleft", OperatorInfo(L"\U000022EA", LayoutTree::Node::cFlavourRel)),
472 make_pair(L"\\ntriangleright", OperatorInfo(L"\U000022EB", LayoutTree::Node::cFlavourRel)),
473 make_pair(L"\\ntrianglelefteq", OperatorInfo(L"\U000022EC", LayoutTree::Node::cFlavourRel)),
474 make_pair(L"\\ntrianglerighteq", OperatorInfo(L"\U000022ED", LayoutTree::Node::cFlavourRel)),
475 make_pair(L"\\nsubseteq", OperatorInfo(L"\U00002288", LayoutTree::Node::cFlavourRel)),
476 make_pair(L"\\nsupseteq", OperatorInfo(L"\U00002289", LayoutTree::Node::cFlavourRel)),
477 make_pair(L"\\nsubseteqq", OperatorInfo(L"\U00002AC5\U00000338", LayoutTree::Node::cFlavourRel)),
478 make_pair(L"\\nsupseteqq", OperatorInfo(L"\U00002AC6\U00000338", LayoutTree::Node::cFlavourRel)),
479 make_pair(L"\\subsetneq", OperatorInfo(L"\U0000228A", LayoutTree::Node::cFlavourRel)),
480 make_pair(L"\\supsetneq", OperatorInfo(L"\U0000228B", LayoutTree::Node::cFlavourRel)),
481 make_pair(L"\\varsubsetneq", OperatorInfo(L"\U0000228A\U0000FE00", LayoutTree::Node::cFlavourRel)),
482 make_pair(L"\\varsupsetneq", OperatorInfo(L"\U0000228B\U0000FE00", LayoutTree::Node::cFlavourRel)),
483 make_pair(L"\\subsetneqq", OperatorInfo(L"\U00002ACB", LayoutTree::Node::cFlavourRel)),
484 make_pair(L"\\supsetneqq", OperatorInfo(L"\U00002ACC", LayoutTree::Node::cFlavourRel)),
485 make_pair(L"\\varsubsetneqq", OperatorInfo(L"\U00002ACB\U0000FE00", LayoutTree::Node::cFlavourRel)),
486 make_pair(L"\\varsupsetneqq", OperatorInfo(L"\U00002ACC\U0000FE00", LayoutTree::Node::cFlavourRel)),
487 make_pair(L"\\leftleftarrows", OperatorInfo(L"\U000021C7", LayoutTree::Node::cFlavourRel)),
488 make_pair(L"\\rightrightarrows", OperatorInfo(L"\U000021C9", LayoutTree::Node::cFlavourRel)),
489 make_pair(L"\\leftrightarrows", OperatorInfo(L"\U000021C6", LayoutTree::Node::cFlavourRel)),
490 make_pair(L"\\rightleftarrows", OperatorInfo(L"\U000021C4", LayoutTree::Node::cFlavourRel)),
491 make_pair(L"\\Lleftarrow", OperatorInfo(L"\U000021DA", LayoutTree::Node::cFlavourRel)),
492 make_pair(L"\\Rrightarrow", OperatorInfo(L"\U000021DB", LayoutTree::Node::cFlavourRel)),
493 make_pair(L"\\twoheadleftarrow", OperatorInfo(L"\U0000219E", LayoutTree::Node::cFlavourRel)),
494 make_pair(L"\\twoheadrightarrow", OperatorInfo(L"\U000021A0", LayoutTree::Node::cFlavourRel)),
495 make_pair(L"\\leftarrowtail", OperatorInfo(L"\U000021A2", LayoutTree::Node::cFlavourRel)),
496 make_pair(L"\\rightarrowtail", OperatorInfo(L"\U000021A3", LayoutTree::Node::cFlavourRel)),
497 make_pair(L"\\looparrowleft", OperatorInfo(L"\U000021AB", LayoutTree::Node::cFlavourRel)),
498 make_pair(L"\\looparrowright", OperatorInfo(L"\U000021AC", LayoutTree::Node::cFlavourRel)),
499 make_pair(L"\\leftrightharpoons", OperatorInfo(L"\U000021CB", LayoutTree::Node::cFlavourRel)),
500 make_pair(L"\\rightleftharpoons", OperatorInfo(L"\U000021CC", LayoutTree::Node::cFlavourRel)),
501 make_pair(L"\\curvearrowleft", OperatorInfo(L"\U000021B6", LayoutTree::Node::cFlavourRel)),
502 make_pair(L"\\curvearrowright", OperatorInfo(L"\U000021B7", LayoutTree::Node::cFlavourRel)),
503 make_pair(L"\\circlearrowleft", OperatorInfo(L"\U000021BA", LayoutTree::Node::cFlavourRel)),
504 make_pair(L"\\circlearrowright", OperatorInfo(L"\U000021BB", LayoutTree::Node::cFlavourRel)),
505 make_pair(L"\\Lsh", OperatorInfo(L"\U000021B0", LayoutTree::Node::cFlavourRel)),
506 make_pair(L"\\Rsh", OperatorInfo(L"\U000021B1", LayoutTree::Node::cFlavourRel)),
507 make_pair(L"\\upuparrows", OperatorInfo(L"\U000021C8", LayoutTree::Node::cFlavourRel)),
508 make_pair(L"\\downdownarrows", OperatorInfo(L"\U000021CA", LayoutTree::Node::cFlavourRel)),
509 make_pair(L"\\multimap", OperatorInfo(L"\U000022B8", LayoutTree::Node::cFlavourRel)),
510 make_pair(L"\\rightsquigarrow", OperatorInfo(L"\U0000219D", LayoutTree::Node::cFlavourRel)),
511 make_pair(L"\\leftrightsquigarrow", OperatorInfo(L"\U000021AD", LayoutTree::Node::cFlavourRel)),
512 make_pair(L"\\nLeftarrow", OperatorInfo(L"\U000021CD", LayoutTree::Node::cFlavourRel)),
513 make_pair(L"\\nRightarrow", OperatorInfo(L"\U000021CF", LayoutTree::Node::cFlavourRel)),
514 make_pair(L"\\nleftrightarrow", OperatorInfo(L"\U000021AE", LayoutTree::Node::cFlavourRel)),
515 make_pair(L"\\nLeftrightarrow", OperatorInfo(L"\U000021CE", LayoutTree::Node::cFlavourRel)),
516 make_pair(L"\\pitchfork", OperatorInfo(L"\U000022D4", LayoutTree::Node::cFlavourRel)),
517 make_pair(L"\\nexists", OperatorInfo(L"\U00002204", LayoutTree::Node::cFlavourOrd)),
518 make_pair(L"\\lhd", OperatorInfo(L"\U000022B2", LayoutTree::Node::cFlavourBin)),
519 make_pair(L"\\rhd", OperatorInfo(L"\U000022B3", LayoutTree::Node::cFlavourBin)),
520 make_pair(L"\\unlhd", OperatorInfo(L"\U000022B4", LayoutTree::Node::cFlavourBin)),
521 make_pair(L"\\unrhd", OperatorInfo(L"\U000022B5", LayoutTree::Node::cFlavourBin)),
522 make_pair(L"\\leadsto", OperatorInfo(L"\U000021DD", LayoutTree::Node::cFlavourRel)),
523 make_pair(L"\\uplus", OperatorInfo(L"\U0000228E", LayoutTree::Node::cFlavourBin)),
524 make_pair(L"\\diamond", OperatorInfo(L"\U000022C4", LayoutTree::Node::cFlavourBin)),
525 make_pair(L"\\bigtriangleup", OperatorInfo(L"\U000025B3", LayoutTree::Node::cFlavourBin)),
526 make_pair(L"\\bigtriangledown", OperatorInfo(L"\U000025BD", LayoutTree::Node::cFlavourBin)),
527 make_pair(L"\\ominus", OperatorInfo(L"\U00002296", LayoutTree::Node::cFlavourBin)),
528 make_pair(L"\\oslash", OperatorInfo(L"\U00002298", LayoutTree::Node::cFlavourBin)),
529 make_pair(L"\\odot", OperatorInfo(L"\U00002299", LayoutTree::Node::cFlavourBin)),
530 make_pair(L"\\bigcirc", OperatorInfo(L"\U000025EF", LayoutTree::Node::cFlavourBin)),
531 make_pair(L"\\amalg", OperatorInfo(L"\U00002A3F", LayoutTree::Node::cFlavourBin)),
532 make_pair(L"\\prec", OperatorInfo(L"\U0000227A", LayoutTree::Node::cFlavourRel)),
533 make_pair(L"\\succ", OperatorInfo(L"\U0000227B", LayoutTree::Node::cFlavourRel)),
534 make_pair(L"\\preceq", OperatorInfo(L"\U00002AAF", LayoutTree::Node::cFlavourRel)),
535 make_pair(L"\\succeq", OperatorInfo(L"\U00002AB0", LayoutTree::Node::cFlavourRel)),
536 make_pair(L"\\dashv", OperatorInfo(L"\U000022A3", LayoutTree::Node::cFlavourRel)),
537 make_pair(L"\\asymp", OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
538 make_pair(L"\\doteq", OperatorInfo(L"\U00002250", LayoutTree::Node::cFlavourRel)),
539 make_pair(L"\\parallel", OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourRel)),
540 make_pair(L"\\bowtie", OperatorInfo(L"\U000022C8", LayoutTree::Node::cFlavourRel)),
541 make_pair(L"\\surd", OperatorInfo(L"\U0000221A", LayoutTree::Node::cFlavourOrd)),
542
543 make_pair(L"\\lim", OperatorInfo(L"lim", LayoutTree::Node::cFlavourOp)),
544 make_pair(L"\\sup", OperatorInfo(L"sup", LayoutTree::Node::cFlavourOp)),
545 make_pair(L"\\inf", OperatorInfo(L"inf", LayoutTree::Node::cFlavourOp)),
546 make_pair(L"\\min", OperatorInfo(L"min", LayoutTree::Node::cFlavourOp)),
547 make_pair(L"\\max", OperatorInfo(L"max", LayoutTree::Node::cFlavourOp)),
548 make_pair(L"\\gcd", OperatorInfo(L"gcd", LayoutTree::Node::cFlavourOp)),
549 make_pair(L"\\det", OperatorInfo(L"det", LayoutTree::Node::cFlavourOp)),
550 make_pair(L"\\Pr", OperatorInfo(L"Pr", LayoutTree::Node::cFlavourOp)),
551 // FIX: the space between the words in these operators is maybe a tiny bit too big.
552 make_pair(L"\\limsup", OperatorInfo(L"lim sup", LayoutTree::Node::cFlavourOp)),
553 make_pair(L"\\liminf", OperatorInfo(L"lim inf", LayoutTree::Node::cFlavourOp)),
554 make_pair(L"\\injlim", OperatorInfo(L"inj lim", LayoutTree::Node::cFlavourOp)),
555 make_pair(L"\\projlim", OperatorInfo(L"proj lim", LayoutTree::Node::cFlavourOp)),
556
557 // The translation of \not is special: we record it as a SymbolOperator
558 // in the layout tree, but it gets special handling later.
559 make_pair(L"\\not", OperatorInfo(L"NOT", LayoutTree::Node::cFlavourRel))
560 };
561 wishful_hash_map<wstring, OperatorInfo> operatorTable(
562 operatorArray,
563 END_ARRAY(operatorArray)
564 );
565
566
567 struct IdentifierInfo
568 {
569 bool mIsItalicDefault;
570 wstring mText;
571 LayoutTree::Node::Flavour mFlavour;
572
IdentifierInfoblahtex::IdentifierInfo573 IdentifierInfo(
574 bool isItalicDefault,
575 const wstring& text,
576 LayoutTree::Node::Flavour flavour
577 ) :
578 mIsItalicDefault(isItalicDefault),
579 mText(text),
580 mFlavour(flavour)
581 { }
582 };
583
584 // A list of all commands that get translated as identifiers,
585 // their MathML translations, flavour, and whether they should be
586 // rendered in italic font.
587 pair<wstring, IdentifierInfo> identifierArray[] =
588 {
589 make_pair(L"\\ker", IdentifierInfo(false, L"ker", LayoutTree::Node::cFlavourOp)),
590 make_pair(L"\\deg", IdentifierInfo(false, L"deg", LayoutTree::Node::cFlavourOp)),
591 make_pair(L"\\hom", IdentifierInfo(false, L"hom", LayoutTree::Node::cFlavourOp)),
592 make_pair(L"\\dim", IdentifierInfo(false, L"dim", LayoutTree::Node::cFlavourOp)),
593 make_pair(L"\\arg", IdentifierInfo(false, L"arg", LayoutTree::Node::cFlavourOp)),
594 make_pair(L"\\sin", IdentifierInfo(false, L"sin", LayoutTree::Node::cFlavourOp)),
595 make_pair(L"\\cos", IdentifierInfo(false, L"cos", LayoutTree::Node::cFlavourOp)),
596 make_pair(L"\\sec", IdentifierInfo(false, L"sec", LayoutTree::Node::cFlavourOp)),
597 make_pair(L"\\csc", IdentifierInfo(false, L"csc", LayoutTree::Node::cFlavourOp)),
598 make_pair(L"\\tan", IdentifierInfo(false, L"tan", LayoutTree::Node::cFlavourOp)),
599 make_pair(L"\\cot", IdentifierInfo(false, L"cot", LayoutTree::Node::cFlavourOp)),
600 make_pair(L"\\arcsin", IdentifierInfo(false, L"arcsin", LayoutTree::Node::cFlavourOp)),
601 make_pair(L"\\arccos", IdentifierInfo(false, L"arccos", LayoutTree::Node::cFlavourOp)),
602 make_pair(L"\\arctan", IdentifierInfo(false, L"arctan", LayoutTree::Node::cFlavourOp)),
603 make_pair(L"\\sinh", IdentifierInfo(false, L"sinh", LayoutTree::Node::cFlavourOp)),
604 make_pair(L"\\cosh", IdentifierInfo(false, L"cosh", LayoutTree::Node::cFlavourOp)),
605 make_pair(L"\\tanh", IdentifierInfo(false, L"tanh", LayoutTree::Node::cFlavourOp)),
606 make_pair(L"\\coth", IdentifierInfo(false, L"coth", LayoutTree::Node::cFlavourOp)),
607 make_pair(L"\\log", IdentifierInfo(false, L"log", LayoutTree::Node::cFlavourOp)),
608 make_pair(L"\\lg", IdentifierInfo(false, L"lg", LayoutTree::Node::cFlavourOp)),
609 make_pair(L"\\ln", IdentifierInfo(false, L"ln", LayoutTree::Node::cFlavourOp)),
610 make_pair(L"\\exp", IdentifierInfo(false, L"exp", LayoutTree::Node::cFlavourOp)),
611 make_pair(L"\\aleph", IdentifierInfo(false, L"\U00002135", LayoutTree::Node::cFlavourOrd)),
612 make_pair(L"\\beth", IdentifierInfo(false, L"\U00002136", LayoutTree::Node::cFlavourOrd)),
613 make_pair(L"\\gimel", IdentifierInfo(false, L"\U00002137", LayoutTree::Node::cFlavourOrd)),
614 make_pair(L"\\daleth", IdentifierInfo(false, L"\U00002138", LayoutTree::Node::cFlavourOrd)),
615 make_pair(L"\\wp", IdentifierInfo(true, L"\U00002118", LayoutTree::Node::cFlavourOrd)),
616 make_pair(L"\\ell", IdentifierInfo(true, L"\U00002113", LayoutTree::Node::cFlavourOrd)),
617 make_pair(L"\\P", IdentifierInfo(true, L"\U000000B6", LayoutTree::Node::cFlavourOrd)),
618 make_pair(L"\\imath", IdentifierInfo(true, L"\U00000131", LayoutTree::Node::cFlavourOrd)),
619 make_pair(L"\\Finv", IdentifierInfo(false, L"\U00002132", LayoutTree::Node::cFlavourOrd)),
620 make_pair(L"\\Game", IdentifierInfo(false, L"\U00002141", LayoutTree::Node::cFlavourOrd)),
621 make_pair(L"\\partial", IdentifierInfo(false, L"\U00002202", LayoutTree::Node::cFlavourOrd)),
622 make_pair(L"\\Re", IdentifierInfo(false, L"\U0000211C", LayoutTree::Node::cFlavourOrd)),
623 make_pair(L"\\Im", IdentifierInfo(false, L"\U00002111", LayoutTree::Node::cFlavourOrd)),
624 make_pair(L"\\infty", IdentifierInfo(false, L"\U0000221E", LayoutTree::Node::cFlavourOrd)),
625 make_pair(L"\\hbar", IdentifierInfo(false, L"\U00000127", LayoutTree::Node::cFlavourOrd)),
626 make_pair(L"\\emptyset", IdentifierInfo(false, L"\U00002205", LayoutTree::Node::cFlavourOrd)),
627 make_pair(L"\\varnothing", IdentifierInfo(false, L"\U000000D8", LayoutTree::Node::cFlavourOrd)),
628 make_pair(L"\\S", IdentifierInfo(false, L"\U000000A7", LayoutTree::Node::cFlavourOrd)),
629 make_pair(L"\\AA", IdentifierInfo(false, L"\U000000C5", LayoutTree::Node::cFlavourOrd)),
630 make_pair(L"\\eth", IdentifierInfo(false, L"\U000000F0", LayoutTree::Node::cFlavourOrd)),
631 make_pair(L"\\hslash", IdentifierInfo(false, L"\U0000210F", LayoutTree::Node::cFlavourOrd)),
632 make_pair(L"\\mho", IdentifierInfo(false, L"\U00002127", LayoutTree::Node::cFlavourOrd)),
633 make_pair(L"\\circledR", IdentifierInfo(false, L"\U000000AE", LayoutTree::Node::cFlavourOrd)),
634 make_pair(L"\\yen", IdentifierInfo(false, L"\U000000A5", LayoutTree::Node::cFlavourOrd)),
635 make_pair(L"\\maltese", IdentifierInfo(false, L"\U00002720", LayoutTree::Node::cFlavourOrd)),
636 make_pair(L"\\circledS", IdentifierInfo(false, L"\U000024C8", LayoutTree::Node::cFlavourOrd)),
637 // FIX: these two needs special testing since they're plane-1:
638 // FIX: need to update mediawiki to recognise these entities
639 make_pair(L"\\Bbbk", IdentifierInfo(false, L"\U0001D55C", LayoutTree::Node::cFlavourOrd)),
640 make_pair(L"\\jmath", IdentifierInfo(true, L"\U0001D6A5", LayoutTree::Node::cFlavourOrd))
641 };
642 wishful_hash_map<wstring, IdentifierInfo> identifierTable(
643 identifierArray,
644 END_ARRAY(identifierArray)
645 );
646
647
648 namespace ParseTree
649 {
650
BuildLayoutTree(const TexProcessingState & state) const651 auto_ptr<LayoutTree::Node> MathSymbol::BuildLayoutTree(
652 const TexProcessingState& state
653 ) const
654 {
655 // First check for certain easy-to-handle single character commands,
656 // like letters or numerals.
657 if (mCommand.size() == 1)
658 {
659 bool good = false;
660 bool isNumber = false;
661 // fancyFontsIllegal is set for characters which can't be
662 // displayed in frak, cal or bb fonts.
663 bool fancyFontsIllegal = false;
664 TexMathFont::Family defaultFamily = TexMathFont::cFamilyIt;
665 TexMathFont font = state.mMathFont;
666
667 if (mCommand[0] >= L'A' && mCommand[0] <= L'Z')
668 good = true;
669
670 else if (mCommand[0] >= L'a' && mCommand[0] <= L'z')
671 {
672 fancyFontsIllegal = true;
673 good = true;
674 }
675
676 else if (mCommand[0] >= L'0' && mCommand[0] <= L'9')
677 {
678 fancyFontsIllegal = true;
679 defaultFamily = TexMathFont::cFamilyRm;
680 good = isNumber = true;
681 }
682
683 if (good)
684 {
685 if (font.mFamily == TexMathFont::cFamilyDefault)
686 font.mFamily = defaultFamily;
687
688 if (fancyFontsIllegal &&
689 font.mFamily == TexMathFont::cFamilyCal
690 )
691 throw Exception(
692 L"UnavailableSymbolFontCombination", mCommand, L"cal"
693 );
694
695 if (fancyFontsIllegal &&
696 font.mFamily == TexMathFont::cFamilyBb
697 )
698 throw Exception(
699 L"UnavailableSymbolFontCombination", mCommand, L"bb"
700 );
701
702 if (isNumber)
703 return auto_ptr<LayoutTree::Node>(
704 new LayoutTree::SymbolNumber(
705 mCommand,
706 font.GetMathmlApproximation(),
707 state.mStyle,
708 LayoutTree::Node::cFlavourOrd,
709 LayoutTree::Node::cLimitsDisplayLimits,
710 state.mColour
711 )
712 );
713 else
714 return auto_ptr<LayoutTree::Node>(
715 new LayoutTree::SymbolIdentifier(
716 mCommand,
717 font.GetMathmlApproximation(),
718 state.mStyle,
719 LayoutTree::Node::cFlavourOrd,
720 LayoutTree::Node::cLimitsDisplayLimits,
721 state.mColour
722 )
723 );
724 }
725
726 // Non-ascii characters
727 if (mCommand[0] > 0x7F)
728 throw logic_error(
729 "Unexpected non-ASCII character "
730 "in MathSymbol::BuildLayoutTree"
731 );
732 }
733
734 wishful_hash_map<wstring, wchar_t>::const_iterator
735 lowercaseGreekLookup = lowercaseGreekTable.find(mCommand);
736
737 if (lowercaseGreekLookup != lowercaseGreekTable.end())
738 {
739 return auto_ptr<LayoutTree::Node>(
740 new LayoutTree::SymbolIdentifier(
741 wstring(1, lowercaseGreekLookup->second),
742 // lowercase greek is only affected by the boldsymbol
743 // status, not the family.
744 state.mMathFont.mIsBoldsymbol
745 ? cMathmlFontBoldItalic : cMathmlFontItalic,
746 state.mStyle,
747 LayoutTree::Node::cFlavourOrd,
748 LayoutTree::Node::cLimitsDisplayLimits,
749 state.mColour
750 )
751 );
752 }
753
754 wishful_hash_map<wstring, wchar_t>::const_iterator
755 uppercaseGreekLookup = uppercaseGreekTable.find(mCommand);
756
757 if (uppercaseGreekLookup != uppercaseGreekTable.end())
758 {
759 TexMathFont font = state.mMathFont;
760 if (font.mFamily == TexMathFont::cFamilyCal)
761 throw Exception(
762 L"UnavailableSymbolFontCombination", mCommand, L"cal"
763 );
764
765 if (font.mFamily == TexMathFont::cFamilyBb)
766 throw Exception(
767 L"UnavailableSymbolFontCombination", mCommand, L"bb"
768 );
769
770 if (font.mFamily == TexMathFont::cFamilyFrak)
771 throw Exception(
772 L"UnavailableSymbolFontCombination", mCommand, L"frak"
773 );
774
775 if (font.mFamily == TexMathFont::cFamilyDefault)
776 font.mFamily = TexMathFont::cFamilyRm;
777
778 return auto_ptr<LayoutTree::Node>(
779 new LayoutTree::SymbolIdentifier(
780 wstring(1, uppercaseGreekLookup->second),
781 font.GetMathmlApproximation(),
782 state.mStyle,
783 LayoutTree::Node::cFlavourOrd,
784 LayoutTree::Node::cLimitsDisplayLimits,
785 state.mColour
786 )
787 );
788 }
789
790 wishful_hash_map<wstring, int>::const_iterator
791 spaceLookup = spaceTable.find(mCommand);
792
793 if (spaceLookup != spaceTable.end())
794 {
795 return auto_ptr<LayoutTree::Node>(
796 new LayoutTree::Space(
797 spaceLookup->second,
798 true // true = indicates a user-requested space
799 )
800 );
801 }
802
803 wishful_hash_map<wstring, OperatorInfo>::const_iterator
804 operatorLookup = operatorTable.find(mCommand);
805
806 if (operatorLookup != operatorTable.end())
807 {
808 return auto_ptr<LayoutTree::Node>(
809 new LayoutTree::SymbolOperator(
810 false, L"", // not stretchy
811 false, // not an accent
812 operatorLookup->second.mText,
813 // operators are only affected by the boldsymbol status,
814 // not the family.
815 state.mMathFont.mIsBoldsymbol
816 ? cMathmlFontBold : cMathmlFontNormal,
817 state.mStyle,
818 operatorLookup->second.mFlavour,
819 operatorLookup->second.mLimits,
820 state.mColour
821 )
822 );
823 }
824
825 wishful_hash_map<wstring, IdentifierInfo>::const_iterator
826 identifierLookup = identifierTable.find(mCommand);
827
828 if (identifierLookup != identifierTable.end())
829 {
830 TexMathFont font = state.mMathFont;
831 font.mFamily =
832 identifierLookup->second.mIsItalicDefault
833 ? TexMathFont::cFamilyIt : TexMathFont::cFamilyRm;
834
835 return auto_ptr<LayoutTree::Node>(
836 new LayoutTree::SymbolIdentifier(
837 identifierLookup->second.mText,
838 font.GetMathmlApproximation(),
839 state.mStyle,
840 identifierLookup->second.mFlavour,
841 // For all the "\sin"-like functions:
842 (
843 identifierLookup->second.mFlavour ==
844 LayoutTree::Node::cFlavourOp
845 )
846 ? LayoutTree::Node::cLimitsNoLimits
847 : LayoutTree::Node::cLimitsDisplayLimits,
848 state.mColour
849 )
850 );
851 }
852
853 if (mCommand == L"\\And")
854 {
855 auto_ptr<LayoutTree::Row> row(
856 new LayoutTree::Row(state.mStyle, state.mColour)
857 );
858 row->mFlavour = LayoutTree::Node::cFlavourRel;
859 row->mChildren.push_back(new LayoutTree::Space(5, true));
860 row->mChildren.push_back(
861 new LayoutTree::SymbolOperator(
862 false,
863 L"",
864 false,
865 L"&",
866 state.mMathFont.mIsBoldsymbol
867 ? cMathmlFontBold : cMathmlFontNormal,
868 state.mStyle,
869 LayoutTree::Node::cFlavourOrd,
870 LayoutTree::Node::cLimitsDisplayLimits,
871 state.mColour
872 )
873 );
874 row->mChildren.push_back(new LayoutTree::Space(5, true));
875 return static_cast<auto_ptr<LayoutTree::Node> >(row);
876 }
877
878 if (mCommand == L"\\iff")
879 {
880 auto_ptr<LayoutTree::Row> row(
881 new LayoutTree::Row(state.mStyle, state.mColour)
882 );
883 row->mFlavour = LayoutTree::Node::cFlavourRel;
884 row->mChildren.push_back(new LayoutTree::Space(5, true));
885 // FIX: I would like to make this stretchy and set a particular
886 // size, but for some reason firefox doesn't stretch things
887 // horizontally like this. It DOES do it if the element is in a
888 // <mover> or <munder> etc, but not when it's just by itself.
889 // Very strange. This is mozilla bug 320303.
890 row->mChildren.push_back(
891 new LayoutTree::SymbolOperator(
892 false,
893 L"",
894 false,
895 L"\U000021D4",
896 state.mMathFont.mIsBoldsymbol
897 ? cMathmlFontBold : cMathmlFontNormal,
898 state.mStyle,
899 LayoutTree::Node::cFlavourOrd,
900 LayoutTree::Node::cLimitsDisplayLimits,
901 state.mColour
902 )
903 );
904 row->mChildren.push_back(new LayoutTree::Space(5, true));
905 return static_cast<auto_ptr<LayoutTree::Node> >(row);
906 }
907
908 if (mCommand == L"\\colon")
909 {
910 // FIX: this spacing stuff isn't quite right, but it will hopefully
911 // do. The amsmath package does all kinds of interesting things with
912 // \colon's spacing.
913 auto_ptr<LayoutTree::Row> row(
914 new LayoutTree::Row(state.mStyle, state.mColour)
915 );
916 row->mChildren.push_back(new LayoutTree::Space(2, true));
917 row->mChildren.push_back(
918 new LayoutTree::SymbolOperator(
919 false,
920 L"",
921 false,
922 L":",
923 state.mMathFont.mIsBoldsymbol
924 ? cMathmlFontBold : cMathmlFontNormal,
925 state.mStyle,
926 LayoutTree::Node::cFlavourOrd,
927 LayoutTree::Node::cLimitsDisplayLimits,
928 state.mColour
929 )
930 );
931 row->mChildren.push_back(new LayoutTree::Space(6, true));
932 return static_cast<auto_ptr<LayoutTree::Node> >(row);
933 }
934
935 if (mCommand == L"\\bmod")
936 {
937 auto_ptr<LayoutTree::Row> row(
938 new LayoutTree::Row(state.mStyle, state.mColour)
939 );
940 row->mFlavour = LayoutTree::Node::cFlavourBin;
941 row->mChildren.push_back(new LayoutTree::Space(1, true));
942 row->mChildren.push_back(
943 new LayoutTree::SymbolOperator(
944 false,
945 L"",
946 false,
947 L"mod",
948 state.mMathFont.mIsBoldsymbol
949 ? cMathmlFontBold : cMathmlFontNormal,
950 state.mStyle,
951 LayoutTree::Node::cFlavourOrd,
952 LayoutTree::Node::cLimitsDisplayLimits,
953 state.mColour
954 )
955 );
956 row->mChildren.push_back(new LayoutTree::Space(1, true));
957 return static_cast<auto_ptr<LayoutTree::Node> >(row);
958 }
959
960 if (mCommand == L"\\mod")
961 {
962 auto_ptr<LayoutTree::Row> row(
963 new LayoutTree::Row(state.mStyle, state.mColour)
964 );
965 row->mChildren.push_back(new LayoutTree::Space(18, true));
966 row->mChildren.push_back(
967 new LayoutTree::SymbolOperator(
968 false,
969 L"",
970 false,
971 L"mod",
972 state.mMathFont.mIsBoldsymbol
973 ? cMathmlFontBold : cMathmlFontNormal,
974 state.mStyle,
975 LayoutTree::Node::cFlavourOrd,
976 LayoutTree::Node::cLimitsDisplayLimits,
977 state.mColour
978 )
979 );
980 row->mChildren.push_back(new LayoutTree::Space(6, true));
981 return static_cast<auto_ptr<LayoutTree::Node> >(row);
982 }
983
984 if (mCommand == L"\\varinjlim" || mCommand == L"\\varprojlim" ||
985 mCommand == L"\\varlimsup" || mCommand == L"\\varliminf")
986 {
987 MathmlFont font =
988 state.mMathFont.mIsBoldsymbol
989 ? cMathmlFontBold : cMathmlFontNormal;
990
991 auto_ptr<LayoutTree::Node> base(
992 new LayoutTree::SymbolOperator(
993 false,
994 L"",
995 false,
996 L"lim",
997 font,
998 state.mStyle,
999 LayoutTree::Node::cFlavourOp,
1000 LayoutTree::Node::cLimitsLimits,
1001 state.mColour
1002 )
1003 );
1004
1005 auto_ptr<LayoutTree::Scripts> node(
1006 new LayoutTree::Scripts(
1007 state.mStyle,
1008 LayoutTree::Node::cFlavourOp,
1009 LayoutTree::Node::cLimitsDisplayLimits,
1010 state.mColour,
1011 false,
1012 base,
1013 auto_ptr<LayoutTree::Node>(),
1014 auto_ptr<LayoutTree::Node>()
1015 )
1016 );
1017
1018 if (mCommand == L"\\varinjlim")
1019 node->mLower = auto_ptr<LayoutTree::Node>(
1020 new LayoutTree::SymbolOperator(
1021 false,
1022 L"",
1023 true,
1024 L"\U00002192",
1025 font,
1026 state.mStyle,
1027 LayoutTree::Node::cFlavourOrd,
1028 LayoutTree::Node::cLimitsDisplayLimits,
1029 state.mColour
1030 )
1031 );
1032
1033 else if (mCommand == L"\\varprojlim")
1034 node->mLower = auto_ptr<LayoutTree::Node>(
1035 new LayoutTree::SymbolOperator(
1036 false,
1037 L"",
1038 true,
1039 L"\U00002190",
1040 font,
1041 state.mStyle,
1042 LayoutTree::Node::cFlavourOrd,
1043 LayoutTree::Node::cLimitsDisplayLimits,
1044 state.mColour
1045 )
1046 );
1047
1048 else if (mCommand == L"\\varliminf")
1049 node->mLower = auto_ptr<LayoutTree::Node>(
1050 new LayoutTree::SymbolOperator(
1051 true,
1052 L"",
1053 true,
1054 L"\U000000AF",
1055 font,
1056 state.mStyle,
1057 LayoutTree::Node::cFlavourOrd,
1058 LayoutTree::Node::cLimitsDisplayLimits,
1059 state.mColour
1060 )
1061 );
1062
1063 else if (mCommand == L"\\varlimsup")
1064 node->mUpper = auto_ptr<LayoutTree::Node>(
1065 new LayoutTree::SymbolOperator(
1066 true,
1067 L"",
1068 true,
1069 L"\U000000AF",
1070 font,
1071 state.mStyle,
1072 LayoutTree::Node::cFlavourOrd,
1073 LayoutTree::Node::cLimitsDisplayLimits,
1074 state.mColour
1075 )
1076 );
1077
1078 return static_cast<auto_ptr<LayoutTree::Node> >(node);
1079 }
1080
1081 throw logic_error("Unexpected command in MathSymbol::BuildLayoutTree");
1082 }
1083
1084 }
1085 }
1086
1087 // end of file @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1088