text: /*
  blahtex: a TeX to MathML converter designed with MediaWiki in mind
  blahtexml: an extension of blahtex with XML processing in mind
  http://gva.noekeon.org/blahtexml
  
  Copyright (c) 2006, David Harvey
  All rights reserved.
  
  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  
      * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
      * 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.
      * 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.
  
  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.
  */
  
  #include <stdexcept>
  #include "ParseTree.h"
  
  using namespace std;
  
  namespace blahtex
  {
  
  pair<wstring, wchar_t> lowercaseGreekArray[] =
  {
      make_pair(L"\\alpha",      L'\U000003B1'),
      make_pair(L"\\beta",       L'\U000003B2'),
      make_pair(L"\\gamma",      L'\U000003B3'),
      make_pair(L"\\delta",      L'\U000003B4'),
      make_pair(L"\\epsilon",    L'\U000003F5'),  // straightepsilon
      make_pair(L"\\varepsilon", L'\U000003B5'),  // varepsilon
      make_pair(L"\\zeta",       L'\U000003B6'),
      make_pair(L"\\eta",        L'\U000003B7'),
      make_pair(L"\\theta",      L'\U000003B8'),
      make_pair(L"\\vartheta",   L'\U000003D1'),
      make_pair(L"\\iota",       L'\U000003B9'),
      make_pair(L"\\kappa",      L'\U000003BA'),
      make_pair(L"\\varkappa",   L'\U000003F0'),
      make_pair(L"\\lambda",     L'\U000003BB'),
      make_pair(L"\\mu",         L'\U000003BC'),
      make_pair(L"\\nu",         L'\U000003BD'),
      make_pair(L"\\pi",         L'\U000003C0'),
      make_pair(L"\\varpi",      L'\U000003D6'),
      make_pair(L"\\rho",        L'\U000003C1'),
      make_pair(L"\\varrho",     L'\U000003F1'),
      make_pair(L"\\sigma",      L'\U000003C3'),
      make_pair(L"\\varsigma",   L'\U000003C2'),
      make_pair(L"\\tau",        L'\U000003C4'),
      make_pair(L"\\upsilon",    L'\U000003C5'),
      make_pair(L"\\phi",        L'\U000003D5'),  // straightphi
      make_pair(L"\\varphi",     L'\U000003C6'),
      make_pair(L"\\chi",        L'\U000003C7'),
      make_pair(L"\\psi",        L'\U000003C8'),
      make_pair(L"\\omega",      L'\U000003C9'),
      make_pair(L"\\xi",         L'\U000003BE'),
      make_pair(L"\\digamma",    L'\U000003DD')
  };
  wishful_hash_map<wstring, wchar_t> lowercaseGreekTable(
      lowercaseGreekArray,
      END_ARRAY(lowercaseGreekArray)
  );
  
  
  pair<wstring, wchar_t> uppercaseGreekArray[] =
  {
      make_pair(L"\\Gamma",     L'\U00000393'),
      make_pair(L"\\Delta",     L'\U00000394'),
      make_pair(L"\\Theta",     L'\U00000398'),
      make_pair(L"\\Lambda",    L'\U0000039B'),
      make_pair(L"\\Pi",        L'\U000003A0'),
      make_pair(L"\\Sigma",     L'\U000003A3'),
      make_pair(L"\\Upsilon",   L'\U000003A5'),
      make_pair(L"\\Phi",       L'\U000003A6'),
      make_pair(L"\\Psi",       L'\U000003A8'),
      make_pair(L"\\Omega",     L'\U000003A9'),
      make_pair(L"\\Xi",        L'\U0000039E')
  };
  wishful_hash_map<wstring, wchar_t> uppercaseGreekTable(
      uppercaseGreekArray,
      END_ARRAY(uppercaseGreekArray)
  );
  
  
  pair<wstring, int> spaceArray[] =
  {
      make_pair(L"\\!",       -3),
      make_pair(L"\\,",       3),
      make_pair(L"\\>",       4),
      make_pair(L"\\;",       5),
      make_pair(L"\\quad",    18),
      make_pair(L"\\qquad",   36),
      // These last two aren't quite right, but hopefully they're close
      // enough. TeX's rules are too complicated for me to care :-)
      make_pair(L"~",         6),
      make_pair(L"\\ ",       6)
  };
  wishful_hash_map<wstring, int> spaceTable(
      spaceArray,
      END_ARRAY(spaceArray)
  );
  
  
  struct OperatorInfo
  {
      wstring mText;
      LayoutTree::Node::Flavour mFlavour;
      LayoutTree::Node::Limits mLimits;
  
      OperatorInfo(
          const wstring& text,
          LayoutTree::Node::Flavour flavour,
          LayoutTree::Node::Limits limits =
              LayoutTree::Node::cLimitsDisplayLimits
      ) :
          mText(text),
          mFlavour(flavour),
          mLimits(limits)
      { }
  };
  
  // Here is a list of all commands that get translated as operators,
  // together with their MathML translation and flavour.
  pair<wstring, OperatorInfo> operatorArray[] =
  {
      make_pair(L"(",                      OperatorInfo(L"(", LayoutTree::Node::cFlavourOpen)),
      make_pair(L")",                      OperatorInfo(L")", LayoutTree::Node::cFlavourClose)),
      make_pair(L"[",                      OperatorInfo(L"[", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"]",                      OperatorInfo(L"]", LayoutTree::Node::cFlavourClose)),
      make_pair(L"<",                      OperatorInfo(L"<", LayoutTree::Node::cFlavourRel)),
      make_pair(L">",                      OperatorInfo(L">", LayoutTree::Node::cFlavourRel)),
      make_pair(L"+",                      OperatorInfo(L"+", LayoutTree::Node::cFlavourBin)),
      make_pair(L"-",                      OperatorInfo(L"-", LayoutTree::Node::cFlavourBin)),
      make_pair(L"=",                      OperatorInfo(L"=", LayoutTree::Node::cFlavourRel)),
      make_pair(L"|",                      OperatorInfo(L"|", LayoutTree::Node::cFlavourOrd)),
      make_pair(L";",                      OperatorInfo(L";", LayoutTree::Node::cFlavourPunct)),
      make_pair(L":",                      OperatorInfo(L":", LayoutTree::Node::cFlavourRel)),
      make_pair(L",",                      OperatorInfo(L",", LayoutTree::Node::cFlavourPunct)),
      make_pair(L".",                      OperatorInfo(L".", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"/",                      OperatorInfo(L"/", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"?",                      OperatorInfo(L"?", LayoutTree::Node::cFlavourClose)),
      make_pair(L"!",                      OperatorInfo(L"!", LayoutTree::Node::cFlavourClose)),
      make_pair(L"@",                      OperatorInfo(L"@", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"*",                      OperatorInfo(L"*", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\_",                    OperatorInfo(L"_", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\&",                    OperatorInfo(L"&", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\$",                    OperatorInfo(L"$", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\#",                    OperatorInfo(L"#", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\%",                    OperatorInfo(L"%", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\{",                    OperatorInfo(L"{", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\}",                    OperatorInfo(L"}", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\ast",                  OperatorInfo(L"*", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\lbrace",               OperatorInfo(L"{", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rbrace",               OperatorInfo(L"}", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\vert",                 OperatorInfo(L"|", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\lvert",                OperatorInfo(L"|", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rvert",                OperatorInfo(L"|", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\lbrack",               OperatorInfo(L"[", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rbrack",               OperatorInfo(L"]", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\Vert",                 OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\lVert",                OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rVert",                OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\lfloor",               OperatorInfo(L"\U0000230A", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rfloor",               OperatorInfo(L"\U0000230B", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\lceil",                OperatorInfo(L"\U00002308", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rceil",                OperatorInfo(L"\U00002309", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\langle",               OperatorInfo(L"\U00002329", LayoutTree::Node::cFlavourOpen)),
      make_pair(L"\\rangle",               OperatorInfo(L"\U0000232A", LayoutTree::Node::cFlavourClose)),
      make_pair(L"\\forall",               OperatorInfo(L"\U00002200", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\exists",               OperatorInfo(L"\U00002203", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\leftarrow",            OperatorInfo(L"\U00002190", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightarrow",           OperatorInfo(L"\U00002192", LayoutTree::Node::cFlavourRel)),
  
      // FIX: The first version below has the correct MathML characters.
      // They seem to be missing in the fonts currently shipped with
      // Firefox, so we just map them to their short counterparts (second
      // version) for the moment.
      // FIX: perhaps it's possible to do this with the "stretchy" attribute
      // instead?
  #if 0
      make_pair(L"\\longleftarrow",        OperatorInfo(L"\U000027F5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longrightarrow",       OperatorInfo(L"\U000027F6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longleftarrow",        OperatorInfo(L"\U000027F8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longrightarrow",       OperatorInfo(L"\U000027F9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longmapsto",           OperatorInfo(L"\U000027FC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longleftrightarrow",   OperatorInfo(L"\U000027F7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longleftrightarrow",   OperatorInfo(L"\U000027FA", LayoutTree::Node::cFlavourRel)),
  #else
      make_pair(L"\\longleftarrow",        OperatorInfo(L"\U00002190", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longrightarrow",       OperatorInfo(L"\U00002192", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longleftarrow",        OperatorInfo(L"\U000021D0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longrightarrow",       OperatorInfo(L"\U000021D2", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longmapsto",           OperatorInfo(L"\U000021A6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\longleftrightarrow",   OperatorInfo(L"\U00002194", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Longleftrightarrow",   OperatorInfo(L"\U000021D4", LayoutTree::Node::cFlavourRel)),
  #endif
  
      make_pair(L"\\Leftarrow",            OperatorInfo(L"\U000021D0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Rightarrow",           OperatorInfo(L"\U000021D2", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\mapsto",               OperatorInfo(L"\U000021A6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftrightarrow",       OperatorInfo(L"\U00002194", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Leftrightarrow",       OperatorInfo(L"\U000021D4", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\uparrow",              OperatorInfo(L"\U00002191", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Uparrow",              OperatorInfo(L"\U000021D1", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\downarrow",            OperatorInfo(L"\U00002193", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Downarrow",            OperatorInfo(L"\U000021D3", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\updownarrow",          OperatorInfo(L"\U00002195", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Updownarrow",          OperatorInfo(L"\U000021D5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\searrow",              OperatorInfo(L"\U00002198", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nearrow",              OperatorInfo(L"\U00002197", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\swarrow",              OperatorInfo(L"\U00002199", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nwarrow",              OperatorInfo(L"\U00002196", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\hookrightarrow",       OperatorInfo(L"\U000021AA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\hookleftarrow",        OperatorInfo(L"\U000021A9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\upharpoonright",       OperatorInfo(L"\U000021BE", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\upharpoonleft",        OperatorInfo(L"\U000021BF", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\downharpoonright",     OperatorInfo(L"\U000021C2", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\downharpoonleft",      OperatorInfo(L"\U000021C3", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightharpoonup",       OperatorInfo(L"\U000021C0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightharpoondown",     OperatorInfo(L"\U000021C1", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftharpoonup",        OperatorInfo(L"\U000021BC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftharpoondown",      OperatorInfo(L"\U000021BD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nleftarrow",           OperatorInfo(L"\U0000219A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nrightarrow",          OperatorInfo(L"\U0000219B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supset",               OperatorInfo(L"\U00002283", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subset",               OperatorInfo(L"\U00002282", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supseteq",             OperatorInfo(L"\U00002287", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subseteq",             OperatorInfo(L"\U00002286", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\sqsupset",             OperatorInfo(L"\U00002290", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\sqsubset",             OperatorInfo(L"\U0000228F", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\sqsupseteq",           OperatorInfo(L"\U00002292", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\sqsubseteq",           OperatorInfo(L"\U00002291", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supsetneq",            OperatorInfo(L"\U0000228B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subsetneq",            OperatorInfo(L"\U0000228A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\in",                   OperatorInfo(L"\U00002208", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ni",                   OperatorInfo(L"\U0000220B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\notin",                OperatorInfo(L"\U00002209", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\mid",                  OperatorInfo(L"|",          LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\sim",                  OperatorInfo(L"\U0000223C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\simeq",                OperatorInfo(L"\U00002243", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\approx",               OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\propto",               OperatorInfo(L"\U0000221D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\equiv",                OperatorInfo(L"\U00002261", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\cong",                 OperatorInfo(L"\U00002245", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\neq",                  OperatorInfo(L"\U00002260", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ll",                   OperatorInfo(L"\U0000226A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gg",                   OperatorInfo(L"\U0000226B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\geq",                  OperatorInfo(L"\U00002265", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leq",                  OperatorInfo(L"\U00002264", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\triangleleft",         OperatorInfo(L"\U000025C3", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\triangleright",        OperatorInfo(L"\U000025B9", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\models",               OperatorInfo(L"\U000022A7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\vdash",                OperatorInfo(L"\U000022A2", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Vdash",                OperatorInfo(L"\U000022A9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\vDash",                OperatorInfo(L"\U000022A8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lesssim",              OperatorInfo(L"\U00002272", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nless",                OperatorInfo(L"\U0000226E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ngeq",                 OperatorInfo(L"\U00002271", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nleq",                 OperatorInfo(L"\U00002270", LayoutTree::Node::cFlavourRel)),
  
      // FIX: the fonts shipped with Firefox 1.5 don't know about
      // 0x2a2f (&Cross;). So I'm mapping it to 0xd7 (&times;) for now.
  #if 0
      make_pair(L"\\times",                OperatorInfo(L"\U00002A2F", LayoutTree::Node::cFlavourBin)),
  #else
      make_pair(L"\\times",                OperatorInfo(L"\U000000D7", LayoutTree::Node::cFlavourBin)),
  #endif
  
      make_pair(L"\\div",                  OperatorInfo(L"\U000000F7", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\wedge",                OperatorInfo(L"\U00002227", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\vee",                  OperatorInfo(L"\U00002228", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\oplus",                OperatorInfo(L"\U00002295", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\otimes",               OperatorInfo(L"\U00002297", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\cap",                  OperatorInfo(L"\U00002229", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\cup",                  OperatorInfo(L"\U0000222A", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\sqcap",                OperatorInfo(L"\U00002293", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\sqcup",                OperatorInfo(L"\U00002294", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\smile",                OperatorInfo(L"\U00002323", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\frown",                OperatorInfo(L"\U00002322", LayoutTree::Node::cFlavourRel)),
      // FIX: how to make these smiles/frowns smaller?
      make_pair(L"\\smallsmile",           OperatorInfo(L"\U00002323", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\smallfrown",           OperatorInfo(L"\U00002322", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\setminus",             OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourBin)),
      // FIX: how to make smallsetminus smaller?
      make_pair(L"\\smallsetminus",        OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\star",                 OperatorInfo(L"\U000022C6", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\triangle",             OperatorInfo(L"\U000025B3", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\wr",                   OperatorInfo(L"\U00002240", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\circ",                 OperatorInfo(L"\U00002218", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\lnot",                 OperatorInfo(L"\U000000AC", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\nabla",                OperatorInfo(L"\U00002207", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\prime",                OperatorInfo(L"\U00002032", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\backslash",            OperatorInfo(L"\U00002216", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\pm",                   OperatorInfo(L"\U000000B1", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\mp",                   OperatorInfo(L"\U00002213", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\angle",                OperatorInfo(L"\U00002220", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\nmid",                 OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\square",               OperatorInfo(L"\U000025A1", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\Box",                  OperatorInfo(L"\U000025A1", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\checkmark",            OperatorInfo(L"\U00002713", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\complement",           OperatorInfo(L"\U00002201", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\flat",                 OperatorInfo(L"\U0000266D", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\sharp",                OperatorInfo(L"\U0000266F", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\natural",              OperatorInfo(L"\U0000266E", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\bullet",               OperatorInfo(L"\U00002022", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\dagger",               OperatorInfo(L"\U00002020", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\ddagger",              OperatorInfo(L"\U00002021", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\clubsuit",             OperatorInfo(L"\U00002663", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\spadesuit",            OperatorInfo(L"\U00002660", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\heartsuit",            OperatorInfo(L"\U00002665", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\diamondsuit",          OperatorInfo(L"\U00002666", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\top",                  OperatorInfo(L"\U000022A4", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\bot",                  OperatorInfo(L"\U000022A5", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\perp",                 OperatorInfo(L"\U000022A5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\cdot",                 OperatorInfo(L"\U000022C5", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\vdots",                OperatorInfo(L"\U000022EE", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\ddots",                OperatorInfo(L"\U000022F1", LayoutTree::Node::cFlavourInner)),
      make_pair(L"\\cdots",                OperatorInfo(L"\U000022EF", LayoutTree::Node::cFlavourInner)),
      make_pair(L"\\ldots",                OperatorInfo(L"\U00002026", LayoutTree::Node::cFlavourInner)),
      // FIX: these next two aren't right. The amsmath package does tricky
      // things so that the dots change their vertical position depending
      // on the surrounding operators. We chicken out and just map them
      // to the same as \cdots and \ldots respectively.
      make_pair(L"\\dotsb",                OperatorInfo(L"\U000022EF", LayoutTree::Node::cFlavourInner)),
      make_pair(L"\\dots",                 OperatorInfo(L"\U00002026", LayoutTree::Node::cFlavourInner)),
      make_pair(L"\\sum",                  OperatorInfo(L"\U00002211", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\prod",                 OperatorInfo(L"\U0000220F", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\int",                  OperatorInfo(L"\U0000222B", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
      make_pair(L"\\iint",                 OperatorInfo(L"\U0000222C", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
      make_pair(L"\\iiint",                OperatorInfo(L"\U0000222D", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
      make_pair(L"\\iiiint",               OperatorInfo(L"\U00002A0C", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
      make_pair(L"\\oint",                 OperatorInfo(L"\U0000222E", LayoutTree::Node::cFlavourOp, LayoutTree::Node::cLimitsNoLimits)),
      make_pair(L"\\bigcap",               OperatorInfo(L"\U000022C2", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigodot",              OperatorInfo(L"\U00002A00", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigcup",               OperatorInfo(L"\U000022C3", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigotimes",            OperatorInfo(L"\U00002A02", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\coprod",               OperatorInfo(L"\U00002210", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigsqcup",             OperatorInfo(L"\U00002A06", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigoplus",             OperatorInfo(L"\U00002A01", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigvee",               OperatorInfo(L"\U000022C1", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\biguplus",             OperatorInfo(L"\U00002A04", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\bigwedge",             OperatorInfo(L"\U000022C0", LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\ulcorner",             OperatorInfo(L"\U0000231C", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\urcorner",             OperatorInfo(L"\U0000231D", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\llcorner",             OperatorInfo(L"\U0000231E", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\lrcorner",             OperatorInfo(L"\U0000231F", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\dashrightarrow",       OperatorInfo(L"\U0000290F", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\dashleftarrow",        OperatorInfo(L"\U0000290E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\backprime",            OperatorInfo(L"\U00002035", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\vartriangle",          OperatorInfo(L"\U000025B5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\blacktriangle",        OperatorInfo(L"\U000025B4", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\triangledown",         OperatorInfo(L"\U000025BF", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\blacktriangledown",    OperatorInfo(L"\U000025BE", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\blacksquare",          OperatorInfo(L"\U000025FC", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\lozenge",              OperatorInfo(L"\U000025CA", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\blacklozenge",         OperatorInfo(L"\U000029EB", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\bigstar",              OperatorInfo(L"\U00002605", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\sphericalangle",       OperatorInfo(L"\U00002222", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\measuredangle",        OperatorInfo(L"\U00002221", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\dotplus",              OperatorInfo(L"\U00002214", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\ltimes",               OperatorInfo(L"\U000022C9", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\rtimes",               OperatorInfo(L"\U000022CA", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\Cap",                  OperatorInfo(L"\U000022D2", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\leftthreetimes",       OperatorInfo(L"\U000022CB", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\rightthreetimes",      OperatorInfo(L"\U000022CC", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\Cup",                  OperatorInfo(L"\U000022D3", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\barwedge",             OperatorInfo(L"\U00002305", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\curlywedge",           OperatorInfo(L"\U000022CF", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\veebar",               OperatorInfo(L"\U000022BB", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\curlyvee",             OperatorInfo(L"\U000022CE", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\doublebarwedge",       OperatorInfo(L"\U00002306", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\boxminus",             OperatorInfo(L"\U0000229F", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\circleddash",          OperatorInfo(L"\U0000229D", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\boxtimes",             OperatorInfo(L"\U000022A0", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\circledast",           OperatorInfo(L"\U0000229B", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\boxdot",               OperatorInfo(L"\U000022A1", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\circledcirc",          OperatorInfo(L"\U0000229A", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\boxplus",              OperatorInfo(L"\U0000229E", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\centerdot",            OperatorInfo(L"\U000022C5", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\divideontimes",        OperatorInfo(L"\U000022C7", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\intercal",             OperatorInfo(L"\U000022BA", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\leqq",                 OperatorInfo(L"\U00002266", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\geqq",                 OperatorInfo(L"\U00002267", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leqslant",             OperatorInfo(L"\U00002A7D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\geqslant",             OperatorInfo(L"\U00002A7E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\eqslantless",          OperatorInfo(L"\U00002A95", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\eqslantgtr",           OperatorInfo(L"\U00002A96", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gtrsim",               OperatorInfo(L"\U00002273", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lessapprox",           OperatorInfo(L"\U00002A85", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gtrapprox",            OperatorInfo(L"\U00002A86", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\approxeq",             OperatorInfo(L"\U0000224A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\eqsim",                OperatorInfo(L"\U00002242", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lessdot",              OperatorInfo(L"\U000022D6", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\gtrdot",               OperatorInfo(L"\U000022D7", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\lll",                  OperatorInfo(L"\U000022D8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ggg",                  OperatorInfo(L"\U000022D9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lessgtr",              OperatorInfo(L"\U00002276", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gtrless",              OperatorInfo(L"\U00002277", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lesseqgtr",            OperatorInfo(L"\U000022DA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gtreqless",            OperatorInfo(L"\U000022DB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lesseqqgtr",           OperatorInfo(L"\U00002A8B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gtreqqless",           OperatorInfo(L"\U00002A8C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\doteqdot",             OperatorInfo(L"\U00002251", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\eqcirc",               OperatorInfo(L"\U00002256", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\risingdotseq",         OperatorInfo(L"\U00002253", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\circeq",               OperatorInfo(L"\U00002257", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\fallingdotseq",        OperatorInfo(L"\U00002252", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\triangleq",            OperatorInfo(L"\U0000225C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\backsim",              OperatorInfo(L"\U0000223D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\thicksim",             OperatorInfo(L"\U0000223C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\backsimeq",            OperatorInfo(L"\U000022CD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\thickapprox",          OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subseteqq",            OperatorInfo(L"\U00002AC5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supseteqq",            OperatorInfo(L"\U00002AC6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Subset",               OperatorInfo(L"\U000022D0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Supset",               OperatorInfo(L"\U000022D1", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\preccurlyeq",          OperatorInfo(L"\U0000227C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succcurlyeq",          OperatorInfo(L"\U0000227D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\curlyeqprec",          OperatorInfo(L"\U000022DE", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\curlyeqsucc",          OperatorInfo(L"\U000022DF", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\precsim",              OperatorInfo(L"\U0000227E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succsim",              OperatorInfo(L"\U0000227F", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\precapprox",           OperatorInfo(L"\U00002AB7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succapprox",           OperatorInfo(L"\U00002AB8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Vvdash",               OperatorInfo(L"\U000022AA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\shortmid",             OperatorInfo(L"\U00002223", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\shortparallel",        OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\bumpeq",               OperatorInfo(L"\U0000224F", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\between",              OperatorInfo(L"\U0000226C", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Bumpeq",               OperatorInfo(L"\U0000224E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\varpropto",            OperatorInfo(L"\U0000221D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\backepsilon",          OperatorInfo(L"\U000003F6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\blacktriangleleft",    OperatorInfo(L"\U000025C0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\blacktriangleright",   OperatorInfo(L"\U000025B6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\therefore",            OperatorInfo(L"\U00002234", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\because",              OperatorInfo(L"\U00002235", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ngtr",                 OperatorInfo(L"\U0000226F", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nleqslant",            OperatorInfo(L"\U00002A7D\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ngeqslant",            OperatorInfo(L"\U00002A7E\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nleqq",                OperatorInfo(L"\U00002266\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ngeqq",                OperatorInfo(L"\U00002267\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lneqq",                OperatorInfo(L"\U00002268", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gneqq",                OperatorInfo(L"\U00002269", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lvertneqq",            OperatorInfo(L"\U00002268\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gvertneqq",            OperatorInfo(L"\U00002269\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lnsim",                OperatorInfo(L"\U000022E6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gnsim",                OperatorInfo(L"\U000022E7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\lnapprox",             OperatorInfo(L"\U00002A89", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\gnapprox",             OperatorInfo(L"\U00002A8A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nprec",                OperatorInfo(L"\U00002280", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsucc",                OperatorInfo(L"\U00002281", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\npreceq",              OperatorInfo(L"\U00002AAF\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsucceq",              OperatorInfo(L"\U00002AB0\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\precneqq",             OperatorInfo(L"\U00002AB5", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succneqq",             OperatorInfo(L"\U00002AB6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\precnsim",             OperatorInfo(L"\U000022E8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succnsim",             OperatorInfo(L"\U000022E9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\precnapprox",          OperatorInfo(L"\U00002AB9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succnapprox",          OperatorInfo(L"\U00002ABA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsim",                 OperatorInfo(L"\U00002241", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ncong",                OperatorInfo(L"\U00002247", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nshortmid",            OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nshortparallel",       OperatorInfo(L"\U00002226", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nmid",                 OperatorInfo(L"\U00002224", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nparallel",            OperatorInfo(L"\U00002226", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nvdash",               OperatorInfo(L"\U000022AC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nvDash",               OperatorInfo(L"\U000022AD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nVdash",               OperatorInfo(L"\U000022AE", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nVDash",               OperatorInfo(L"\U000022AF", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ntriangleleft",        OperatorInfo(L"\U000022EA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ntriangleright",       OperatorInfo(L"\U000022EB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ntrianglelefteq",      OperatorInfo(L"\U000022EC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\ntrianglerighteq",     OperatorInfo(L"\U000022ED", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsubseteq",            OperatorInfo(L"\U00002288", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsupseteq",            OperatorInfo(L"\U00002289", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsubseteqq",           OperatorInfo(L"\U00002AC5\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nsupseteqq",           OperatorInfo(L"\U00002AC6\U00000338", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subsetneq",            OperatorInfo(L"\U0000228A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supsetneq",            OperatorInfo(L"\U0000228B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\varsubsetneq",         OperatorInfo(L"\U0000228A\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\varsupsetneq",         OperatorInfo(L"\U0000228B\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\subsetneqq",           OperatorInfo(L"\U00002ACB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\supsetneqq",           OperatorInfo(L"\U00002ACC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\varsubsetneqq",        OperatorInfo(L"\U00002ACB\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\varsupsetneqq",        OperatorInfo(L"\U00002ACC\U0000FE00", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftleftarrows",       OperatorInfo(L"\U000021C7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightrightarrows",     OperatorInfo(L"\U000021C9", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftrightarrows",      OperatorInfo(L"\U000021C6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightleftarrows",      OperatorInfo(L"\U000021C4", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Lleftarrow",           OperatorInfo(L"\U000021DA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Rrightarrow",          OperatorInfo(L"\U000021DB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\twoheadleftarrow",     OperatorInfo(L"\U0000219E", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\twoheadrightarrow",    OperatorInfo(L"\U000021A0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftarrowtail",        OperatorInfo(L"\U000021A2", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightarrowtail",       OperatorInfo(L"\U000021A3", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\looparrowleft",        OperatorInfo(L"\U000021AB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\looparrowright",       OperatorInfo(L"\U000021AC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftrightharpoons",    OperatorInfo(L"\U000021CB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightleftharpoons",    OperatorInfo(L"\U000021CC", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\curvearrowleft",       OperatorInfo(L"\U000021B6", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\curvearrowright",      OperatorInfo(L"\U000021B7", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\circlearrowleft",      OperatorInfo(L"\U000021BA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\circlearrowright",     OperatorInfo(L"\U000021BB", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Lsh",                  OperatorInfo(L"\U000021B0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\Rsh",                  OperatorInfo(L"\U000021B1", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\upuparrows",           OperatorInfo(L"\U000021C8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\downdownarrows",       OperatorInfo(L"\U000021CA", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\multimap",             OperatorInfo(L"\U000022B8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\rightsquigarrow",      OperatorInfo(L"\U0000219D", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\leftrightsquigarrow",  OperatorInfo(L"\U000021AD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nLeftarrow",           OperatorInfo(L"\U000021CD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nRightarrow",          OperatorInfo(L"\U000021CF", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nleftrightarrow",      OperatorInfo(L"\U000021AE", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nLeftrightarrow",      OperatorInfo(L"\U000021CE", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\pitchfork",            OperatorInfo(L"\U000022D4", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\nexists",              OperatorInfo(L"\U00002204", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\lhd",                  OperatorInfo(L"\U000022B2", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\rhd",                  OperatorInfo(L"\U000022B3", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\unlhd",                OperatorInfo(L"\U000022B4", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\unrhd",                OperatorInfo(L"\U000022B5", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\leadsto",              OperatorInfo(L"\U000021DD", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\uplus",                OperatorInfo(L"\U0000228E", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\diamond",              OperatorInfo(L"\U000022C4", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\bigtriangleup",        OperatorInfo(L"\U000025B3", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\bigtriangledown",      OperatorInfo(L"\U000025BD", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\ominus",               OperatorInfo(L"\U00002296", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\oslash",               OperatorInfo(L"\U00002298", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\odot",                 OperatorInfo(L"\U00002299", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\bigcirc",              OperatorInfo(L"\U000025EF", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\amalg",                OperatorInfo(L"\U00002A3F", LayoutTree::Node::cFlavourBin)),
      make_pair(L"\\prec",                 OperatorInfo(L"\U0000227A", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succ",                 OperatorInfo(L"\U0000227B", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\preceq",               OperatorInfo(L"\U00002AAF", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\succeq",               OperatorInfo(L"\U00002AB0", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\dashv",                OperatorInfo(L"\U000022A3", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\asymp",                OperatorInfo(L"\U00002248", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\doteq",                OperatorInfo(L"\U00002250", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\parallel",             OperatorInfo(L"\U00002225", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\bowtie",               OperatorInfo(L"\U000022C8", LayoutTree::Node::cFlavourRel)),
      make_pair(L"\\surd",                 OperatorInfo(L"\U0000221A", LayoutTree::Node::cFlavourOrd)),
  
      make_pair(L"\\lim",                  OperatorInfo(L"lim",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\sup",                  OperatorInfo(L"sup",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\inf",                  OperatorInfo(L"inf",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\min",                  OperatorInfo(L"min",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\max",                  OperatorInfo(L"max",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\gcd",                  OperatorInfo(L"gcd",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\det",                  OperatorInfo(L"det",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\Pr",                   OperatorInfo(L"Pr",         LayoutTree::Node::cFlavourOp)),
      // FIX: the space between the words in these operators is maybe a tiny bit too big.
      make_pair(L"\\limsup",               OperatorInfo(L"lim sup",    LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\liminf",               OperatorInfo(L"lim inf",    LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\injlim",               OperatorInfo(L"inj lim",    LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\projlim",              OperatorInfo(L"proj lim",   LayoutTree::Node::cFlavourOp)),
      
      // The translation of \not is special: we record it as a SymbolOperator
      // in the layout tree, but it gets special handling later.
      make_pair(L"\\not",                  OperatorInfo(L"NOT", LayoutTree::Node::cFlavourRel))
  };
  wishful_hash_map<wstring, OperatorInfo> operatorTable(
      operatorArray,
      END_ARRAY(operatorArray)
  );
  
  
  struct IdentifierInfo
  {
      bool mIsItalicDefault;
      wstring mText;
      LayoutTree::Node::Flavour mFlavour;
  
      IdentifierInfo(
          bool isItalicDefault,
          const wstring& text,
          LayoutTree::Node::Flavour flavour
      ) :
          mIsItalicDefault(isItalicDefault),
          mText(text),
          mFlavour(flavour)
      { }
  };
  
  // A list of all commands that get translated as identifiers,
  // their MathML translations, flavour, and whether they should be
  // rendered in italic font.
  pair<wstring, IdentifierInfo> identifierArray[] =
  {
      make_pair(L"\\ker",         IdentifierInfo(false, L"ker",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\deg",         IdentifierInfo(false, L"deg",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\hom",         IdentifierInfo(false, L"hom",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\dim",         IdentifierInfo(false, L"dim",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\arg",         IdentifierInfo(false, L"arg",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\sin",         IdentifierInfo(false, L"sin",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\cos",         IdentifierInfo(false, L"cos",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\sec",         IdentifierInfo(false, L"sec",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\csc",         IdentifierInfo(false, L"csc",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\tan",         IdentifierInfo(false, L"tan",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\cot",         IdentifierInfo(false, L"cot",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\arcsin",      IdentifierInfo(false, L"arcsin",     LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\arccos",      IdentifierInfo(false, L"arccos",     LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\arctan",      IdentifierInfo(false, L"arctan",     LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\sinh",        IdentifierInfo(false, L"sinh",       LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\cosh",        IdentifierInfo(false, L"cosh",       LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\tanh",        IdentifierInfo(false, L"tanh",       LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\coth",        IdentifierInfo(false, L"coth",       LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\log",         IdentifierInfo(false, L"log",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\lg",          IdentifierInfo(false, L"lg",         LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\ln",          IdentifierInfo(false, L"ln",         LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\exp",         IdentifierInfo(false, L"exp",        LayoutTree::Node::cFlavourOp)),
      make_pair(L"\\aleph",       IdentifierInfo(false, L"\U00002135", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\beth",        IdentifierInfo(false, L"\U00002136", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\gimel",       IdentifierInfo(false, L"\U00002137", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\daleth",      IdentifierInfo(false, L"\U00002138", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\wp",          IdentifierInfo(true,  L"\U00002118", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\ell",         IdentifierInfo(true,  L"\U00002113", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\P",           IdentifierInfo(true,  L"\U000000B6", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\imath",       IdentifierInfo(true,  L"\U00000131", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\Finv",        IdentifierInfo(false, L"\U00002132", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\Game",        IdentifierInfo(false, L"\U00002141", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\partial",     IdentifierInfo(false, L"\U00002202", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\Re",          IdentifierInfo(false, L"\U0000211C", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\Im",          IdentifierInfo(false, L"\U00002111", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\infty",       IdentifierInfo(false, L"\U0000221E", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\hbar",        IdentifierInfo(false, L"\U00000127", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\emptyset",    IdentifierInfo(false, L"\U00002205", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\varnothing",  IdentifierInfo(false, L"\U000000D8", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\S",           IdentifierInfo(false, L"\U000000A7", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\AA",          IdentifierInfo(false, L"\U000000C5", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\eth",         IdentifierInfo(false, L"\U000000F0", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\hslash",      IdentifierInfo(false, L"\U0000210F", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\mho",         IdentifierInfo(false, L"\U00002127", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\circledR",    IdentifierInfo(false, L"\U000000AE", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\yen",         IdentifierInfo(false, L"\U000000A5", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\maltese",     IdentifierInfo(false, L"\U00002720", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\circledS",    IdentifierInfo(false, L"\U000024C8", LayoutTree::Node::cFlavourOrd)),
      // FIX: these two needs special testing since they're plane-1:
      // FIX: need to update mediawiki to recognise these entities
      make_pair(L"\\Bbbk",        IdentifierInfo(false, L"\U0001D55C", LayoutTree::Node::cFlavourOrd)),
      make_pair(L"\\jmath",       IdentifierInfo(true,  L"\U0001D6A5", LayoutTree::Node::cFlavourOrd))
  };
  wishful_hash_map<wstring, IdentifierInfo> identifierTable(
      identifierArray,
      END_ARRAY(identifierArray)
  );
  
  
  namespace ParseTree
  {
  
  auto_ptr<LayoutTree::Node> MathSymbol::BuildLayoutTree(
      const TexProcessingState& state
  ) const
  {
      // First check for certain easy-to-handle single character commands,
      // like letters or numerals.
      if (mCommand.size() == 1)
      {
          bool good = false;
          bool isNumber = false;
          // fancyFontsIllegal is set for characters which can't be
          // displayed in frak, cal or bb fonts.
          bool fancyFontsIllegal = false;
          TexMathFont::Family defaultFamily = TexMathFont::cFamilyIt;
          TexMathFont font = state.mMathFont;
  
          if (mCommand[0] >= L'A' && mCommand[0] <= L'Z')
              good = true;
  
          else if (mCommand[0] >= L'a' && mCommand[0] <= L'z')
          {
              fancyFontsIllegal = true;
              good = true;
          }
  
          else if (mCommand[0] >= L'0' && mCommand[0] <= L'9')
          {
              fancyFontsIllegal = true;
              defaultFamily = TexMathFont::cFamilyRm;
              good = isNumber = true;
          }
  
          if (good)
          {
              if (font.mFamily == TexMathFont::cFamilyDefault)
                  font.mFamily = defaultFamily;
  
              if (fancyFontsIllegal &&
                  font.mFamily == TexMathFont::cFamilyCal
              )
                  throw Exception(
                      L"UnavailableSymbolFontCombination", mCommand, L"cal"
                  );
  
              if (fancyFontsIllegal &&
                  font.mFamily == TexMathFont::cFamilyBb
              )
                  throw Exception(
                      L"UnavailableSymbolFontCombination", mCommand, L"bb"
                  );
  
              if (isNumber)
                  return auto_ptr<LayoutTree::Node>(
                      new LayoutTree::SymbolNumber(
                          mCommand,
                          font.GetMathmlApproximation(),
                          state.mStyle,
                          LayoutTree::Node::cFlavourOrd,
                          LayoutTree::Node::cLimitsDisplayLimits,
                          state.mColour
                      )
                  );
              else
                  return auto_ptr<LayoutTree::Node>(
                      new LayoutTree::SymbolIdentifier(
                          mCommand,
                          font.GetMathmlApproximation(),
                          state.mStyle,
                          LayoutTree::Node::cFlavourOrd,
                          LayoutTree::Node::cLimitsDisplayLimits,
                          state.mColour
                      )
                  );
          }
  
          // Non-ascii characters
          if (mCommand[0] > 0x7F)
              throw logic_error(
                  "Unexpected non-ASCII character "
                  "in MathSymbol::BuildLayoutTree"
              );
      }
  
      wishful_hash_map<wstring, wchar_t>::const_iterator
          lowercaseGreekLookup = lowercaseGreekTable.find(mCommand);
  
      if (lowercaseGreekLookup != lowercaseGreekTable.end())
      {
          return auto_ptr<LayoutTree::Node>(
              new LayoutTree::SymbolIdentifier(
                  wstring(1, lowercaseGreekLookup->second),
                  // lowercase greek is only affected by the boldsymbol
                  // status, not the family.
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBoldItalic : cMathmlFontItalic,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
      }
  
      wishful_hash_map<wstring, wchar_t>::const_iterator
          uppercaseGreekLookup = uppercaseGreekTable.find(mCommand);
  
      if (uppercaseGreekLookup != uppercaseGreekTable.end())
      {
          TexMathFont font = state.mMathFont;
          if (font.mFamily == TexMathFont::cFamilyCal)
              throw Exception(
                  L"UnavailableSymbolFontCombination", mCommand, L"cal"
              );
  
          if (font.mFamily == TexMathFont::cFamilyBb)
              throw Exception(
                  L"UnavailableSymbolFontCombination", mCommand, L"bb"
              );
  
          if (font.mFamily == TexMathFont::cFamilyFrak)
              throw Exception(
                  L"UnavailableSymbolFontCombination", mCommand, L"frak"
              );
  
          if (font.mFamily == TexMathFont::cFamilyDefault)
              font.mFamily = TexMathFont::cFamilyRm;
  
          return auto_ptr<LayoutTree::Node>(
              new LayoutTree::SymbolIdentifier(
                  wstring(1, uppercaseGreekLookup->second),
                  font.GetMathmlApproximation(),
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
      }
  
      wishful_hash_map<wstring, int>::const_iterator
          spaceLookup = spaceTable.find(mCommand);
  
      if (spaceLookup != spaceTable.end())
      {
          return auto_ptr<LayoutTree::Node>(
              new LayoutTree::Space(
                  spaceLookup->second,
                  true      // true = indicates a user-requested space
              )
          );
      }
  
      wishful_hash_map<wstring, OperatorInfo>::const_iterator
          operatorLookup = operatorTable.find(mCommand);
  
      if (operatorLookup != operatorTable.end())
      {
          return auto_ptr<LayoutTree::Node>(
              new LayoutTree::SymbolOperator(
                  false, L"",     // not stretchy
                  false,          // not an accent
                  operatorLookup->second.mText,
                  // operators are only affected by the boldsymbol status,
                  // not the family.
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  operatorLookup->second.mFlavour,
                  operatorLookup->second.mLimits,
                  state.mColour
              )
          );
      }
  
      wishful_hash_map<wstring, IdentifierInfo>::const_iterator
          identifierLookup = identifierTable.find(mCommand);
  
      if (identifierLookup != identifierTable.end())
      {
          TexMathFont font = state.mMathFont;
          font.mFamily =
              identifierLookup->second.mIsItalicDefault
                  ? TexMathFont::cFamilyIt : TexMathFont::cFamilyRm;
  
          return auto_ptr<LayoutTree::Node>(
              new LayoutTree::SymbolIdentifier(
                  identifierLookup->second.mText,
                  font.GetMathmlApproximation(),
                  state.mStyle,
                  identifierLookup->second.mFlavour,
                  // For all the "\sin"-like functions:
                  (
                      identifierLookup->second.mFlavour ==
                      LayoutTree::Node::cFlavourOp
                  )
                      ? LayoutTree::Node::cLimitsNoLimits
                      : LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
      }
  
      if (mCommand == L"\\And")
      {
          auto_ptr<LayoutTree::Row> row(
              new LayoutTree::Row(state.mStyle, state.mColour)
          );
          row->mFlavour = LayoutTree::Node::cFlavourRel;
          row->mChildren.push_back(new LayoutTree::Space(5, true));
          row->mChildren.push_back(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L"&",
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
          row->mChildren.push_back(new LayoutTree::Space(5, true));
          return static_cast<auto_ptr<LayoutTree::Node> >(row);
      }
  
      if (mCommand == L"\\iff")
      {
          auto_ptr<LayoutTree::Row> row(
              new LayoutTree::Row(state.mStyle, state.mColour)
          );
          row->mFlavour = LayoutTree::Node::cFlavourRel;
          row->mChildren.push_back(new LayoutTree::Space(5, true));
          // FIX: I would like to make this stretchy and set a particular
          // size, but for some reason firefox doesn't stretch things
          // horizontally like this. It DOES do it if the element is in a
          // <mover> or <munder> etc, but not when it's just by itself.
          // Very strange. This is mozilla bug 320303.
          row->mChildren.push_back(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L"\U000021D4",
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
          row->mChildren.push_back(new LayoutTree::Space(5, true));
          return static_cast<auto_ptr<LayoutTree::Node> >(row);
      }
  
      if (mCommand == L"\\colon")
      {
          // FIX: this spacing stuff isn't quite right, but it will hopefully
          // do. The amsmath package does all kinds of interesting things with
          // \colon's spacing.
          auto_ptr<LayoutTree::Row> row(
              new LayoutTree::Row(state.mStyle, state.mColour)
          );
          row->mChildren.push_back(new LayoutTree::Space(2, true));
          row->mChildren.push_back(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L":",
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
          row->mChildren.push_back(new LayoutTree::Space(6, true));
          return static_cast<auto_ptr<LayoutTree::Node> >(row);
      }
  
      if (mCommand == L"\\bmod")
      {
          auto_ptr<LayoutTree::Row> row(
              new LayoutTree::Row(state.mStyle, state.mColour)
          );
          row->mFlavour = LayoutTree::Node::cFlavourBin;
          row->mChildren.push_back(new LayoutTree::Space(1, true));
          row->mChildren.push_back(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L"mod",
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
          row->mChildren.push_back(new LayoutTree::Space(1, true));
          return static_cast<auto_ptr<LayoutTree::Node> >(row);
      }
  
      if (mCommand == L"\\mod")
      {
          auto_ptr<LayoutTree::Row> row(
              new LayoutTree::Row(state.mStyle, state.mColour)
          );
          row->mChildren.push_back(new LayoutTree::Space(18, true));
          row->mChildren.push_back(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L"mod",
                  state.mMathFont.mIsBoldsymbol
                      ? cMathmlFontBold : cMathmlFontNormal,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOrd,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour
              )
          );
          row->mChildren.push_back(new LayoutTree::Space(6, true));
          return static_cast<auto_ptr<LayoutTree::Node> >(row);
      }
  
      if (mCommand == L"\\varinjlim" || mCommand == L"\\varprojlim" ||
          mCommand == L"\\varlimsup" || mCommand == L"\\varliminf")
      {
          MathmlFont font =
              state.mMathFont.mIsBoldsymbol
                  ? cMathmlFontBold : cMathmlFontNormal;
  
          auto_ptr<LayoutTree::Node> base(
              new LayoutTree::SymbolOperator(
                  false,
                  L"",
                  false,
                  L"lim",
                  font,
                  state.mStyle,
                  LayoutTree::Node::cFlavourOp,
                  LayoutTree::Node::cLimitsLimits,
                  state.mColour
              )
          );
  
          auto_ptr<LayoutTree::Scripts> node(
              new LayoutTree::Scripts(
                  state.mStyle,
                  LayoutTree::Node::cFlavourOp,
                  LayoutTree::Node::cLimitsDisplayLimits,
                  state.mColour,
                  false,
                  base,
                  auto_ptr<LayoutTree::Node>(),
                  auto_ptr<LayoutTree::Node>()
              )
          );
  
          if (mCommand == L"\\varinjlim")
              node->mLower = auto_ptr<LayoutTree::Node>(
                  new LayoutTree::SymbolOperator(
                      false,
                      L"",
                      true,
                      L"\U00002192",
                      font,
                      state.mStyle,
                      LayoutTree::Node::cFlavourOrd,
                      LayoutTree::Node::cLimitsDisplayLimits,
                      state.mColour
                  )
              );
  
          else if (mCommand == L"\\varprojlim")
              node->mLower = auto_ptr<LayoutTree::Node>(
                  new LayoutTree::SymbolOperator(
                      false,
                      L"",
                      true,
                      L"\U00002190",
                      font,
                      state.mStyle,
                      LayoutTree::Node::cFlavourOrd,
                      LayoutTree::Node::cLimitsDisplayLimits,
                      state.mColour
                  )
              );
  
          else if (mCommand == L"\\varliminf")
              node->mLower = auto_ptr<LayoutTree::Node>(
                  new LayoutTree::SymbolOperator(
                      true,
                      L"",
                      true,
                      L"\U000000AF",
                      font,
                      state.mStyle,
                      LayoutTree::Node::cFlavourOrd,
                      LayoutTree::Node::cLimitsDisplayLimits,
                      state.mColour
                  )
              );
  
          else if (mCommand == L"\\varlimsup")
              node->mUpper = auto_ptr<LayoutTree::Node>(
                  new LayoutTree::SymbolOperator(
                      true,
                      L"",
                      true,
                      L"\U000000AF",
                      font,
                      state.mStyle,
                      LayoutTree::Node::cFlavourOrd,
                      LayoutTree::Node::cLimitsDisplayLimits,
                      state.mColour
                  )
              );
  
          return static_cast<auto_ptr<LayoutTree::Node> >(node);
      }
  
      throw logic_error("Unexpected command in MathSymbol::BuildLayoutTree");
  }
  
  }
  }
  
  // end of file @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  