[med-svn] r9493 - in trunk/packages: . copasi copasi/trunk copasi/trunk/debian copasi/trunk/debian/patches copasi/trunk/debian/source
Ivo Maintz
ivomaintz-guest at alioth.debian.org
Sun Jan 29 09:23:36 UTC 2012
Author: ivomaintz-guest
Date: 2012-01-29 09:23:35 +0000 (Sun, 29 Jan 2012)
New Revision: 9493
Added:
trunk/packages/copasi/
trunk/packages/copasi/trunk/
trunk/packages/copasi/trunk/debian/
trunk/packages/copasi/trunk/debian/CopasiSE.1
trunk/packages/copasi/trunk/debian/CopasiUI.1
trunk/packages/copasi/trunk/debian/README.source
trunk/packages/copasi/trunk/debian/changelog
trunk/packages/copasi/trunk/debian/compat
trunk/packages/copasi/trunk/debian/control
trunk/packages/copasi/trunk/debian/copasi.desktop
trunk/packages/copasi/trunk/debian/copasi.install
trunk/packages/copasi/trunk/debian/copasi.manpages
trunk/packages/copasi/trunk/debian/copyright
trunk/packages/copasi/trunk/debian/dirs
trunk/packages/copasi/trunk/debian/docs
trunk/packages/copasi/trunk/debian/menu
trunk/packages/copasi/trunk/debian/patches/
trunk/packages/copasi/trunk/debian/patches/main.patch
trunk/packages/copasi/trunk/debian/patches/series
trunk/packages/copasi/trunk/debian/rules
trunk/packages/copasi/trunk/debian/source/
trunk/packages/copasi/trunk/debian/source/format
Log:
This is the initial checkin for copasi, a tool for for simulation
and analysis of biochemical networks and their dynamics.
Added: trunk/packages/copasi/trunk/debian/CopasiSE.1
===================================================================
--- trunk/packages/copasi/trunk/debian/CopasiSE.1 (rev 0)
+++ trunk/packages/copasi/trunk/debian/CopasiSE.1 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,78 @@
+.\"Created with GNOME Manpages Editor Wizard
+.\"http://sourceforge.net/projects/gmanedit2
+.TH CopasiSE 1 "September 9, 2011" "" "CopasiSE"
+
+.SH NAME
+CopasiSE \- simulation and analysis of biochemical networks
+
+.SH SYNOPSIS
+.B CopasiSE
+.RI [ OPTIONS ] " files" ...
+.br
+
+.SH DESCRIPTION
+Copasi is distributed as a commandline tool and a graphical version, both are independent from each other.
+This manual page explains the
+.B CopasiSE
+program.
+.PP
+\fBCopasiSE\fP is a software application for simulation and analysis of biochemical networks.
+
+.SH OPTIONS
+.B
+.IP
+.B \-\-SBMLSchema SCHEMA
+ The Schema of the SBML file to export.
+.IP
+.B \-\-configdir DIR
+ The configuration directory for copasi. The default is .copasi in the home directory.
+.IP
+.B \-\-configfile FILE
+ The configuration file for copasi. The default is copasi in the ConfigDir.
+.IP
+.B \-\-exportBerkeleyMadonna FILE
+ The Berkeley Madonna file to export.
+.IP
+.B \-\-exportC FILE
+ The C code file to export.
+.IP
+.B \-\-exportXPPAUT FILE
+ The XPPAUT file to export.
+.IP
+.B \-\-home DIR
+ Your home directory.
+.IP
+.B \-\-license
+ Display the license.
+.IP
+.B \-\-nologo
+ Surpresses the startup message.
+.IP
+.B \-\-validate
+ Only validate the given input file (COPASI, Gepasi, or SBML) without performing any calculations.
+.IP
+.B \-\-verbose
+ Enable output of messages during runtime to std::error.
+.IP
+.B \-c, \-\-copasidir DIR
+ The COPASI installation directory.
+.IP
+.B \-e, \-\-exportSBML FILE
+ The SBML file to export.
+.IP
+.B \-i, \-\-importSBML FILE
+ A SBML file to import.
+.IP
+.B \-s, \-\-save FILE
+ The file the model is saved to after work.
+.IP
+.B \-t, \-\-tmp DIR
+ The temp directory used for autosave.
+
+.SH "SEE ALSO"
+.BR
+.br online documentation at
+.IR http://www.copasi.org/tiki-index.php?page_ref_id=113
+.PP
+This manual page was written by Ivo Maintz <ivo at maintz.de>,
+for the Debian project (and may be used by others).
Added: trunk/packages/copasi/trunk/debian/CopasiUI.1
===================================================================
--- trunk/packages/copasi/trunk/debian/CopasiUI.1 (rev 0)
+++ trunk/packages/copasi/trunk/debian/CopasiUI.1 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,30 @@
+.\"Created with GNOME Manpages Editor Wizard
+.\"http://sourceforge.net/projects/gmanedit2
+.TH CopasiUI 1 "January 28, 2012" "" "CopasiUI"
+
+.SH NAME
+CopasiUI \- simulation and analysis of biochemical networks
+
+.SH SYNOPSIS
+.B CopasiUI
+.RI [ OPTIONS ]
+.br
+
+.SH DESCRIPTION
+This manual page explains the
+.B CopasiUI
+program.
+.PP
+\fBCopasiUI\fP is a software application for simulation and analysis of biochemical networks.
+This is the graphical UI
+
+.SH OPTIONS
+There are actually no command line options to CopasiUI; have a look at CopasiSE
+.B
+.SH "SEE ALSO"
+.BR
+.br wizards in
+.IR /usr/share/copasi7/doc/html
+.PP
+This manual page was written by Ivo Maintz <ivo at maintz.de>,
+for the Debian project (and may be used by others).
Added: trunk/packages/copasi/trunk/debian/README.source
===================================================================
--- trunk/packages/copasi/trunk/debian/README.source (rev 0)
+++ trunk/packages/copasi/trunk/debian/README.source 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,16 @@
+copasi for Debian
+-----------------
+
+<this file describes information about the source package, see Debian policy
+manual section 4.14. You WILL either need to modify or delete this file>
+unfortunately, I couldn't find out a way to directly download Copasi-35-SRC.tar.gz and the patch;
+you have to go to http://www.copasi.org/tiki-index.php?page=DownloadNonCommercial&structure=Download
+to get it.
+
+tar xzf Copasi-35-SRC.tar.gz
+gunzip copasi-35-bindings.patch.gz
+patch -p0 < copasi-35-bindings.patch
+mv copasi-35-src/* .
+rmdir copasi-35-src/
+rm README*
+tar czf ../copasi_4.8.35.orig.tar.gz . --exclude=debian
Added: trunk/packages/copasi/trunk/debian/changelog
===================================================================
--- trunk/packages/copasi/trunk/debian/changelog (rev 0)
+++ trunk/packages/copasi/trunk/debian/changelog 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,11 @@
+copasi (4.8.35-1) unstable; urgency=low
+
+ * Update from upstream
+
+ -- Ivo Maintz <ivo at maintz.de> Thu, 05 Jan 2012 16:34:29 +0200
+
+copasi (4.7.34-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Ivo Maintz <ivo at maintz.de> Fri, 07 Oct 2011 14:20:04 +0200
Added: trunk/packages/copasi/trunk/debian/compat
===================================================================
--- trunk/packages/copasi/trunk/debian/compat (rev 0)
+++ trunk/packages/copasi/trunk/debian/compat 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1 @@
+8
Added: trunk/packages/copasi/trunk/debian/control
===================================================================
--- trunk/packages/copasi/trunk/debian/control (rev 0)
+++ trunk/packages/copasi/trunk/debian/control 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,29 @@
+Source: copasi
+Section: science
+Priority: extra
+Maintainer: Ivo Maintz <ivo at maintz.de>
+Build-Depends: debhelper (>= 8.0.0),
+ autotools-dev,
+ cdbs,
+ libqwt5-qt4-dev,
+ libqwtplot3d-qt4-dev,
+ default-jdk | openjdk-6-jdk,
+ python-all-dev,
+ octave3.2-headers,
+ libf2c2-dev
+Standards-Version: 3.9.2
+Homepage: http://wwww.copasi.org
+
+Package: copasi
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: simulation and analysis of biochemical networks
+ COPASI is a software application for simulation and analysis of biochemical
+ networks and their dynamics. COPASI is a stand-alone program that supports
+ models in the SBML standard and can simulate their behavior using ODEs or
+ Gillespie's stochastic simulation algorithm; arbitrary discrete events can
+ be included in such simulations.
+ COPASI carries out several analyses of the network and its dynamics and has
+ extensive support for parameter estimation and optimization. COPASI provides
+ means to visualize data in customizable plots, histograms and animations of
+ network diagrams.
Added: trunk/packages/copasi/trunk/debian/copasi.desktop
===================================================================
--- trunk/packages/copasi/trunk/debian/copasi.desktop (rev 0)
+++ trunk/packages/copasi/trunk/debian/copasi.desktop 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Copasi
+Comment=Simulation of biochemical networks
+Exec=/usr/bin/CopasiUI
+Icon=/usr/share/pixmaps/Copasi32-Alpha.xpm
+Terminal=false
+Type=Application
+Categories=Development;Science;Biology;
+StartupNotify=true
Added: trunk/packages/copasi/trunk/debian/copasi.install
===================================================================
--- trunk/packages/copasi/trunk/debian/copasi.install (rev 0)
+++ trunk/packages/copasi/trunk/debian/copasi.install 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,4 @@
+../../copasi/CopasiSE/CopasiSE usr/bin
+../../copasi/CopasiUI/CopasiUI usr/bin
+../../copasi/UI/icons/Copasi32-Alpha.xpm usr/share/pixmaps
+../copasi.desktop usr/share/applications
Added: trunk/packages/copasi/trunk/debian/copasi.manpages
===================================================================
--- trunk/packages/copasi/trunk/debian/copasi.manpages (rev 0)
+++ trunk/packages/copasi/trunk/debian/copasi.manpages 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1 @@
+debian/*.1
Added: trunk/packages/copasi/trunk/debian/copyright
===================================================================
--- trunk/packages/copasi/trunk/debian/copyright (rev 0)
+++ trunk/packages/copasi/trunk/debian/copyright 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,34 @@
+Format: http://dep.debian.net/deps/dep5
+Upstream-Name: copasi
+Source: http://www.copasi.org/tiki-index.php?page=downloadnoncommercial
+
+Files: *
+Copyright: 2011 copasi.org
+License: Artistic
+
+Files: debian/*
+Copyright: 2011 Ivo Maintz <ivo at maintz.de>
+License: GPL-3+
+
+License: GPL-3+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation version 3
+ .
+ THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
+ OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ .
+ On Debian systems, the complete text of the GPL-3
+ can be found in "/usr/share/common-licenses/GPL-3".
+
+License: Artistic
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the "Artistic License" which comes with Debian.
+ .
+ THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
+ OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ .
+ On Debian systems, the complete text of the Artistic License
+ can be found in "/usr/share/common-licenses/Artistic".
Added: trunk/packages/copasi/trunk/debian/dirs
===================================================================
--- trunk/packages/copasi/trunk/debian/dirs (rev 0)
+++ trunk/packages/copasi/trunk/debian/dirs 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1 @@
+usr/bin
Added: trunk/packages/copasi/trunk/debian/docs
===================================================================
Added: trunk/packages/copasi/trunk/debian/menu
===================================================================
--- trunk/packages/copasi/trunk/debian/menu (rev 0)
+++ trunk/packages/copasi/trunk/debian/menu 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,2 @@
+?package(copasi):needs="X11" section="Applications/Science/Biology"\
+ title="Copasi" command="/usr/bin/CopasiUI"
Added: trunk/packages/copasi/trunk/debian/patches/main.patch
===================================================================
--- trunk/packages/copasi/trunk/debian/patches/main.patch (rev 0)
+++ trunk/packages/copasi/trunk/debian/patches/main.patch 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,6676 @@
+Description: <short summary of the patch>
+ TODO: Put a short summary on the line above and replace this paragraph
+ with a longer explanation of this change. Complete the meta-information
+ with other relevant fields (see below for details). To make it easier, the
+ information below has been extracted from the changelog. Adjust it or drop
+ it.
+ .
+ copasi (4.8.35-1) unstable; urgency=low
+ .
+ * Update from upstream
+Author: Ivo Maintz <ivo at maintz.de>
+
+---
+The information above should follow the Patch Tagging Guidelines, please
+checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
+are templates for supplementary fields that you might want to add:
+
+Origin: <vendor|upstream|other>, <url of original patch>
+Bug: <url in upstream bugtracker>
+Bug-Debian: http://bugs.debian.org/<bugnumber>
+Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
+Forwarded: <no|not-needed|url proving that it has been forwarded>
+Reviewed-By: <name and email of someone who approved the patch>
+Last-Update: <YYYY-MM-DD>
+
+--- copasi-4.8.35.orig/configure
++++ copasi-4.8.35/configure
+@@ -1617,22 +1617,18 @@ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_NAME "$PACKAGE_NAME"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_VERSION "$PACKAGE_VERSION"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_STRING "$PACKAGE_STRING"
+ _ACEOF
+
+-
+ cat >>confdefs.h <<_ACEOF
+ #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+ _ACEOF
+--- copasi-4.8.35.orig/copasi/common.pri
++++ copasi-4.8.35/copasi/common.pri
+@@ -1,6 +1,6 @@
+ # Begin CVS Header
+ # $Source: /fs/turing/cvs/copasi_dev/copasi/common.pri,v $
+-# $Revision: 1.120.2.13 $
++# $Revision: 1.120.2.12 $
+ # $Name: Build-33 $
+ # End CVS Header
+
+@@ -19,7 +19,7 @@
+ # All rights reserved.
+
+ ######################################################################
+-# $Revision: 1.120.2.13 $ $Author: shoops $ $Date: 2011/11/10 15:32:28 $
++# $Revision: 1.120.2.12 $ $Author: shoops $ $Date: 2011/05/19 22:26:04 $
+ ######################################################################
+
+ # In the case the BUILD_OS is not specified we make a guess.
+@@ -171,16 +171,16 @@ contains(BUILD_OS, Darwin) {
+
+ !isEmpty(QWT_PATH){
+ LIBS+= $${QWT_PATH}/lib/libqwt.a
+- INCLUDEPATH += $${QWT_PATH}/include
++ INCLUDEPATH += $${QWT_PATH}/include/qwt-qt4
+ } else {
+- LIBS += -lqwt
++ LIBS += -lqwt-qt4
+ }
+
+ !isEmpty(QWT3D_PATH){
+ LIBS += $${QWT3D_PATH}/lib/libqwtplot3d.a
+- INCLUDEPATH += $${QWT3D_PATH}/include
++ INCLUDEPATH += $${QWT3D_PATH}/include/qwtplot3d-qt4
+ } else {
+- LIBS += -lqwtplot3d
++ LIBS += -lqwtplot3d-qt4
+ }
+ }
+
+@@ -376,7 +376,7 @@ contains(BUILD_OS, WIN32) {
+ INCLUDEPATH += \""$${QWT_PATH}"/include\"
+ }
+
+- release: LIBS += -lqwt
++ release: LIBS += -lqwt-qt4
+ debug: LIBS += -lqwtD
+
+ !isEmpty(QWT3D_PATH){
+@@ -386,7 +386,7 @@ contains(BUILD_OS, WIN32) {
+
+ # DEFINES += QWT3D_NODLL
+
+- release: LIBS += -lqwtplot3d
++ release: LIBS += -lqwtplot3d-qt4
+ debug: LIBS += -lqwtplot3dD
+ }
+ }
+@@ -453,15 +453,15 @@ contains(STATIC_LINKAGE, yes) {
+
+ !isEmpty(QWT_PATH){
+ LIBS+= -L$${QWT_PATH}/lib
+- INCLUDEPATH += $${QWT_PATH}/include
++ INCLUDEPATH += $${QWT_PATH}/include/qwt-qt4
+ }
+- LIBS += -lqwt
++ LIBS += -lqwt-qt4
+
+ !isEmpty(QWT3D_PATH){
+ LIBS += -L$${QWT3D_PATH}/lib/
+- INCLUDEPATH += $${QWT3D_PATH}/include
++ INCLUDEPATH += $${QWT3D_PATH}/include/qwtplot3d-qt4
+ }
+- LIBS += -lqwtplot3d
++ LIBS += -lqwtplot3d-qt4
+
+ LIBS += -lSM
+ } else {
+@@ -628,17 +628,15 @@ contains(BUILD_OS, Linux) {
+
+ !isEmpty(QWT_PATH){
+ LIBS += -L$${QWT_PATH}/lib
+- INCLUDEPATH += $${QWT_PATH}/include
+ INCLUDEPATH += $${QWT_PATH}/include/qwt-qt4
+ }
+- LIBS += -lqwt
++ LIBS += -lqwt-qt4
+
+ !isEmpty(QWT3D_PATH){
+ LIBS += -L$${QWT3D_PATH}/lib/
+- INCLUDEPATH += $${QWT3D_PATH}/include
+ INCLUDEPATH += $${QWT3D_PATH}/include/qwtplot3d-qt4
+ }
+- LIBS += -lqwtplot3d
++ LIBS += -lqwtplot3d-qt4
+
+ # only needed for the class CLSimpleImageTexturizer which is only
+ # needed if we want to create bitmaps from layouts in the backend
+--- copasi-4.8.35.orig/copasi/mml/mml.pro
++++ copasi-4.8.35/copasi/mml/mml.pro
+@@ -1,12 +1,12 @@
+ # Begin CVS Header
+ # $Source: /fs/turing/cvs/copasi_dev/copasi/mml/mml.pro,v $
+-# $Revision: 1.8.2.3 $
+-# $Name: Build-33 $
++# $Revision: 1.9 $
++# $Name: $
+ # $Author: shoops $
+-# $Date: 2010/11/13 16:55:57 $
++# $Date: 2011/03/07 19:30:52 $
+ # End CVS Header
+
+-# Copyright (C) 2010 by Pedro Mendes, Virginia Tech Intellectual
++# Copyright (C) 2011 - 2010 by Pedro Mendes, Virginia Tech Intellectual
+ # Properties, Inc., University of Heidelberg, and The University
+ # of Manchester.
+ # All rights reserved.
+@@ -17,7 +17,7 @@
+ # All rights reserved.
+
+ ######################################################################
+-# $Revision: 1.8.2.3 $ $Author: shoops $ $Date: 2010/11/13 16:55:57 $
++# $Revision: 1.9 $ $Author: shoops $ $Date: 2011/03/07 19:30:52 $
+ ######################################################################
+
+ LIB = mml
+--- /dev/null
++++ copasi-4.8.35/copasi/mml/qtmmlwidget.cpp
+@@ -0,0 +1,6370 @@
++/****************************************************************************
++**
++** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
++** All rights reserved.
++** Contact: Nokia Corporation (qt-info at nokia.com)
++**
++** This file is part of a Qt Solutions component.
++**
++** Commercial Usage
++** Licensees holding valid Qt Commercial licenses may use this file in
++** accordance with the Qt Solutions Commercial License Agreement provided
++** with the Software or, alternatively, in accordance with the terms
++** contained in a written agreement between you and Nokia.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 2.1 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 2.1 requirements
++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Nokia gives you certain
++** additional rights. These rights are described in the Nokia Qt LGPL
++** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
++** package.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 3.0 as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU General Public License version 3.0 requirements will be
++** met: http://www.gnu.org/copyleft/gpl.html.
++**
++** Please note Third Party Software included with Qt Solutions may impose
++** additional restrictions and it is the user's responsibility to ensure
++** that they have met the licensing requirements of the GPL, LGPL, or Qt
++** Solutions Commercial license and the relevant license of the Third
++** Party Software they are using.
++**
++** If you are unsure which license is appropriate for your use, please
++** contact Nokia at qt-info at nokia.com.
++**
++****************************************************************************/
++
++#include <QtGui/QApplication>
++#include <QtCore/QString>
++#include <QtCore/QMap>
++#include <QtGui/QDesktopWidget>
++#include <QtGui/QPainter>
++#include <QtGui/QPaintEvent>
++
++#include "qtmmlwidget.h"
++
++// *******************************************************************
++// Declarations
++// *******************************************************************
++
++#define ROUND(a) (int)((a)+.5)
++
++static bool g_draw_frames = false;
++static const double g_mfrac_spacing = 0.1;
++static const double g_mroot_base_margin = 0.1;
++static const double g_script_size_multiplier = 0.7071; // sqrt(1/2)
++static const int g_min_font_point_size = 8;
++static const QChar g_radical_char = QChar(0x1A, 0x22);
++static const unsigned g_oper_spec_rows = 9;
++
++struct Mml
++{
++ enum NodeType {
++ NoNode = 0, MiNode, MnNode, MfracNode, MrowNode, MsqrtNode,
++ MrootNode, MsupNode, MsubNode, MsubsupNode, MoNode,
++ MstyleNode, TextNode, MphantomNode, MfencedNode,
++ MtableNode, MtrNode, MtdNode, MoverNode, MunderNode,
++ MunderoverNode, MerrorNode, MtextNode, MpaddedNode,
++ MspaceNode, MalignMarkNode, UnknownNode
++ };
++
++ enum MathVariant {
++ NormalMV = 0x0000,
++ BoldMV = 0x0001,
++ ItalicMV = 0x0002,
++ DoubleStruckMV = 0x0004,
++ ScriptMV = 0x0008,
++ FrakturMV = 0x0010,
++ SansSerifMV = 0x0020,
++ MonospaceMV = 0x0040
++ };
++
++ enum FormType { PrefixForm, InfixForm, PostfixForm };
++ enum ColAlign { ColAlignLeft, ColAlignCenter, ColAlignRight };
++ enum RowAlign { RowAlignTop, RowAlignCenter, RowAlignBottom,
++ RowAlignAxis, RowAlignBaseline };
++ enum FrameType { FrameNone, FrameSolid, FrameDashed };
++
++ struct FrameSpacing {
++ FrameSpacing(int hor = 0, int ver = 0)
++ : m_hor(hor), m_ver(ver) {}
++ int m_hor, m_ver;
++ };
++};
++
++struct OperSpec {
++ enum StretchDir { NoStretch, HStretch, VStretch, HVStretch };
++
++ const char *name;
++ Mml::FormType form;
++ const char *attributes[g_oper_spec_rows];
++ StretchDir stretch_dir;
++};
++
++struct NodeSpec
++{
++ Mml::NodeType type;
++ const char *tag;
++ const char *type_str;
++ int child_spec;
++ const char *child_types;
++ const char *attributes;
++
++ enum ChildSpec {
++ ChildAny = -1, // any number of children allowed
++ ChildIgnore = -2, // do not build subexpression of children
++ ImplicitMrow = -3 // if more than one child, build mrow
++ };
++};
++
++struct EntitySpec
++{
++ const char *name;
++ const char *value;
++};
++
++typedef QMap<QString, QString> MmlAttributeMap;
++class MmlNode;
++
++class MmlDocument : public Mml
++{
++ public:
++ MmlDocument();
++ ~MmlDocument();
++ void clear();
++
++ bool setContent(QString text, QString *errorMsg = 0,
++ int *errorLine = 0, int *errorColumn = 0);
++ void paint(QPainter *p, const QPoint &pos) const;
++ void dump() const;
++ QSize size() const;
++ void layout();
++
++ QString fontName(QtMmlWidget::MmlFont type) const;
++ void setFontName(QtMmlWidget::MmlFont type, const QString &name);
++
++ int baseFontPointSize() const
++ { return m_base_font_point_size; }
++ void setBaseFontPointSize(int size)
++ { m_base_font_point_size = size; }
++ QColor foregroundColor() const
++ { return m_foreground_color; }
++ void setForegroundColor(const QColor &color)
++ { m_foreground_color = color; }
++ QColor backgroundColor() const
++ { return m_background_color; }
++ void setBackgroundColor(const QColor &color)
++ { m_background_color = color; }
++
++ private:
++ void _dump(const MmlNode *node, QString &indent) const;
++ bool insertChild(MmlNode *parent, MmlNode *new_node, QString *errorMsg);
++
++ MmlNode *domToMml(const QDomNode &dom_node, bool *ok, QString *errorMsg);
++ MmlNode *createNode(NodeType type, const MmlAttributeMap &mml_attr,
++ const QString &mml_value, QString *errorMsg);
++ MmlNode *createImplicitMrowNode(const QDomNode &dom_node, bool *ok,
++ QString *errorMsg);
++
++ void insertOperator(MmlNode *node, const QString &text);
++
++ MmlNode *m_root_node;
++
++ QString m_normal_font_name;
++ QString m_fraktur_font_name;
++ QString m_sans_serif_font_name;
++ QString m_script_font_name;
++ QString m_monospace_font_name;
++ QString m_doublestruck_font_name;
++ int m_base_font_point_size;
++ QColor m_foreground_color;
++ QColor m_background_color;
++};
++
++class MmlNode : public Mml
++{
++ friend class MmlDocument;
++
++ public:
++ MmlNode(NodeType type, MmlDocument *document, const MmlAttributeMap &attribute_map);
++ virtual ~MmlNode();
++
++ // Mml stuff
++ NodeType nodeType() const
++ { return m_node_type; }
++
++ virtual QString toStr() const;
++
++ void setRelOrigin(const QPoint &rel_origin);
++ QPoint relOrigin() const
++ { return m_rel_origin; }
++ void stretchTo(const QRect &rect);
++ bool isStretched() const
++ { return m_stretched; }
++ QPoint devicePoint(const QPoint &p) const;
++
++ QRect myRect() const
++ { return m_my_rect; }
++ QRect parentRect() const;
++ virtual QRect deviceRect() const;
++ void updateMyRect();
++ virtual void setMyRect(const QRect &rect)
++ { m_my_rect = rect; }
++
++ virtual void stretch();
++ virtual void layout();
++ virtual void paint(QPainter *p);
++
++ int basePos() const;
++ int overlinePos() const;
++ int underlinePos() const;
++ int em() const;
++ int ex() const;
++
++ QString explicitAttribute(const QString &name, const QString &def = QString::null) const;
++ QString inheritAttributeFromMrow(const QString &name, const QString &def = QString::null) const;
++
++ virtual QFont font() const;
++ virtual QColor color() const;
++ virtual QColor background() const;
++ virtual int scriptlevel(const MmlNode *child = 0) const;
++
++
++ // Node stuff
++ MmlDocument *document() const
++ { return m_document; }
++ MmlNode *parent() const
++ { return m_parent; }
++ MmlNode *firstChild() const
++ { return m_first_child; }
++ MmlNode *nextSibling() const
++ { return m_next_sibling; }
++ MmlNode *previousSibling() const
++ { return m_previous_sibling; }
++ MmlNode *lastSibling() const;
++ MmlNode *firstSibling() const;
++ bool isLastSibling() const
++ { return m_next_sibling == 0; }
++ bool isFirstSibling() const
++ { return m_previous_sibling == 0; }
++ bool hasChildNodes() const
++ { return m_first_child != 0; }
++
++ protected:
++ virtual void layoutSymbol();
++ virtual void paintSymbol(QPainter *p) const;
++ virtual QRect symbolRect() const
++ { return QRect(0, 0, 0, 0); }
++
++ MmlNode *parentWithExplicitAttribute(const QString &name, NodeType type = NoNode);
++ int interpretSpacing(const QString &value, bool *ok) const;
++
++ private:
++ MmlAttributeMap m_attribute_map;
++ bool m_stretched;
++ QRect m_my_rect, m_parent_rect;
++ QPoint m_rel_origin;
++
++ NodeType m_node_type;
++ MmlDocument *m_document;
++
++ MmlNode *m_parent,
++ *m_first_child,
++ *m_next_sibling,
++ *m_previous_sibling;
++};
++
++class MmlTokenNode : public MmlNode
++{
++ public:
++ MmlTokenNode(NodeType type, MmlDocument *document,
++ const MmlAttributeMap &attribute_map)
++ : MmlNode(type, document, attribute_map) {}
++
++ QString text() const;
++};
++
++class MmlMphantomNode : public MmlNode
++{
++ public:
++ MmlMphantomNode(MmlDocument *document,
++ const MmlAttributeMap &attribute_map)
++ : MmlNode(MphantomNode, document, attribute_map) {}
++
++ virtual void paint(QPainter *) {}
++};
++
++class MmlUnknownNode : public MmlNode
++{
++ public:
++ MmlUnknownNode(MmlDocument *document,
++ const MmlAttributeMap &attribute_map)
++ : MmlNode(UnknownNode, document, attribute_map) {}
++};
++
++class MmlMfencedNode : public MmlNode
++{
++ public:
++ MmlMfencedNode(MmlDocument *document,
++ const MmlAttributeMap &attribute_map)
++ : MmlNode(MfencedNode, document, attribute_map) {}
++};
++
++class MmlMalignMarkNode : public MmlNode
++{
++ public:
++ MmlMalignMarkNode(MmlDocument *document)
++ : MmlNode(MalignMarkNode, document, MmlAttributeMap()) {}
++};
++
++class MmlMfracNode : public MmlNode
++{
++ public:
++ MmlMfracNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MfracNode, document, attribute_map) {}
++
++ MmlNode *numerator() const;
++ MmlNode *denominator() const;
++
++ protected:
++ virtual void layoutSymbol();
++ virtual void paintSymbol(QPainter *p) const;
++ virtual QRect symbolRect() const;
++};
++
++class MmlMrowNode : public MmlNode
++{
++ public:
++ MmlMrowNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MrowNode, document, attribute_map) {}
++};
++
++class MmlRootBaseNode : public MmlNode
++{
++ public:
++ MmlRootBaseNode(NodeType type, MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(type, document, attribute_map) {}
++
++ MmlNode *base() const;
++ MmlNode *index() const;
++
++ virtual int scriptlevel(const MmlNode *child = 0) const;
++
++ protected:
++ virtual void layoutSymbol();
++ virtual void paintSymbol(QPainter *p) const;
++ virtual QRect symbolRect() const;
++ int tailWidth() const;
++};
++
++class MmlMrootNode : public MmlRootBaseNode
++{
++ public:
++ MmlMrootNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlRootBaseNode(MrootNode, document, attribute_map) {}
++};
++
++class MmlMsqrtNode : public MmlRootBaseNode
++{
++ public:
++ MmlMsqrtNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlRootBaseNode(MsqrtNode, document, attribute_map) {}
++
++};
++
++
++class MmlTextNode : public MmlNode
++{
++ public:
++ MmlTextNode(const QString &text, MmlDocument *document);
++
++ virtual QString toStr() const;
++ QString text() const
++ { return m_text; }
++
++ // TextNodes are not xml elements, so they can't have attributes of
++ // their own. Everything is taken from the parent.
++ virtual QFont font() const
++ { return parent()->font(); }
++ virtual int scriptlevel(const MmlNode* = 0) const
++ { return parent()->scriptlevel(this); }
++ virtual QColor color() const
++ { return parent()->color(); }
++ virtual QColor background() const
++ { return parent()->background(); }
++
++ protected:
++ virtual void paintSymbol(QPainter *p) const;
++ virtual QRect symbolRect() const;
++
++ QString m_text;
++};
++
++class MmlMiNode : public MmlTokenNode
++{
++ public:
++ MmlMiNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTokenNode(MiNode, document, attribute_map) {}
++};
++
++class MmlMnNode : public MmlTokenNode
++{
++ public:
++ MmlMnNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTokenNode(MnNode, document, attribute_map) {}
++};
++
++class MmlSubsupBaseNode : public MmlNode
++{
++ public:
++ MmlSubsupBaseNode(NodeType type, MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(type, document, attribute_map) {}
++
++ MmlNode *base() const;
++ MmlNode *sscript() const;
++
++ virtual int scriptlevel(const MmlNode *child = 0) const;
++};
++
++class MmlMsupNode : public MmlSubsupBaseNode
++{
++ public:
++ MmlMsupNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlSubsupBaseNode(MsupNode, document, attribute_map) {}
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMsubNode : public MmlSubsupBaseNode
++{
++ public:
++ MmlMsubNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlSubsupBaseNode(MsubNode, document, attribute_map) {}
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMsubsupNode : public MmlNode
++{
++ public:
++ MmlMsubsupNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MsubsupNode, document, attribute_map) {}
++
++ MmlNode *base() const;
++ MmlNode *superscript() const;
++ MmlNode *subscript() const;
++
++ virtual int scriptlevel(const MmlNode *child = 0) const;
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMoNode : public MmlTokenNode
++{
++ public:
++ MmlMoNode(MmlDocument *document, const MmlAttributeMap &attribute_map);
++
++ QString dictionaryAttribute(const QString &name) const;
++ virtual void stretch();
++ virtual int lspace() const;
++ virtual int rspace() const;
++
++ virtual QString toStr() const;
++
++ protected:
++ virtual void layoutSymbol();
++ virtual QRect symbolRect() const;
++
++ virtual FormType form() const;
++
++ private:
++ const OperSpec *m_oper_spec;
++};
++
++class MmlMstyleNode : public MmlNode
++{
++ public:
++ MmlMstyleNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MstyleNode, document, attribute_map) {}
++};
++
++class MmlTableBaseNode : public MmlNode
++{
++ public:
++ MmlTableBaseNode(NodeType type, MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(type, document, attribute_map) {}
++};
++
++class MmlMtableNode : public MmlTableBaseNode
++{
++ public:
++ MmlMtableNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTableBaseNode(MtableNode, document, attribute_map) {}
++
++ int rowspacing() const;
++ int columnspacing() const;
++ int framespacing_hor() const;
++ int framespacing_ver() const;
++ FrameType frame() const;
++ FrameType columnlines(int idx) const;
++ FrameType rowlines(int idx) const;
++
++ protected:
++ virtual void layoutSymbol();
++ virtual QRect symbolRect() const;
++ virtual void paintSymbol(QPainter *p) const;
++
++ private:
++ struct CellSizeData
++ {
++ void init(const MmlNode *first_row);
++ QList<int> col_widths, row_heights;
++ int numCols() const { return col_widths.count(); }
++ int numRows() const { return row_heights.count(); }
++ uint colWidthSum() const;
++ uint rowHeightSum() const;
++ };
++
++ CellSizeData m_cell_size_data;
++ int m_content_width, m_content_height;
++};
++
++class MmlMtrNode : public MmlTableBaseNode
++{
++ public:
++ MmlMtrNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTableBaseNode(MtrNode, document, attribute_map) {}
++ void layoutCells(const QList<int> &col_widths, int col_spc);
++};
++
++class MmlMtdNode : public MmlTableBaseNode
++{
++ public:
++ MmlMtdNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTableBaseNode(MtdNode, document, attribute_map)
++ { m_scriptlevel_adjust = 0; }
++ virtual void setMyRect(const QRect &rect);
++
++ ColAlign columnalign();
++ RowAlign rowalign();
++ uint colNum();
++ uint rowNum();
++ virtual int scriptlevel(const MmlNode *child = 0) const;
++
++ private:
++ int m_scriptlevel_adjust; // added or subtracted to scriptlevel to
++ // make contents fit the cell
++};
++
++class MmlMoverNode : public MmlNode
++{
++ public:
++ MmlMoverNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MoverNode, document, attribute_map) {}
++ virtual int scriptlevel(const MmlNode *node = 0) const;
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMunderNode : public MmlNode
++{
++ public:
++ MmlMunderNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MunderNode, document, attribute_map) {}
++ virtual int scriptlevel(const MmlNode *node = 0) const;
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMunderoverNode : public MmlNode
++{
++ public:
++ MmlMunderoverNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MunderoverNode, document, attribute_map) {}
++ virtual int scriptlevel(const MmlNode *node = 0) const;
++
++ protected:
++ virtual void layoutSymbol();
++};
++
++class MmlMerrorNode : public MmlNode
++{
++ public:
++ MmlMerrorNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MerrorNode, document, attribute_map) {}
++};
++
++class MmlMtextNode : public MmlNode
++{
++ public:
++ MmlMtextNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MtextNode, document, attribute_map) {}
++};
++
++class MmlMpaddedNode : public MmlNode
++{
++ public:
++ MmlMpaddedNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MpaddedNode, document, attribute_map) {}
++
++ public:
++ int lspace() const;
++ int width() const;
++ int height() const;
++ int depth() const;
++
++ protected:
++ int interpretSpacing(QString value, int base_value, bool *ok) const;
++ virtual void layoutSymbol();
++ virtual QRect symbolRect() const;
++};
++
++class MmlMspaceNode : public MmlNode
++{
++ public:
++ MmlMspaceNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlNode(MspaceNode, document, attribute_map) {}
++};
++
++static const NodeSpec *mmlFindNodeSpec(Mml::NodeType type);
++static const NodeSpec *mmlFindNodeSpec(const QString &tag);
++static bool mmlCheckChildType(Mml::NodeType parent_type,
++ Mml::NodeType child_type, QString *error_str);
++static bool mmlCheckAttributes(Mml::NodeType child_type,
++ const MmlAttributeMap &attr, QString *error_str);
++static QString mmlDictAttribute(const QString &name, const OperSpec *spec);
++static const OperSpec *mmlFindOperSpec(const QString &name, Mml::FormType form);
++static int interpretSpacing(QString name, int em, int ex, bool *ok);
++static int interpretPercentSpacing(QString value, int base, bool *ok);
++static uint interpretMathVariant(const QString &value, bool *ok);
++static Mml::FormType interpretForm(const QString &value, bool *ok);
++static Mml::FrameType interpretFrameType(const QString &value_list, uint idx, bool *ok);
++static Mml::FrameSpacing interpretFrameSpacing(const QString &value_list, int em, int ex, bool *ok);
++static Mml::ColAlign interpretColAlign(const QString &value_list, uint colnum, bool *ok);
++static Mml::RowAlign interpretRowAlign(const QString &value_list, uint rownum, bool *ok);
++static Mml::FrameType interpretFrameType(const QString &value_list, uint idx, bool *ok);
++static QFont interpretDepreciatedFontAttr(const MmlAttributeMap &font_attr, QFont &fn, int em, int ex);
++static QFont interpretMathSize(QString value, QFont &fn, int em, int ex, bool *ok);
++static QString interpretListAttr(const QString &value_list, int idx, const QString &def);
++static QString rectToStr(const QRect &rect);
++static QString entityDeclarations();
++
++
++#define MML_ATT_COMMON " class style id xref actiontype "
++#define MML_ATT_FONTSIZE " fontsize fontweight fontstyle fontfamily color "
++#define MML_ATT_MATHVARIANT " mathvariant mathsize mathcolor mathbackground "
++#define MML_ATT_FONTINFO MML_ATT_FONTSIZE MML_ATT_MATHVARIANT
++#define MML_ATT_OPINFO " form fence separator lspace rspace stretchy symmetric " \
++ " maxsize minsize largeop movablelimits accent "
++#define MML_ATT_SIZEINFO " width height depth "
++#define MML_ATT_TABLEINFO " align rowalign columnalign columnwidth groupalign " \
++ " alignmentscope side rowspacing columnspacing rowlines " \
++ " columnlines width frame framespacing equalrows " \
++ " equalcolumns displaystyle "
++#define MML_ATT_MFRAC " bevelled numalign denomalign linethickness "
++#define MML_ATT_MSTYLE MML_ATT_FONTINFO MML_ATT_OPINFO \
++ " scriptlevel lquote rquote linethickness displaystyle " \
++ " scriptsizemultiplier scriptminsize background " \
++ " veryverythinmathspace verythinmathspace thinmathspace " \
++ " mediummathspace thickmathspace verythickmathspace " \
++ " veryverythickmathspace open close separators " \
++ " subscriptshift superscriptshift accentunder tableinfo " \
++ " rowspan columnspan edge selection bevelled "
++#define MML_ATT_MTABLE " align rowalign columnalign groupalign alignmentscope " \
++ " columnwidth width rowspacing columnspacing rowlines columnlines " \
++ " frame framespacing equalrows equalcolumns displaystyle side " \
++ " minlabelspacing "
++
++static const NodeSpec g_node_spec_data[] = {
++
++// type tag type_str child_spec child_types attributes ""=none, 0=any
++// ----------------------- --------------- ------------------- ----------------------- ------------------------ ------------------------------------
++ { Mml::MiNode, "mi", "MiNode", NodeSpec::ChildAny, " TextNode MalignMark ", MML_ATT_COMMON MML_ATT_FONTINFO },
++ { Mml::MnNode, "mn", "MnNode", NodeSpec::ChildAny, " TextNode MalignMark ", MML_ATT_COMMON MML_ATT_FONTINFO },
++ { Mml::MfracNode, "mfrac", "MfracNode", 2, 0, MML_ATT_COMMON MML_ATT_MFRAC },
++ { Mml::MrowNode, "mrow", "MrowNode", NodeSpec::ChildAny, 0, MML_ATT_COMMON " display mode " },
++ { Mml::MsqrtNode, "msqrt", "MsqrtNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON },
++ { Mml::MrootNode, "mroot", "MrootNode", 2, 0, MML_ATT_COMMON },
++ { Mml::MsupNode, "msup", "MsupNode", 2, 0, MML_ATT_COMMON " subscriptshift " },
++ { Mml::MsubNode, "msub", "MsubNode", 2, 0, MML_ATT_COMMON " superscriptshift " },
++ { Mml::MsubsupNode, "msubsup", "MsubsupNode", 3, 0, MML_ATT_COMMON " subscriptshift superscriptshift " },
++ { Mml::MoNode, "mo", "MoNode", NodeSpec::ChildAny, " TextNode MalignMark ", MML_ATT_COMMON MML_ATT_FONTINFO MML_ATT_OPINFO },
++ { Mml::MstyleNode, "mstyle", "MstyleNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON MML_ATT_MSTYLE },
++ { Mml::MphantomNode, "mphantom", "MphantomNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON },
++ { Mml::MalignMarkNode, "malignmark", "MalignMarkNode", 0, 0, "" },
++ { Mml::MfencedNode, "mfenced", "MfencedNode", NodeSpec::ChildAny, 0, MML_ATT_COMMON " open close separators " },
++ { Mml::MtableNode, "mtable", "MtableNode", NodeSpec::ChildAny, " MtrNode ", MML_ATT_COMMON MML_ATT_MTABLE },
++ { Mml::MtrNode, "mtr", "MtrNode", NodeSpec::ChildAny, " MtdNode ", MML_ATT_COMMON " rowalign columnalign groupalign " },
++ { Mml::MtdNode, "mtd", "MtdNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON " rowspan columnspan rowalign columnalign groupalign " },
++ { Mml::MoverNode, "mover", "MoverNode", 2, 0, MML_ATT_COMMON " accent " },
++ { Mml::MunderNode, "munder", "MunderNode", 2, 0, MML_ATT_COMMON " accentunder " },
++ { Mml::MunderoverNode, "munderover", "MunderoverNode", 3, 0, MML_ATT_COMMON " accentunder accent " },
++ { Mml::MerrorNode, "merror", "MerrorNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON },
++ { Mml::MtextNode, "mtext", "MtextNode", 1, " TextNode ", MML_ATT_COMMON " width height depth linebreak " },
++ { Mml::MpaddedNode, "mpadded", "MpaddedNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON " width height depth lspace " },
++ { Mml::MspaceNode, "mspace", "MspaceNode", NodeSpec::ImplicitMrow, 0, MML_ATT_COMMON " width height depth linebreak " },
++ { Mml::TextNode, 0, "TextNode", NodeSpec::ChildIgnore, 0, "" },
++ { Mml::UnknownNode, 0, "UnknownNode", NodeSpec::ChildAny, 0, 0 },
++ { Mml::NoNode, 0, 0, 0, 0, 0 }
++};
++
++static const char *g_oper_spec_names[g_oper_spec_rows] = { "accent", "fence", "largeop", "lspace", "minsize", "movablelimits", "rspace", "separator", "stretchy" /* stretchdir */ };
++static const OperSpec g_oper_spec_data[] = {
++
++ { "!!" , Mml::PostfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "!!"
++ { "!" , Mml::PostfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "!"
++ { "!=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "!="
++ { "⩓" , Mml::InfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "mediummathspace", 0, "true" }, OperSpec::VStretch }, // "⩓"
++ { "⁡" , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "⁡"
++ { "≔" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≔"
++ { "∖" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, "true" }, OperSpec::HVStretch }, // "∖"
++ { "∵" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∵"
++ { "˘" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "˘"
++ { "⋒" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋒"
++ { "ⅅ" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // ⅅ"
++ { "¸" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "¸"
++ { "·" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "·"
++ { "⊙" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊙"
++ { "⊖" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊖"
++ { "⊕" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊕"
++ { "⊗" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊗"
++ { "∲" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, 0, "0em", 0, "true"}, OperSpec::VStretch }, // ∲"
++ { "”" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // ”"
++ { "’" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "’"
++ { "∷" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∷"
++ { "≡" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≡"
++ { "∮" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "∮"
++ { "∐" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∐"
++ { "∳", Mml::PrefixForm, { 0, 0, "true", "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // &CounterClockwiseContourInteg
++ { "⨯" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⨯"
++ { "⋓" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋓"
++ { "≍" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≍"
++ { "∇" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∇"
++ { "´" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "´"
++ { "˙" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "˙"
++ { "˝" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // ˝"
++ { "`" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "`"
++ { "&DiacriticalLeftArrow;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalLeftArrow;"
++ { "&DiacriticalLeftRightArrow;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalLeftRightArrow;"
++ { "&DiacriticalLeftRightVector;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalLeftRightVector;"
++ { "&DiacriticalLeftVector;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalLeftVector;"
++ { "&DiacriticalRightArrow;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalRightArrow;"
++ { "&DiacriticalRightVector;" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &DiacriticalRightVector;"
++ { "˜" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::NoStretch }, // "˜"
++ { "⋄" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋄"
++ { "ⅆ" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "ⅆ"
++ { "≐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≐"
++ { "∯" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // ∯"
++ { "¨" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "¨"
++ { "⇓" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⇓"
++ { "⇐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇐"
++ { "⇔" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // ⇔"
++ { "⫤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⫤"
++ { "⟸" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // "⟸"
++ { "⟺" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // ⟺"
++ { "⟹" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // ⟹"
++ { "⇒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇒"
++ { "⊨" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊨"
++ { "⇑" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⇑"
++ { "⇕" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⇕"
++ { "∥" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∥"
++ { "↓" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "↓"
++ { "⤓" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⤓"
++ { "⇵" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⇵"
++ { "̑" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "̑"
++ { "⥐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥐"
++ { "⥞" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥞"
++ { "↽" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "↽"
++ { "⥖" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥖"
++ { "⥟" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥟"
++ { "⇁" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⇁"
++ { "⥗" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥗"
++ { "⊤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊤"
++ { "↧" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "↧"
++ { "∈" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∈"
++ { "⩵" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⩵"
++ { "≂" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≂"
++ { "⇌" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇌"
++ { "∃" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∃"
++ { "∀" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∀"
++ { "≥" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≥"
++ { "⋛" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋛"
++ { "≧" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≧"
++ { "⪢" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪢"
++ { "≷" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≷"
++ { "⩾" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⩾"
++ { "≳" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≳"
++ { "ˇ" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::NoStretch }, // "ˇ"
++ { "^" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "^"
++ { "─" , Mml::InfixForm, { 0, 0, 0, "0em", "0", 0, "0em", 0, "true" }, OperSpec::HStretch }, // "─"
++ { "≎" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≎"
++ { "≏" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≏"
++ { "⇒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇒"
++ { "∫" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "∫"
++ { "⋂" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, "true", "thinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⋂"
++ { "⁣" , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "0em", "true", 0 }, OperSpec::NoStretch }, // "⁣"
++ { "⁢" , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "⁢"
++ { "⟨" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⟨"
++ { "←" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "←"
++ { "⇤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇤"
++ { "⇆" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇆"
++ { "&LeftBracketingBar;" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "&LeftBracketingBar;"
++ { "⌈" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⌈"
++ { "⟦" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⟦"
++ { "&LeftDoubleBracketingBar;" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &LeftDoubleBracketingBar;"
++ { "⥡" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥡"
++ { "⇃" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⇃"
++ { "⥙" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥙"
++ { "⌊" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⌊"
++ { "↔" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "↔"
++ { "⥎" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⥎"
++ { "&LeftSkeleton;" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "&LeftSkeleton;"
++ { "⊣" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊣"
++ { "↤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "↤"
++ { "⥚" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⥚"
++ { "⊲" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊲"
++ { "⧏" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⧏"
++ { "⊴" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊴"
++ { "⥑" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥑"
++ { "⥠" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥠"
++ { "↿" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "↿"
++ { "⥘" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥘"
++ { "↼" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "↼"
++ { "⥒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::VStretch }, // "⥒"
++ { "⋚" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋚"
++ { "≦" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≦"
++ { "≶" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≶"
++ { "⪡" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪡"
++ { "⩽" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⩽"
++ { "≲" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≲"
++ { "⟵" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // "⟵"
++ { "⟷" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // "⟷"
++ { "⟶" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // "⟶"
++ { "↙" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "↙"
++ { "↘" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "↘"
++ { "∓" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "veryverythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∓"
++ { "≫" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ≫"
++ { "≪" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≪"
++ { "⫬" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⫬"
++ { "≢" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≢"
++ { "≭" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≭"
++ { "∦" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ∦"
++ { "∉" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∉"
++ { "≠" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≠"
++ { "≂̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≂̸"
++ { "∄" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∄"
++ { "≯" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≯"
++ { "≱" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≱"
++ { "≧̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≧̸"
++ { "≫̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≫̸"
++ { "≹" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≹"
++ { "⩾̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⩾̸"
++ { "≵" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≵"
++ { "≎̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≎̸"
++ { "≏̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≏̸"
++ { "⋪" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋪"
++ { "⧏̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⧏̸"
++ { "⋬" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋬"
++ { "≮" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≮"
++ { "≰" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≰"
++ { "&NotLessFullEqual;" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "&NotLessFullEqual;"
++ { "≸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≸"
++ { "≪̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≪̸"
++ { "⩽̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⩽̸"
++ { "≴" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≴"
++ { "⪢̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⪢̸"
++ { "⪡̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪡̸"
++ { "⊀" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊀"
++ { "⪯̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪯̸"
++ { "⋠" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋠"
++ { "&NotPrecedesTilde;" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "&NotPrecedesTilde;"
++ { "∌" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∌"
++ { "⋫" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋫"
++ { "⧐̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⧐̸"
++ { "⋭" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋭"
++ { "⊏̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊏̸"
++ { "⋢" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋢"
++ { "⊐̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊐̸"
++ { "⋣" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋣"
++ { "⊂⃒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊂⃒"
++ { "⊈" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊈"
++ { "⊁" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊁"
++ { "⪰̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪰̸"
++ { "⋡" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ⋡"
++ { "≿̸" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≿̸"
++ { "⊃⃒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊃⃒"
++ { "⊉" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊉"
++ { "≁" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≁"
++ { "≄" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≄"
++ { "≇" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≇"
++ { "≉" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≉"
++ { "∤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∤"
++ { "“" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // “"
++ { "‘" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "‘"
++ { "⩔" , Mml::InfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "mediummathspace", 0, "true" }, OperSpec::VStretch }, // "⩔"
++ { "‾" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "‾"
++ { "⏞" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⏞"
++ { "⎴" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⎴"
++ { "⏜" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⏜"
++ { "∂" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∂"
++ { "±" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "veryverythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "±"
++ { "≺" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≺"
++ { "⪯" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪯"
++ { "≼" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≼"
++ { "≾" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≾"
++ { "∏" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, "true", "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∏"
++ { "∷" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∷"
++ { "∝" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∝"
++ { "∋" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∋"
++ { "⇋" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇋"
++ { "⥯" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HStretch }, // ⥯"
++ { "⟩" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⟩"
++ { "→" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "→"
++ { "⇥" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇥"
++ { "⇄" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇄"
++ { "&RightBracketingBar;" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "&RightBracketingBar;"
++ { "⌉" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⌉"
++ { "⟧" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⟧"
++ { "&RightDoubleBracketingBar;" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // &RightDoubleBracketingBar;"
++ { "⥝" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥝"
++ { "⇂" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⇂"
++ { "⥕" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥕"
++ { "⌋" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "⌋"
++ { "&RightSkeleton;" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "&RightSkeleton;"
++ { "⊢" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊢"
++ { "↦" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "↦"
++ { "⥛" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⥛"
++ { "⊳" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊳"
++ { "⧐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⧐"
++ { "⊵" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊵"
++ { "⥏" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⥏"
++ { "⥜" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥜"
++ { "↾" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "↾"
++ { "⥔" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⥔"
++ { "⇀" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⇀"
++ { "⥓" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HStretch }, // "⥓"
++ { "⥰" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⥰"
++ { "↓" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "↓"
++ { "←" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::HStretch }, // "←"
++ { "→" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::HStretch }, // "→"
++ { "↑" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::VStretch }, // "↑"
++ { "∘" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∘"
++ { "√" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "√"
++ { "□" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "□"
++ { "⊓" , Mml::InfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "mediummathspace", 0, "true" }, OperSpec::HVStretch }, // "⊓"
++ { "⊏" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊏"
++ { "⊑" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊑"
++ { "⊐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊐"
++ { "⊒" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊒"
++ { "⊔" , Mml::InfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "mediummathspace", 0, "true" }, OperSpec::HVStretch }, // "⊔"
++ { "⋆" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋆"
++ { "⋐" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋐"
++ { "⊆" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊆"
++ { "≻" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≻"
++ { "⪰" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⪰"
++ { "≽" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≽"
++ { "≿" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≿"
++ { "∋" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∋"
++ { "∑" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, "true", "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "∑"
++ { "⊃" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊃"
++ { "⊇" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊇"
++ { "∴" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∴"
++ { "∼" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∼"
++ { "≃" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≃"
++ { "≅" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≅"
++ { "≈" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≈"
++ { "⃛" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "⃛"
++ { "_" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "_"
++ { "⏟" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⏟"
++ { "⎵" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⎵"
++ { "⏝" , Mml::PostfixForm, { "true", 0, 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::HStretch }, // "⏝"
++ { "⋃" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, "true", "thinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⋃"
++ { "⊎" , Mml::PrefixForm, { 0, 0, "true", "0em", 0, "true", "thinmathspace", 0, "true" }, OperSpec::HVStretch }, // "⊎"
++ { "↑" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "↑"
++ { "⤒" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⤒"
++ { "⇅" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⇅"
++ { "↕" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "↕"
++ { "⥮" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "⥮"
++ { "⊥" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "⊥"
++ { "↥" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, "true" }, OperSpec::VStretch }, // "↥"
++ { "↖" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "↖"
++ { "↗" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::HVStretch }, // "↗"
++ { "⋁" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋁"
++ { "∣" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "∣"
++ { "|" , Mml::InfixForm, { 0, 0, 0, "0em", "0", 0, "0em", 0, "true" }, OperSpec::VStretch }, // "|"
++ { "❘" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::VStretch }, // "❘"
++ { "≀" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "≀"
++ { "⋀" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "⋀"
++ { "&" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "&"
++ { "&&" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "&&"
++ { "≤" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "≤"
++ { "<" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "<"
++ { "<=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "<="
++ { "<>" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "<>"
++ { "'" , Mml::PostfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "'"
++ { "(" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "("
++ { ")" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // ")"
++ { "*" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "*"
++ { "**" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "**"
++ { "*=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "*="
++ { "+" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "+"
++ { "+" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "veryverythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "+"
++ { "++" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "++"
++ { "+=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "+="
++ { "," , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "verythickmathspace", "true", 0 }, OperSpec::NoStretch }, // ","
++ { "-" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "-"
++ { "-" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "veryverythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "-"
++ { "--" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "--"
++ { "-=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "-="
++ { "->" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "->"
++ { "." , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "."
++ { ".." , Mml::PostfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // ".."
++ { "..." , Mml::PostfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "0em", 0, 0 }, OperSpec::NoStretch }, // "..."
++ { "/" , Mml::InfixForm, { 0, 0, 0, "thinmathspace", 0, 0, "thinmathspace", 0, "true" }, OperSpec::VStretch }, // "/"
++ { "//" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "//"
++ { "/=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "/="
++ { ":" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ":"
++ { ":=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ":="
++ { ";" , Mml::InfixForm, { 0, 0, 0, "0em", 0, 0, "verythickmathspace", "true", 0 }, OperSpec::NoStretch }, // ";"
++ { ";" , Mml::PostfixForm, { 0, 0, 0, "0em", 0, 0, "0em", "true", 0 }, OperSpec::NoStretch }, // ";"
++ { "=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "="
++ { "==" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // "=="
++ { ">" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ">"
++ { ">=" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, 0 }, OperSpec::NoStretch }, // ">="
++ { "?" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "?"
++ { "@" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "@"
++ { "[" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "["
++ { "]" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "]"
++ { "^" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "^"
++ { "_" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "_"
++ { "lim" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, "true", "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "lim"
++ { "max" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, "true", "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "max"
++ { "min" , Mml::PrefixForm, { 0, 0, 0, "0em", 0, "true", "thinmathspace", 0, 0 }, OperSpec::NoStretch }, // "min"
++ { "{" , Mml::PrefixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "{"
++ { "|" , Mml::InfixForm, { 0, 0, 0, "thickmathspace", 0, 0, "thickmathspace", 0, "true" }, OperSpec::VStretch }, // "|"
++ { "||" , Mml::InfixForm, { 0, 0, 0, "mediummathspace", 0, 0, "mediummathspace", 0, 0 }, OperSpec::NoStretch }, // "||"
++ { "}" , Mml::PostfixForm, { 0, "true", 0, "0em", 0, 0, "0em", 0, "true" }, OperSpec::VStretch }, // "}"
++ { "~" , Mml::InfixForm, { 0, 0, 0, "verythinmathspace", 0, 0, "verythinmathspace", 0, 0 }, OperSpec::NoStretch }, // "~"
++
++ { 0 , Mml::InfixForm, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, OperSpec::NoStretch }
++};
++
++static const OperSpec g_oper_spec_defaults =
++ { 0 , Mml::InfixForm, { "false", "false", "false", "thickmathspace", "1", "false", "thickmathspace", "false", "false" }, OperSpec::NoStretch };
++
++static const uint g_oper_spec_count = sizeof(g_oper_spec_data)/sizeof(OperSpec) - 1;
++
++static const EntitySpec g_xml_entity_data[] = {
++ { "angzarr", "⍼" },
++ { "cirmid", "⫯" },
++ { "cudarrl", "⤸" },
++ { "cudarrr", "⤵" },
++ { "cularr", "↶" },
++ { "cularrp", "⤽" },
++ { "curarr", "↷" },
++ { "curarrm", "⤼" },
++ { "Darr", "↡" },
++ { "dArr", "⇓" },
++ { "ddarr", "⇊" },
++ { "DDotrahd", "⤑" },
++ { "dfisht", "⥿" },
++ { "dHar", "⥥" },
++ { "dharl", "⇃" },
++ { "dharr", "⇂" },
++ { "duarr", "⇵" },
++ { "duhar", "⥯" },
++ { "dzigrarr", "⟿" },
++ { "erarr", "⥱" },
++ { "hArr", "⇔" },
++ { "harr", "↔" },
++ { "harrcir", "⥈" },
++ { "harrw", "↭" },
++ { "hoarr", "⇿" },
++ { "imof", "⊷" },
++ { "lAarr", "⇚" },
++ { "Larr", "↞" },
++ { "larrbfs", "⤟" },
++ { "larrfs", "⤝" },
++ { "larrhk", "↩" },
++ { "larrlp", "↫" },
++ { "larrpl", "⤹" },
++ { "larrsim", "⥳" },
++ { "larrtl", "↢" },
++ { "lAtail", "⤛" },
++ { "latail", "⤙" },
++ { "lBarr", "⤎" },
++ { "lbarr", "⤌" },
++ { "ldca", "⤶" },
++ { "ldrdhar", "⥧" },
++ { "ldrushar", "⥋" },
++ { "ldsh", "↲" },
++ { "lfisht", "⥼" },
++ { "lHar", "⥢" },
++ { "lhard", "↽" },
++ { "lharu", "↼" },
++ { "lharul", "⥪" },
++ { "llarr", "⇇" },
++ { "llhard", "⥫" },
++ { "loarr", "⇽" },
++ { "lrarr", "⇆" },
++ { "lrhar", "⇋" },
++ { "lrhard", "⥭" },
++ { "lsh", "↰" },
++ { "lurdshar", "⥊" },
++ { "luruhar", "⥦" },
++ { "Map", "⤅" },
++ { "map", "↦" },
++ { "midcir", "⫰" },
++ { "mumap", "⊸" },
++ { "nearhk", "⤤" },
++ { "neArr", "⇗" },
++ { "nearr", "↗" },
++ { "nesear", "⤨" },
++ { "nhArr", "⇎" },
++ { "nharr", "↮" },
++ { "nlArr", "⇍" },
++ { "nlarr", "↚" },
++ { "nrArr", "⇏" },
++ { "nrarr", "↛" },
++ { "nrarrc", "⤳̸" },
++ { "nrarrw", "↝̸" },
++ { "nvHarr", "⤄" },
++ { "nvlArr", "⤂" },
++ { "nvrArr", "⤃" },
++ { "nwarhk", "⤣" },
++ { "nwArr", "⇖" },
++ { "nwarr", "↖" },
++ { "nwnear", "⤧" },
++ { "olarr", "↺" },
++ { "orarr", "↻" },
++ { "origof", "⊶" },
++ { "rAarr", "⇛" },
++ { "Rarr", "↠" },
++ { "rarrap", "⥵" },
++ { "rarrbfs", "⤠" },
++ { "rarrc", "⤳" },
++ { "rarrfs", "⤞" },
++ { "rarrhk", "↪" },
++ { "rarrlp", "↬" },
++ { "rarrpl", "⥅" },
++ { "rarrsim", "⥴" },
++ { "Rarrtl", "⤖" },
++ { "rarrtl", "↣" },
++ { "rarrw", "↝" },
++ { "rAtail", "⤜" },
++ { "ratail", "⤚" },
++ { "RBarr", "⤐" },
++ { "rBarr", "⤏" },
++ { "rbarr", "⤍" },
++ { "rdca", "⤷" },
++ { "rdldhar", "⥩" },
++ { "rdsh", "↳" },
++ { "rfisht", "⥽" },
++ { "rHar", "⥤" },
++ { "rhard", "⇁" },
++ { "rharu", "⇀" },
++ { "rharul", "⥬" },
++ { "rlarr", "⇄" },
++ { "rlhar", "⇌" },
++ { "roarr", "⇾" },
++ { "rrarr", "⇉" },
++ { "rsh", "↱" },
++ { "ruluhar", "⥨" },
++ { "searhk", "⤥" },
++ { "seArr", "⇘" },
++ { "searr", "↘" },
++ { "seswar", "⤩" },
++ { "simrarr", "⥲" },
++ { "slarr", "←" },
++ { "srarr", "→" },
++ { "swarhk", "⤦" },
++ { "swArr", "⇙" },
++ { "swarr", "↙" },
++ { "swnwar", "⤪" },
++ { "Uarr", "↟" },
++ { "uArr", "⇑" },
++ { "Uarrocir", "⥉" },
++ { "udarr", "⇅" },
++ { "udhar", "⥮" },
++ { "ufisht", "⥾" },
++ { "uHar", "⥣" },
++ { "uharl", "↿" },
++ { "uharr", "↾" },
++ { "uuarr", "⇈" },
++ { "vArr", "⇕" },
++ { "varr", "↕" },
++ { "xhArr", "⟺" },
++ { "xharr", "⟷" },
++ { "xlArr", "⟸" },
++ { "xlarr", "⟵" },
++ { "xmap", "⟼" },
++ { "xrArr", "⟹" },
++ { "xrarr", "⟶" },
++ { "zigrarr", "⇝" },
++ { "ac", "∾" },
++ { "acE", "∾̳" },
++ { "amalg", "⨿" },
++ { "barvee", "⊽" },
++ { "Barwed", "⌆" },
++ { "barwed", "⌅" },
++ { "bsolb", "⧅" },
++ { "Cap", "⋒" },
++ { "capand", "⩄" },
++ { "capbrcup", "⩉" },
++ { "capcap", "⩋" },
++ { "capcup", "⩇" },
++ { "capdot", "⩀" },
++ { "caps", "∩︀" },
++ { "ccaps", "⩍" },
++ { "ccups", "⩌" },
++ { "ccupssm", "⩐" },
++ { "coprod", "∐" },
++ { "Cup", "⋓" },
++ { "cupbrcap", "⩈" },
++ { "cupcap", "⩆" },
++ { "cupcup", "⩊" },
++ { "cupdot", "⊍" },
++ { "cupor", "⩅" },
++ { "cups", "∪︀" },
++ { "cuvee", "⋎" },
++ { "cuwed", "⋏" },
++ { "Dagger", "‡" },
++ { "dagger", "†" },
++ { "diam", "⋄" },
++ { "divonx", "⋇" },
++ { "eplus", "⩱" },
++ { "hercon", "⊹" },
++ { "intcal", "⊺" },
++ { "iprod", "⨼" },
++ { "loplus", "⨭" },
++ { "lotimes", "⨴" },
++ { "lthree", "⋋" },
++ { "ltimes", "⋉" },
++ { "midast", "*" },
++ { "minusb", "⊟" },
++ { "minusd", "∸" },
++ { "minusdu", "⨪" },
++ { "ncap", "⩃" },
++ { "ncup", "⩂" },
++ { "oast", "⊛" },
++ { "ocir", "⊚" },
++ { "odash", "⊝" },
++ { "odiv", "⨸" },
++ { "odot", "⊙" },
++ { "odsold", "⦼" },
++ { "ofcir", "⦿" },
++ { "ogt", "⧁" },
++ { "ohbar", "⦵" },
++ { "olcir", "⦾" },
++ { "olt", "⧀" },
++ { "omid", "⦶" },
++ { "ominus", "⊖" },
++ { "opar", "⦷" },
++ { "operp", "⦹" },
++ { "oplus", "⊕" },
++ { "osol", "⊘" },
++ { "Otimes", "⨷" },
++ { "otimes", "⊗" },
++ { "otimesas", "⨶" },
++ { "ovbar", "⌽" },
++ { "plusacir", "⨣" },
++ { "plusb", "⊞" },
++ { "pluscir", "⨢" },
++ { "plusdo", "∔" },
++ { "plusdu", "⨥" },
++ { "pluse", "⩲" },
++ { "plussim", "⨦" },
++ { "plustwo", "⨧" },
++ { "prod", "∏" },
++ { "race", "⧚" },
++ { "roplus", "⨮" },
++ { "rotimes", "⨵" },
++ { "rthree", "⋌" },
++ { "rtimes", "⋊" },
++ { "sdot", "⋅" },
++ { "sdotb", "⊡" },
++ { "setmn", "∖" },
++ { "simplus", "⨤" },
++ { "smashp", "⨳" },
++ { "solb", "⧄" },
++ { "sqcap", "⊓" },
++ { "sqcaps", "⊓︀" },
++ { "sqcup", "⊔" },
++ { "sqcups", "⊔︀" },
++ { "ssetmn", "∖" },
++ { "sstarf", "⋆" },
++ { "subdot", "⪽" },
++ { "sum", "∑" },
++ { "supdot", "⪾" },
++ { "timesb", "⊠" },
++ { "timesbar", "⨱" },
++ { "timesd", "⨰" },
++ { "tridot", "◬" },
++ { "triminus", "⨺" },
++ { "triplus", "⨹" },
++ { "trisb", "⧍" },
++ { "tritime", "⨻" },
++ { "uplus", "⊎" },
++ { "veebar", "⊻" },
++ { "wedbar", "⩟" },
++ { "wreath", "≀" },
++ { "xcap", "⋂" },
++ { "xcirc", "◯" },
++ { "xcup", "⋃" },
++ { "xdtri", "▽" },
++ { "xodot", "⨀" },
++ { "xoplus", "⨁" },
++ { "xotime", "⨂" },
++ { "xsqcup", "⨆" },
++ { "xuplus", "⨄" },
++ { "xutri", "△" },
++ { "xvee", "⋁" },
++ { "xwedge", "⋀" },
++ { "dlcorn", "⌞" },
++ { "drcorn", "⌟" },
++ { "gtlPar", "⦕" },
++ { "langd", "⦑" },
++ { "lbrke", "⦋" },
++ { "lbrksld", "⦏" },
++ { "lbrkslu", "⦍" },
++ { "lceil", "⌈" },
++ { "lfloor", "⌊" },
++ { "lmoust", "⎰" },
++ { "lparlt", "⦓" },
++ { "ltrPar", "⦖" },
++ { "rangd", "⦒" },
++ { "rbrke", "⦌" },
++ { "rbrksld", "⦎" },
++ { "rbrkslu", "⦐" },
++ { "rceil", "⌉" },
++ { "rfloor", "⌋" },
++ { "rmoust", "⎱" },
++ { "rpargt", "⦔" },
++ { "ulcorn", "⌜" },
++ { "urcorn", "⌝" },
++ { "gnap", "⪊" },
++ { "gnE", "≩" },
++ { "gne", "⪈" },
++ { "gnsim", "⋧" },
++ { "gvnE", "≩︀" },
++ { "lnap", "⪉" },
++ { "lnE", "≨" },
++ { "lne", "⪇" },
++ { "lnsim", "⋦" },
++ { "lvnE", "≨︀" },
++ { "nap", "≉" },
++ { "napE", "⩰̸" },
++ { "napid", "≋̸" },
++ { "ncong", "≇" },
++ { "ncongdot", "⩭̸" },
++ { "nequiv", "≢" },
++ { "ngE", "≧̸" },
++ { "nge", "≱" },
++ { "nges", "⩾̸" },
++ { "nGg", "⋙̸" },
++ { "ngsim", "≵" },
++ { "nGt", "≫⃒" },
++ { "ngt", "≯" },
++ { "nGtv", "≫̸" },
++ { "nlE", "≦̸" },
++ { "nle", "≰" },
++ { "nles", "⩽̸" },
++ { "nLl", "⋘̸" },
++ { "nlsim", "≴" },
++ { "nLt", "≪⃒" },
++ { "nlt", "≮" },
++ { "nltri", "⋪" },
++ { "nltrie", "⋬" },
++ { "nLtv", "≪̸" },
++ { "nmid", "∤" },
++ { "npar", "∦" },
++ { "npr", "⊀" },
++ { "nprcue", "⋠" },
++ { "npre", "⪯̸" },
++ { "nrtri", "⋫" },
++ { "nrtrie", "⋭" },
++ { "nsc", "⊁" },
++ { "nsccue", "⋡" },
++ { "nsce", "⪰̸" },
++ { "nsim", "≁" },
++ { "nsime", "≄" },
++ { "nsmid", "∤" },
++ { "nspar", "∦" },
++ { "nsqsube", "⋢" },
++ { "nsqsupe", "⋣" },
++ { "nsub", "⊄" },
++ { "nsubE", "⫅̸" },
++ { "nsube", "⊈" },
++ { "nsup", "⊅" },
++ { "nsupE", "⫆̸" },
++ { "nsupe", "⊉" },
++ { "ntgl", "≹" },
++ { "ntlg", "≸" },
++ { "nvap", "≍⃒" },
++ { "nVDash", "⊯" },
++ { "nVdash", "⊮" },
++ { "nvDash", "⊭" },
++ { "nvdash", "⊬" },
++ { "nvge", "≥⃒" },
++ { "nvgt", ">⃒" },
++ { "nvle", "≤⃒" },
++ { "nvlt", "<⃒" },
++ { "nvltrie", "⊴⃒" },
++ { "nvrtrie", "⊵⃒" },
++ { "nvsim", "∼⃒" },
++ { "parsim", "⫳" },
++ { "prnap", "⪹" },
++ { "prnE", "⪵" },
++ { "prnsim", "⋨" },
++ { "rnmid", "⫮" },
++ { "scnap", "⪺" },
++ { "scnE", "⪶" },
++ { "scnsim", "⋩" },
++ { "simne", "≆" },
++ { "solbar", "⌿" },
++ { "subnE", "⫋" },
++ { "subne", "⊊" },
++ { "supnE", "⫌" },
++ { "supne", "⊋" },
++ { "vnsub", "⊂⃒" },
++ { "vnsup", "⊃⃒" },
++ { "vsubnE", "⫋︀" },
++ { "vsubne", "⊊︀" },
++ { "vsupnE", "⫌︀" },
++ { "vsupne", "⊋︀" },
++ { "ang", "∠" },
++ { "ange", "⦤" },
++ { "angmsd", "∡" },
++ { "angmsdaa", "⦨" },
++ { "angmsdab", "⦩" },
++ { "angmsdac", "⦪" },
++ { "angmsdad", "⦫" },
++ { "angmsdae", "⦬" },
++ { "angmsdaf", "⦭" },
++ { "angmsdag", "⦮" },
++ { "angmsdah", "⦯" },
++ { "angrtvb", "⊾" },
++ { "angrtvbd", "⦝" },
++ { "bbrk", "⎵" },
++ { "bemptyv", "⦰" },
++ { "beth", "ℶ" },
++ { "boxbox", "⧉" },
++ { "bprime", "‵" },
++ { "bsemi", "⁏" },
++ { "cemptyv", "⦲" },
++ { "cirE", "⧃" },
++ { "cirscir", "⧂" },
++ { "comp", "∁" },
++ { "daleth", "ℸ" },
++ { "demptyv", "⦱" },
++ { "ell", "ℓ" },
++ { "empty", "∅" },
++ { "emptyv", "∅" },
++ { "gimel", "ℷ" },
++ { "iiota", "℩" },
++ { "image", "ℑ" },
++ { "imath", "ı" },
++ { "jmath", "j" },
++ { "laemptyv", "⦴" },
++ { "lltri", "◺" },
++ { "lrtri", "⊿" },
++ { "mho", "℧" },
++ { "nang", "∠⃒" },
++ { "nexist", "∄" },
++ { "oS", "Ⓢ" },
++ { "planck", "ℏ" },
++ { "plankv", "ℏ" },
++ { "raemptyv", "⦳" },
++ { "range", "⦥" },
++ { "real", "ℜ" },
++ { "tbrk", "⎴" },
++ { "ultri", "◸" },
++ { "urtri", "◹" },
++ { "vzigzag", "⦚" },
++ { "weierp", "℘" },
++ { "apE", "⩰" },
++ { "ape", "≊" },
++ { "apid", "≋" },
++ { "asymp", "≈" },
++ { "Barv", "⫧" },
++ { "bcong", "≌" },
++ { "bepsi", "϶" },
++ { "bowtie", "⋈" },
++ { "bsim", "∽" },
++ { "bsime", "⋍" },
++ { "bsolhsub", "\⊂" },
++ { "bump", "≎" },
++ { "bumpE", "⪮" },
++ { "bumpe", "≏" },
++ { "cire", "≗" },
++ { "Colon", "∷" },
++ { "Colone", "⩴" },
++ { "colone", "≔" },
++ { "congdot", "⩭" },
++ { "csub", "⫏" },
++ { "csube", "⫑" },
++ { "csup", "⫐" },
++ { "csupe", "⫒" },
++ { "cuepr", "⋞" },
++ { "cuesc", "⋟" },
++ { "Dashv", "⫤" },
++ { "dashv", "⊣" },
++ { "easter", "⩮" },
++ { "ecir", "≖" },
++ { "ecolon", "≕" },
++ { "eDDot", "⩷" },
++ { "eDot", "≑" },
++ { "efDot", "≒" },
++ { "eg", "⪚" },
++ { "egs", "⪖" },
++ { "egsdot", "⪘" },
++ { "el", "⪙" },
++ { "els", "⪕" },
++ { "elsdot", "⪗" },
++ { "equest", "≟" },
++ { "equivDD", "⩸" },
++ { "erDot", "≓" },
++ { "esdot", "≐" },
++ { "Esim", "⩳" },
++ { "esim", "≂" },
++ { "fork", "⋔" },
++ { "forkv", "⫙" },
++ { "frown", "⌢" },
++ { "gap", "⪆" },
++ { "gE", "≧" },
++ { "gEl", "⪌" },
++ { "gel", "⋛" },
++ { "ges", "⩾" },
++ { "gescc", "⪩" },
++ { "gesdot", "⪀" },
++ { "gesdoto", "⪂" },
++ { "gesdotol", "⪄" },
++ { "gesl", "⋛︀" },
++ { "gesles", "⪔" },
++ { "Gg", "⋙" },
++ { "gl", "≷" },
++ { "gla", "⪥" },
++ { "glE", "⪒" },
++ { "glj", "⪤" },
++ { "gsim", "≳" },
++ { "gsime", "⪎" },
++ { "gsiml", "⪐" },
++ { "Gt", "≫" },
++ { "gtcc", "⪧" },
++ { "gtcir", "⩺" },
++ { "gtdot", "⋗" },
++ { "gtquest", "⩼" },
++ { "gtrarr", "⥸" },
++ { "homtht", "∻" },
++ { "lap", "⪅" },
++ { "lat", "⪫" },
++ { "late", "⪭" },
++ { "lates", "⪭︀" },
++ { "lE", "≦" },
++ { "lEg", "⪋" },
++ { "leg", "⋚" },
++ { "les", "⩽" },
++ { "lescc", "⪨" },
++ { "lesdot", "⩿" },
++ { "lesdoto", "⪁" },
++ { "lesdotor", "⪃" },
++ { "lesg", "⋚︀" },
++ { "lesges", "⪓" },
++ { "lg", "≶" },
++ { "lgE", "⪑" },
++ { "Ll", "⋘" },
++ { "lsim", "≲" },
++ { "lsime", "⪍" },
++ { "lsimg", "⪏" },
++ { "Lt", "≪" },
++ { "ltcc", "⪦" },
++ { "ltcir", "⩹" },
++ { "ltdot", "⋖" },
++ { "ltlarr", "⥶" },
++ { "ltquest", "⩻" },
++ { "ltrie", "⊴" },
++ { "mcomma", "⨩" },
++ { "mDDot", "∺" },
++ { "mid", "∣" },
++ { "mlcp", "⫛" },
++ { "models", "⊧" },
++ { "mstpos", "∾" },
++ { "Pr", "⪻" },
++ { "pr", "≺" },
++ { "prap", "⪷" },
++ { "prcue", "≼" },
++ { "prE", "⪳" },
++ { "pre", "⪯" },
++ { "prsim", "≾" },
++ { "prurel", "⊰" },
++ { "ratio", "∶" },
++ { "rtrie", "⊵" },
++ { "rtriltri", "⧎" },
++ { "Sc", "⪼" },
++ { "sc", "≻" },
++ { "scap", "⪸" },
++ { "sccue", "≽" },
++ { "scE", "⪴" },
++ { "sce", "⪰" },
++ { "scsim", "≿" },
++ { "sdote", "⩦" },
++ { "simg", "⪞" },
++ { "simgE", "⪠" },
++ { "siml", "⪝" },
++ { "simlE", "⪟" },
++ { "smid", "∣" },
++ { "smile", "⌣" },
++ { "smt", "⪪" },
++ { "smte", "⪬" },
++ { "smtes", "⪬︀" },
++ { "spar", "∥" },
++ { "sqsub", "⊏" },
++ { "sqsube", "⊑" },
++ { "sqsup", "⊐" },
++ { "sqsupe", "⊒" },
++ { "Sub", "⋐" },
++ { "subE", "⫅" },
++ { "subedot", "⫃" },
++ { "submult", "⫁" },
++ { "subplus", "⪿" },
++ { "subrarr", "⥹" },
++ { "subsim", "⫇" },
++ { "subsub", "⫕" },
++ { "subsup", "⫓" },
++ { "Sup", "⋑" },
++ { "supdsub", "⫘" },
++ { "supE", "⫆" },
++ { "supedot", "⫄" },
++ { "suphsol", "⊅" },
++ { "suphsub", "⫗" },
++ { "suplarr", "⥻" },
++ { "supmult", "⫂" },
++ { "supplus", "⫀" },
++ { "supsim", "⫈" },
++ { "supsub", "⫔" },
++ { "supsup", "⫖" },
++ { "thkap", "≈" },
++ { "topfork", "⫚" },
++ { "trie", "≜" },
++ { "twixt", "≬" },
++ { "Vbar", "⫫" },
++ { "vBar", "⫨" },
++ { "vBarv", "⫩" },
++ { "VDash", "⊫" },
++ { "Vdash", "⊩" },
++ { "vDash", "⊨" },
++ { "vdash", "⊢" },
++ { "Vdashl", "⫦" },
++ { "vltri", "⊲" },
++ { "vprop", "∝" },
++ { "vrtri", "⊳" },
++ { "Vvdash", "⊪" },
++ { "alpha", "α" },
++ { "beta", "β" },
++ { "chi", "χ" },
++ { "Delta", "Δ" },
++ { "delta", "δ" },
++ { "epsi", "ε" },
++ { "epsiv", "ɛ" },
++ { "eta", "η" },
++ { "Gamma", "Γ" },
++ { "gamma", "γ" },
++ { "Gammad", "Ϝ" },
++ { "gammad", "ϝ" },
++ { "iota", "ι" },
++ { "kappa", "κ" },
++ { "kappav", "ϰ" },
++ { "Lambda", "Λ" },
++ { "lambda", "λ" },
++ { "mu", "μ" },
++ { "nu", "ν" },
++ { "Omega", "Ω" },
++ { "omega", "ω" },
++ { "Phi", "Φ" },
++ { "phi", "ϕ" },
++ { "phiv", "φ" },
++ { "Pi", "Π" },
++ { "pi", "π" },
++ { "piv", "ϖ" },
++ { "Psi", "Ψ" },
++ { "psi", "ψ" },
++ { "rho", "ρ" },
++ { "rhov", "ϱ" },
++ { "Sigma", "Σ" },
++ { "sigma", "σ" },
++ { "sigmav", "ς" },
++ { "tau", "τ" },
++ { "Theta", "Θ" },
++ { "theta", "θ" },
++ { "thetav", "ϑ" },
++ { "Upsi", "ϒ" },
++ { "upsi", "υ" },
++ { "Xi", "Ξ" },
++ { "xi", "ξ" },
++ { "zeta", "ζ" },
++ { "Cfr", "ℭ" },
++ { "Hfr", "ℌ" },
++ { "Ifr", "ℑ" },
++ { "Rfr", "ℜ" },
++ { "Zfr", "ℨ" },
++ { "Copf", "ℂ" },
++ { "Hopf", "ℍ" },
++ { "Nopf", "ℕ" },
++ { "Popf", "ℙ" },
++ { "Qopf", "ℚ" },
++ { "Ropf", "ℝ" },
++ { "Zopf", "ℤ" },
++ { "Bscr", "ℬ" },
++ { "Escr", "ℰ" },
++ { "escr", "ℯ" },
++ { "Fscr", "ℱ" },
++ { "gscr", "ℊ" },
++ { "Hscr", "ℋ" },
++ { "Iscr", "ℐ" },
++ { "Lscr", "ℒ" },
++ { "Mscr", "ℳ" },
++ { "oscr", "ℴ" },
++ { "pscr", "𝓅" },
++ { "Rscr", "ℛ" },
++ { "acd", "∿" },
++ { "aleph", "ℵ" },
++ { "And", "⩓" },
++ { "and", "∧" },
++ { "andand", "⩕" },
++ { "andd", "⩜" },
++ { "andslope", "⩘" },
++ { "andv", "⩚" },
++ { "angrt", "∟" },
++ { "angsph", "∢" },
++ { "angst", "Å" },
++ { "ap", "≈" },
++ { "apacir", "⩯" },
++ { "awconint", "∳" },
++ { "awint", "⨑" },
++ { "becaus", "∵" },
++ { "bernou", "ℬ" },
++ { "bne", "=⃥" },
++ { "bnequiv", "≡⃥" },
++ { "bNot", "⫭" },
++ { "bnot", "⌐" },
++ { "bottom", "⊥" },
++ { "cap", "∩" },
++ { "Cconint", "∰" },
++ { "cirfnint", "⨐" },
++ { "compfn", "∘" },
++ { "cong", "≅" },
++ { "Conint", "∯" },
++ { "conint", "∮" },
++ { "ctdot", "⋯" },
++ { "cup", "∪" },
++ { "cwconint", "∲" },
++ { "cwint", "∱" },
++ { "cylcty", "⌭" },
++ { "disin", "⋲" },
++ { "Dot", "¨" },
++ { "DotDot", "⃜" },
++ { "dsol", "⧶" },
++ { "dtdot", "⋱" },
++ { "dwangle", "⦦" },
++ { "epar", "⋕" },
++ { "eparsl", "⧣" },
++ { "equiv", "≡" },
++ { "eqvparsl", "⧥" },
++ { "exist", "∃" },
++ { "fnof", "ƒ" },
++ { "forall", "∀" },
++ { "fpartint", "⨍" },
++ { "ge", "≥" },
++ { "hamilt", "ℋ" },
++ { "iff", "⇔" },
++ { "iinfin", "⧜" },
++ { "infin", "∞" },
++ { "Int", "∬" },
++ { "int", "∫" },
++ { "intlarhk", "⨗" },
++ { "isin", "∈" },
++ { "isindot", "⋵" },
++ { "isinE", "⋹" },
++ { "isins", "⋴" },
++ { "isinsv", "⋳" },
++ { "isinv", "∈" },
++ { "lagran", "ℒ" },
++ { "Lang", "《" },
++ { "lang", "〈" },
++ { "lArr", "⇐" },
++ { "lbbrk", "〔" },
++ { "le", "≤" },
++ { "loang", "〘" },
++ { "lobrk", "〚" },
++ { "lopar", "⦅" },
++ { "lowast", "∗" },
++ { "minus", "−" },
++ { "mnplus", "∓" },
++ { "nabla", "∇" },
++ { "ne", "≠" },
++ { "nedot", "≐̸" },
++ { "nhpar", "⫲" },
++ { "ni", "∋" },
++ { "nis", "⋼" },
++ { "nisd", "⋺" },
++ { "niv", "∋" },
++ { "Not", "⫬" },
++ { "notin", "∉" },
++ { "notindot", "⋵̸" },
++ { "notinva", "∉" },
++ { "notinvb", "⋷" },
++ { "notinvc", "⋶" },
++ { "notni", "∌" },
++ { "notniva", "∌" },
++ { "notnivb", "⋾" },
++ { "notnivc", "⋽" },
++ { "nparsl", "⫽⃥" },
++ { "npart", "∂̸" },
++ { "npolint", "⨔" },
++ { "nvinfin", "⧞" },
++ { "olcross", "⦻" },
++ { "Or", "⩔" },
++ { "or", "∨" },
++ { "ord", "⩝" },
++ { "order", "ℴ" },
++ { "oror", "⩖" },
++ { "orslope", "⩗" },
++ { "orv", "⩛" },
++ { "par", "∥" },
++ { "parsl", "⫽" },
++ { "part", "∂" },
++ { "permil", "‰" },
++ { "perp", "⊥" },
++ { "pertenk", "‱" },
++ { "phmmat", "ℳ" },
++ { "pointint", "⨕" },
++ { "Prime", "″" },
++ { "prime", "′" },
++ { "profalar", "⌮" },
++ { "profline", "⌒" },
++ { "profsurf", "⌓" },
++ { "prop", "∝" },
++ { "qint", "⨌" },
++ { "qprime", "⁗" },
++ { "quatint", "⨖" },
++ { "radic", "√" },
++ { "Rang", "》" },
++ { "rang", "〉" },
++ { "rArr", "⇒" },
++ { "rbbrk", "〕" },
++ { "roang", "〙" },
++ { "robrk", "〛" },
++ { "ropar", "⦆" },
++ { "rppolint", "⨒" },
++ { "scpolint", "⨓" },
++ { "sim", "∼" },
++ { "simdot", "⩪" },
++ { "sime", "≃" },
++ { "smeparsl", "⧤" },
++ { "square", "□" },
++ { "squarf", "▪" },
++ { "sub", "⊂" },
++ { "sube", "⊆" },
++ { "sup", "⊃" },
++ { "supe", "⊇" },
++ { "tdot", "⃛" },
++ { "there4", "∴" },
++ { "tint", "∭" },
++ { "top", "⊤" },
++ { "topbot", "⌶" },
++ { "topcir", "⫱" },
++ { "tprime", "‴" },
++ { "utdot", "⋰" },
++ { "uwangle", "⦧" },
++ { "vangrt", "⦜" },
++ { "veeeq", "≚" },
++ { "Verbar", "‖" },
++ { "wedgeq", "≙" },
++ { "xnis", "⋻" },
++ { "boxDL", "╗" },
++ { "boxDl", "╖" },
++ { "boxdL", "╕" },
++ { "boxdl", "┐" },
++ { "boxDR", "╔" },
++ { "boxDr", "╓" },
++ { "boxdR", "╒" },
++ { "boxdr", "┌" },
++ { "boxH", "═" },
++ { "boxh", "─" },
++ { "boxHD", "╦" },
++ { "boxHd", "╤" },
++ { "boxhD", "╥" },
++ { "boxhd", "┬" },
++ { "boxHU", "╩" },
++ { "boxHu", "╧" },
++ { "boxhU", "╨" },
++ { "boxhu", "┴" },
++ { "boxUL", "╝" },
++ { "boxUl", "╜" },
++ { "boxuL", "╛" },
++ { "boxul", "┘" },
++ { "boxUR", "╚" },
++ { "boxUr", "╙" },
++ { "boxuR", "╘" },
++ { "boxur", "└" },
++ { "boxV", "║" },
++ { "boxv", "│" },
++ { "boxVH", "╬" },
++ { "boxVh", "╫" },
++ { "boxvH", "╪" },
++ { "boxvh", "┼" },
++ { "boxVL", "╣" },
++ { "boxVl", "╢" },
++ { "boxvL", "╡" },
++ { "boxvl", "┤" },
++ { "boxVR", "╠" },
++ { "boxVr", "╟" },
++ { "boxvR", "╞" },
++ { "boxvr", "├" },
++ { "Acy", "А" },
++ { "acy", "а" },
++ { "Bcy", "Б" },
++ { "bcy", "б" },
++ { "CHcy", "Ч" },
++ { "chcy", "ч" },
++ { "Dcy", "Д" },
++ { "dcy", "д" },
++ { "Ecy", "Э" },
++ { "ecy", "э" },
++ { "Fcy", "Ф" },
++ { "fcy", "ф" },
++ { "Gcy", "Г" },
++ { "gcy", "г" },
++ { "HARDcy", "Ъ" },
++ { "hardcy", "ъ" },
++ { "Icy", "И" },
++ { "icy", "и" },
++ { "IEcy", "Е" },
++ { "iecy", "е" },
++ { "IOcy", "Ё" },
++ { "iocy", "ё" },
++ { "Jcy", "Й" },
++ { "jcy", "й" },
++ { "Kcy", "К" },
++ { "kcy", "к" },
++ { "KHcy", "Х" },
++ { "khcy", "х" },
++ { "Lcy", "Л" },
++ { "lcy", "л" },
++ { "Mcy", "М" },
++ { "mcy", "м" },
++ { "Ncy", "Н" },
++ { "ncy", "н" },
++ { "numero", "№" },
++ { "Ocy", "О" },
++ { "ocy", "о" },
++ { "Pcy", "П" },
++ { "pcy", "п" },
++ { "Rcy", "Р" },
++ { "rcy", "р" },
++ { "Scy", "С" },
++ { "scy", "с" },
++ { "SHCHcy", "Щ" },
++ { "shchcy", "щ" },
++ { "SHcy", "Ш" },
++ { "shcy", "ш" },
++ { "SOFTcy", "Ь" },
++ { "softcy", "ь" },
++ { "Tcy", "Т" },
++ { "tcy", "т" },
++ { "TScy", "Ц" },
++ { "tscy", "ц" },
++ { "Ucy", "У" },
++ { "ucy", "у" },
++ { "Vcy", "В" },
++ { "vcy", "в" },
++ { "YAcy", "Я" },
++ { "yacy", "я" },
++ { "Ycy", "Ы" },
++ { "ycy", "ы" },
++ { "YUcy", "Ю" },
++ { "yucy", "ю" },
++ { "Zcy", "З" },
++ { "zcy", "з" },
++ { "ZHcy", "Ж" },
++ { "zhcy", "ж" },
++ { "DJcy", "Ђ" },
++ { "djcy", "ђ" },
++ { "DScy", "Ѕ" },
++ { "dscy", "ѕ" },
++ { "DZcy", "Џ" },
++ { "dzcy", "џ" },
++ { "GJcy", "Ѓ" },
++ { "gjcy", "ѓ" },
++ { "Iukcy", "І" },
++ { "iukcy", "і" },
++ { "Jsercy", "Ј" },
++ { "jsercy", "ј" },
++ { "Jukcy", "Є" },
++ { "jukcy", "є" },
++ { "KJcy", "Ќ" },
++ { "kjcy", "ќ" },
++ { "LJcy", "Љ" },
++ { "ljcy", "љ" },
++ { "NJcy", "Њ" },
++ { "njcy", "њ" },
++ { "TSHcy", "Ћ" },
++ { "tshcy", "ћ" },
++ { "Ubrcy", "Ў" },
++ { "ubrcy", "ў" },
++ { "YIcy", "Ї" },
++ { "yicy", "ї" },
++ { "acute", "´" },
++ { "breve", "˘" },
++ { "caron", "ˇ" },
++ { "cedil", "¸" },
++ { "circ", "ˆ" },
++ { "dblac", "˝" },
++ { "die", "¨" },
++ { "dot", "˙" },
++ { "grave", "`" },
++ { "macr", "¯" },
++ { "ogon", "˛" },
++ { "ring", "˚" },
++ { "tilde", "˜" },
++ { "uml", "¨" },
++ { "Aacute", "Á" },
++ { "aacute", "á" },
++ { "Acirc", "Â" },
++ { "acirc", "â" },
++ { "AElig", "Æ" },
++ { "aelig", "æ" },
++ { "Agrave", "À" },
++ { "agrave", "à" },
++ { "Aring", "Å" },
++ { "aring", "å" },
++ { "Atilde", "Ã" },
++ { "atilde", "ã" },
++ { "Auml", "Ä" },
++ { "auml", "ä" },
++ { "Ccedil", "Ç" },
++ { "ccedil", "ç" },
++ { "Eacute", "É" },
++ { "eacute", "é" },
++ { "Ecirc", "Ê" },
++ { "ecirc", "ê" },
++ { "Egrave", "È" },
++ { "egrave", "è" },
++ { "ETH", "Ð" },
++ { "eth", "ð" },
++ { "Euml", "Ë" },
++ { "euml", "ë" },
++ { "Iacute", "Í" },
++ { "iacute", "í" },
++ { "Icirc", "Î" },
++ { "icirc", "î" },
++ { "Igrave", "Ì" },
++ { "igrave", "ì" },
++ { "Iuml", "Ï" },
++ { "iuml", "ï" },
++ { "Ntilde", "Ñ" },
++ { "ntilde", "ñ" },
++ { "Oacute", "Ó" },
++ { "oacute", "ó" },
++ { "Ocirc", "Ô" },
++ { "ocirc", "ô" },
++ { "Ograve", "Ò" },
++ { "ograve", "ò" },
++ { "Oslash", "Ø" },
++ { "oslash", "ø" },
++ { "Otilde", "Õ" },
++ { "otilde", "õ" },
++ { "Ouml", "Ö" },
++ { "ouml", "ö" },
++ { "szlig", "ß" },
++ { "THORN", "Þ" },
++ { "thorn", "þ" },
++ { "Uacute", "Ú" },
++ { "uacute", "ú" },
++ { "Ucirc", "Û" },
++ { "ucirc", "û" },
++ { "Ugrave", "Ù" },
++ { "ugrave", "ù" },
++ { "Uuml", "Ü" },
++ { "uuml", "ü" },
++ { "Yacute", "Ý" },
++ { "yacute", "ý" },
++ { "yuml", "ÿ" },
++ { "Abreve", "Ă" },
++ { "abreve", "ă" },
++ { "Amacr", "Ā" },
++ { "amacr", "ā" },
++ { "Aogon", "Ą" },
++ { "aogon", "ą" },
++ { "Cacute", "Ć" },
++ { "cacute", "ć" },
++ { "Ccaron", "Č" },
++ { "ccaron", "č" },
++ { "Ccirc", "Ĉ" },
++ { "ccirc", "ĉ" },
++ { "Cdot", "Ċ" },
++ { "cdot", "ċ" },
++ { "Dcaron", "Ď" },
++ { "dcaron", "ď" },
++ { "Dstrok", "Đ" },
++ { "dstrok", "đ" },
++ { "Ecaron", "Ě" },
++ { "ecaron", "ě" },
++ { "Edot", "Ė" },
++ { "edot", "ė" },
++ { "Emacr", "Ē" },
++ { "emacr", "ē" },
++ { "ENG", "Ŋ" },
++ { "eng", "ŋ" },
++ { "Eogon", "Ę" },
++ { "eogon", "ę" },
++ { "gacute", "ǵ" },
++ { "Gbreve", "Ğ" },
++ { "gbreve", "ğ" },
++ { "Gcedil", "Ģ" },
++ { "Gcirc", "Ĝ" },
++ { "gcirc", "ĝ" },
++ { "Gdot", "Ġ" },
++ { "gdot", "ġ" },
++ { "Hcirc", "Ĥ" },
++ { "hcirc", "ĥ" },
++ { "Hstrok", "Ħ" },
++ { "hstrok", "ħ" },
++ { "Idot", "İ" },
++ { "IJlig", "IJ" },
++ { "ijlig", "ij" },
++ { "Imacr", "Ī" },
++ { "imacr", "ī" },
++ { "inodot", "ı" },
++ { "Iogon", "Į" },
++ { "iogon", "į" },
++ { "Itilde", "Ĩ" },
++ { "itilde", "ĩ" },
++ { "Jcirc", "Ĵ" },
++ { "jcirc", "ĵ" },
++ { "Kcedil", "Ķ" },
++ { "kcedil", "ķ" },
++ { "kgreen", "ĸ" },
++ { "Lacute", "Ĺ" },
++ { "lacute", "ĺ" },
++ { "Lcaron", "Ľ" },
++ { "lcaron", "ľ" },
++ { "Lcedil", "Ļ" },
++ { "lcedil", "ļ" },
++ { "Lmidot", "Ŀ" },
++ { "lmidot", "ŀ" },
++ { "Lstrok", "Ł" },
++ { "lstrok", "ł" },
++ { "Nacute", "Ń" },
++ { "nacute", "ń" },
++ { "napos", "ʼn" },
++ { "Ncaron", "Ň" },
++ { "ncaron", "ň" },
++ { "Ncedil", "Ņ" },
++ { "ncedil", "ņ" },
++ { "Odblac", "Ő" },
++ { "odblac", "ő" },
++ { "OElig", "Œ" },
++ { "oelig", "œ" },
++ { "Omacr", "Ō" },
++ { "omacr", "ō" },
++ { "Racute", "Ŕ" },
++ { "racute", "ŕ" },
++ { "Rcaron", "Ř" },
++ { "rcaron", "ř" },
++ { "Rcedil", "Ŗ" },
++ { "rcedil", "ŗ" },
++ { "Sacute", "Ś" },
++ { "sacute", "ś" },
++ { "Scaron", "Š" },
++ { "scaron", "š" },
++ { "Scedil", "Ş" },
++ { "scedil", "ş" },
++ { "Scirc", "Ŝ" },
++ { "scirc", "ŝ" },
++ { "Tcaron", "Ť" },
++ { "tcaron", "ť" },
++ { "Tcedil", "Ţ" },
++ { "tcedil", "ţ" },
++ { "Tstrok", "Ŧ" },
++ { "tstrok", "ŧ" },
++ { "Ubreve", "Ŭ" },
++ { "ubreve", "ŭ" },
++ { "Udblac", "Ű" },
++ { "udblac", "ű" },
++ { "Umacr", "Ū" },
++ { "umacr", "ū" },
++ { "Uogon", "Ų" },
++ { "uogon", "ų" },
++ { "Uring", "Ů" },
++ { "uring", "ů" },
++ { "Utilde", "Ũ" },
++ { "utilde", "ũ" },
++ { "Wcirc", "Ŵ" },
++ { "wcirc", "ŵ" },
++ { "Ycirc", "Ŷ" },
++ { "ycirc", "ŷ" },
++ { "Yuml", "Ÿ" },
++ { "Zacute", "Ź" },
++ { "zacute", "ź" },
++ { "Zcaron", "Ž" },
++ { "zcaron", "ž" },
++ { "Zdot", "Ż" },
++ { "zdot", "ż" },
++ { "apos", "'" },
++ { "ast", "*" },
++ { "brvbar", "¦" },
++ { "bsol", "\" },
++ { "cent", "¢" },
++ { "colon", ":" },
++ { "comma", "," },
++ { "commat", "@" },
++ { "copy", "©" },
++ { "curren", "¤" },
++ { "darr", "↓" },
++ { "deg", "°" },
++ { "divide", "÷" },
++ { "dollar", "$" },
++ { "equals", "=" },
++ { "excl", "!" },
++ { "frac12", "½" },
++ { "frac14", "¼" },
++ { "frac18", "⅛" },
++ { "frac34", "¾" },
++ { "frac38", "⅜" },
++ { "frac58", "⅝" },
++ { "frac78", "⅞" },
++ { "gt", ">" },
++ { "half", "½" },
++ { "horbar", "―" },
++ { "hyphen", "‐" },
++ { "iexcl", "¡" },
++ { "iquest", "¿" },
++ { "laquo", "«" },
++ { "larr", "←" },
++ { "lcub", "{" },
++ { "ldquo", "“" },
++ { "lowbar", "_" },
++ { "lpar", "(" },
++ { "lsqb", "[" },
++ { "lsquo", "‘" },
++ { "lt", "<" },
++ { "micro", "µ" },
++ { "middot", "·" },
++ { "nbsp", " " },
++ { "not", "¬" },
++ { "num", "#" },
++ { "ohm", "Ω" },
++ { "ordf", "ª" },
++ { "ordm", "º" },
++ { "para", "¶" },
++ { "percnt", "%" },
++ { "period", "." },
++ { "plus", "+" },
++ { "plusmn", "±" },
++ { "pound", "£" },
++ { "quest", "?" },
++ { "quot", """ },
++ { "raquo", "»" },
++ { "rarr", "→" },
++ { "rcub", "}" },
++ { "rdquo", "”" },
++ { "reg", "®" },
++ { "rpar", ")" },
++ { "rsqb", "]" },
++ { "rsquo", "’" },
++ { "sect", "§" },
++ { "semi", ";" },
++ { "shy", "­" },
++ { "sol", "/" },
++ { "sung", "♪" },
++ { "sup1", "¹" },
++ { "sup2", "²" },
++ { "sup3", "³" },
++ { "times", "×" },
++ { "trade", "™" },
++ { "uarr", "↑" },
++ { "verbar", "|" },
++ { "yen", "¥" },
++ { "blank", "␣" },
++ { "blk12", "▒" },
++ { "blk14", "░" },
++ { "blk34", "▓" },
++ { "block", "█" },
++ { "bull", "•" },
++ { "caret", "⁁" },
++ { "check", "✓" },
++ { "cir", "○" },
++ { "clubs", "♣" },
++ { "copysr", "℗" },
++ { "cross", "✗" },
++ { "Dagger", "‡" },
++ { "dagger", "†" },
++ { "dash", "‐" },
++ { "diams", "♦" },
++ { "dlcrop", "⌍" },
++ { "drcrop", "⌌" },
++ { "dtri", "▿" },
++ { "dtrif", "▾" },
++ { "emsp", " " },
++ { "emsp13", " " },
++ { "emsp14", " " },
++ { "ensp", " " },
++ { "female", "♀" },
++ { "ffilig", "ffi" },
++ { "fflig", "ff" },
++ { "ffllig", "ffl" },
++ { "filig", "fi" },
++ { "flat", "♭" },
++ { "fllig", "fl" },
++ { "frac13", "⅓" },
++ { "frac15", "⅕" },
++ { "frac16", "⅙" },
++ { "frac23", "⅔" },
++ { "frac25", "⅖" },
++ { "frac35", "⅗" },
++ { "frac45", "⅘" },
++ { "frac56", "⅚" },
++ { "hairsp", " " },
++ { "hearts", "♥" },
++ { "hellip", "…" },
++ { "hybull", "⁃" },
++ { "incare", "℅" },
++ { "ldquor", "„" },
++ { "lhblk", "▄" },
++ { "loz", "◊" },
++ { "lozf", "⧫" },
++ { "lsquor", "‚" },
++ { "ltri", "◃" },
++ { "ltrif", "◂" },
++ { "male", "♂" },
++ { "malt", "✠" },
++ { "marker", "▮" },
++ { "mdash", "—" },
++ { "mldr", "…" },
++ { "natur", "♮" },
++ { "ndash", "–" },
++ { "nldr", "‥" },
++ { "numsp", " " },
++ { "phone", "☎" },
++ { "puncsp", " " },
++ { "rdquor", "”" },
++ { "rect", "▭" },
++ { "rsquor", "’" },
++ { "rtri", "▹" },
++ { "rtrif", "▸" },
++ { "rx", "℞" },
++ { "sext", "✶" },
++ { "sharp", "♯" },
++ { "spades", "♠" },
++ { "squ", "□" },
++ { "squf", "▪" },
++ { "star", "☆" },
++ { "starf", "★" },
++ { "target", "⌖" },
++ { "telrec", "⌕" },
++ { "thinsp", " " },
++ { "uhblk", "▀" },
++ { "ulcrop", "⌏" },
++ { "urcrop", "⌎" },
++ { "utri", "▵" },
++ { "utrif", "▴" },
++ { "vellip", "⋮" },
++ { "af", "⁡" },
++ { "asympeq", "≍" },
++ { "Cross", "⨯" },
++ { "DD", "ⅅ" },
++ { "dd", "ⅆ" },
++ { "DownArrowBar", "⤓" },
++ { "DownBreve", "̑" },
++ { "DownLeftRightVector", "⥐" },
++ { "DownLeftTeeVector", "⥞" },
++ { "DownLeftVectorBar", "⥖" },
++ { "DownRightTeeVector", "⥟" },
++ { "DownRightVectorBar", "⥗" },
++ { "ee", "ⅇ" },
++ { "EmptySmallSquare", "◻" },
++ { "EmptyVerySmallSquare", "▫" },
++ { "Equal", "⩵" },
++ { "FilledSmallSquare", "◼" },
++ { "FilledVerySmallSquare", "▪" },
++ { "GreaterGreater", "⪢" },
++ { "Hat", "^" },
++ { "HorizontalLine", "─" },
++ { "ic", "⁣" },
++ { "ii", "ⅈ" },
++ { "it", "⁢" },
++ { "larrb", "⇤" },
++ { "LeftDownTeeVector", "⥡" },
++ { "LeftDownVectorBar", "⥙" },
++ { "LeftRightVector", "⥎" },
++ { "LeftTeeVector", "⥚" },
++ { "LeftTriangleBar", "⧏" },
++ { "LeftUpDownVector", "⥑" },
++ { "LeftUpTeeVector", "⥠" },
++ { "LeftUpVectorBar", "⥘" },
++ { "LeftVectorBar", "⥒" },
++ { "LessLess", "⪡" },
++ { "mapstodown", "↧" },
++ { "mapstoleft", "↤" },
++ { "mapstoup", "↥" },
++ { "MediumSpace", " " },
++ { "nbump", "≎̸" },
++ { "nbumpe", "≏̸" },
++ { "nesim", "≂̸" },
++ { "NewLine", "
" },
++ { "NoBreak", "⁠" },
++ { "NotCupCap", "≭" },
++ { "NotHumpEqual", "≏̸" },
++ { "NotLeftTriangleBar", "⧏̸" },
++ { "NotNestedGreaterGreater", "⪢̸" },
++ { "NotNestedLessLess", "⪡̸" },
++ { "NotRightTriangleBar", "⧐̸" },
++ { "NotSquareSubset", "⊏̸" },
++ { "NotSquareSuperset", "⊐̸" },
++ { "NotSucceedsTilde", "≿̸" },
++ { "OverBar", "¯" },
++ { "OverBrace", "︷" },
++ { "OverBracket", "⎴" },
++ { "OverParenthesis", "︵" },
++ { "planckh", "ℎ" },
++ { "Product", "∏" },
++ { "rarrb", "⇥" },
++ { "RightDownTeeVector", "⥝" },
++ { "RightDownVectorBar", "⥕" },
++ { "RightTeeVector", "⥛" },
++ { "RightTriangleBar", "⧐" },
++ { "RightUpDownVector", "⥏" },
++ { "RightUpTeeVector", "⥜" },
++ { "RightUpVectorBar", "⥔" },
++ { "RightVectorBar", "⥓" },
++ { "RoundImplies", "⥰" },
++ { "RuleDelayed", "⧴" },
++ { "Tab", "	" },
++ { "ThickSpace", "   " },
++ { "UnderBar", "̲" },
++ { "UnderBrace", "︸" },
++ { "UnderBracket", "⎵" },
++ { "UnderParenthesis", "︶" },
++ { "UpArrowBar", "⤒" },
++ { "Upsilon", "Υ" },
++ { "VerticalLine", "|" },
++ { "VerticalSeparator", "❘" },
++ { "ZeroWidthSpace", "​" },
++ { "angle", "∠" },
++ { "ApplyFunction", "⁡" },
++ { "approx", "≈" },
++ { "approxeq", "≊" },
++ { "Assign", "≔" },
++ { "backcong", "≌" },
++ { "backepsilon", "϶" },
++ { "backprime", "‵" },
++ { "backsim", "∽" },
++ { "backsimeq", "⋍" },
++ { "Backslash", "∖" },
++ { "barwedge", "⌅" },
++ { "Because", "∵" },
++ { "because", "∵" },
++ { "Bernoullis", "ℬ" },
++ { "between", "≬" },
++ { "bigcap", "⋂" },
++ { "bigcirc", "◯" },
++ { "bigcup", "⋃" },
++ { "bigodot", "⨀" },
++ { "bigoplus", "⨁" },
++ { "bigotimes", "⨂" },
++ { "bigsqcup", "⨆" },
++ { "bigstar", "★" },
++ { "bigtriangledown", "▽" },
++ { "bigtriangleup", "△" },
++ { "biguplus", "⨄" },
++ { "bigvee", "⋁" },
++ { "bigwedge", "⋀" },
++ { "bkarow", "⤍" },
++ { "blacklozenge", "⧫" },
++ { "blacksquare", "▪" },
++ { "blacktriangle", "▴" },
++ { "blacktriangledown", "▾" },
++ { "blacktriangleleft", "◂" },
++ { "blacktriangleright", "▸" },
++ { "bot", "⊥" },
++ { "boxminus", "⊟" },
++ { "boxplus", "⊞" },
++ { "boxtimes", "⊠" },
++ { "Breve", "˘" },
++ { "bullet", "•" },
++ { "Bumpeq", "≎" },
++ { "bumpeq", "≏" },
++ { "CapitalDifferentialD", "ⅅ" },
++ { "Cayleys", "ℭ" },
++ { "Cedilla", "¸" },
++ { "CenterDot", "·" },
++ { "centerdot", "·" },
++ { "checkmark", "✓" },
++ { "circeq", "≗" },
++ { "circlearrowleft", "↺" },
++ { "circlearrowright", "↻" },
++ { "circledast", "⊛" },
++ { "circledcirc", "⊚" },
++ { "circleddash", "⊝" },
++ { "CircleDot", "⊙" },
++ { "circledR", "®" },
++ { "circledS", "Ⓢ" },
++ { "CircleMinus", "⊖" },
++ { "CirclePlus", "⊕" },
++ { "CircleTimes", "⊗" },
++ { "ClockwiseContourIntegral", "∲" },
++ { "CloseCurlyDoubleQuote", "”" },
++ { "CloseCurlyQuote", "’" },
++ { "clubsuit", "♣" },
++ { "coloneq", "≔" },
++ { "complement", "∁" },
++ { "complexes", "ℂ" },
++ { "Congruent", "≡" },
++ { "ContourIntegral", "∮" },
++ { "Coproduct", "∐" },
++ { "CounterClockwiseContourIntegral", "∳" },
++ { "CupCap", "≍" },
++ { "curlyeqprec", "⋞" },
++ { "curlyeqsucc", "⋟" },
++ { "curlyvee", "⋎" },
++ { "curlywedge", "⋏" },
++ { "curvearrowleft", "↶" },
++ { "curvearrowright", "↷" },
++ { "dbkarow", "⤏" },
++ { "ddagger", "‡" },
++ { "ddotseq", "⩷" },
++ { "Del", "∇" },
++ { "DiacriticalAcute", "´" },
++ { "DiacriticalDot", "˙" },
++ { "DiacriticalDoubleAcute", "˝" },
++ { "DiacriticalGrave", "`" },
++ { "DiacriticalTilde", "˜" },
++ { "Diamond", "⋄" },
++ { "diamond", "⋄" },
++ { "diamondsuit", "♦" },
++ { "DifferentialD", "ⅆ" },
++ { "digamma", "ϝ" },
++ { "div", "÷" },
++ { "divideontimes", "⋇" },
++ { "doteq", "≐" },
++ { "doteqdot", "≑" },
++ { "DotEqual", "≐" },
++ { "dotminus", "∸" },
++ { "dotplus", "∔" },
++ { "dotsquare", "⊡" },
++ { "doublebarwedge", "⌆" },
++ { "DoubleContourIntegral", "∯" },
++ { "DoubleDot", "¨" },
++ { "DoubleDownArrow", "⇓" },
++ { "DoubleLeftArrow", "⇐" },
++ { "DoubleLeftRightArrow", "⇔" },
++ { "DoubleLeftTee", "⫤" },
++ { "DoubleLongLeftArrow", "⟸" },
++ { "DoubleLongLeftRightArrow", "⟺" },
++ { "DoubleLongRightArrow", "⟹" },
++ { "DoubleRightArrow", "⇒" },
++ { "DoubleRightTee", "⊨" },
++ { "DoubleUpArrow", "⇑" },
++ { "DoubleUpDownArrow", "⇕" },
++ { "DoubleVerticalBar", "∥" },
++ { "DownArrow", "↓" },
++ { "Downarrow", "⇓" },
++ { "downarrow", "↓" },
++ { "DownArrowUpArrow", "⇵" },
++ { "downdownarrows", "⇊" },
++ { "downharpoonleft", "⇃" },
++ { "downharpoonright", "⇂" },
++ { "DownLeftVector", "↽" },
++ { "DownRightVector", "⇁" },
++ { "DownTee", "⊤" },
++ { "DownTeeArrow", "↧" },
++ { "drbkarow", "⤐" },
++ { "Element", "∈" },
++ { "emptyset", "∅" },
++ { "eqcirc", "≖" },
++ { "eqcolon", "≕" },
++ { "eqsim", "≂" },
++ { "eqslantgtr", "⪖" },
++ { "eqslantless", "⪕" },
++ { "EqualTilde", "≂" },
++ { "Equilibrium", "⇌" },
++ { "Exists", "∃" },
++ { "expectation", "ℰ" },
++ { "ExponentialE", "ⅇ" },
++ { "exponentiale", "ⅇ" },
++ { "fallingdotseq", "≒" },
++ { "ForAll", "∀" },
++ { "Fouriertrf", "ℱ" },
++ { "geq", "≥" },
++ { "geqq", "≧" },
++ { "geqslant", "⩾" },
++ { "gg", "≫" },
++ { "ggg", "⋙" },
++ { "gnapprox", "⪊" },
++ { "gneq", "⪈" },
++ { "gneqq", "≩" },
++ { "GreaterEqual", "≥" },
++ { "GreaterEqualLess", "⋛" },
++ { "GreaterFullEqual", "≧" },
++ { "GreaterLess", "≷" },
++ { "GreaterSlantEqual", "⩾" },
++ { "GreaterTilde", "≳" },
++ { "gtrapprox", "⪆" },
++ { "gtrdot", "⋗" },
++ { "gtreqless", "⋛" },
++ { "gtreqqless", "⪌" },
++ { "gtrless", "≷" },
++ { "gtrsim", "≳" },
++ { "gvertneqq", "≩︀" },
++ { "Hacek", "ˇ" },
++ { "hbar", "ℏ" },
++ { "heartsuit", "♥" },
++ { "HilbertSpace", "ℋ" },
++ { "hksearow", "⤥" },
++ { "hkswarow", "⤦" },
++ { "hookleftarrow", "↩" },
++ { "hookrightarrow", "↪" },
++ { "hslash", "ℏ" },
++ { "HumpDownHump", "≎" },
++ { "HumpEqual", "≏" },
++ { "iiiint", "⨌" },
++ { "iiint", "∭" },
++ { "Im", "ℑ" },
++ { "ImaginaryI", "ⅈ" },
++ { "imagline", "ℐ" },
++ { "imagpart", "ℑ" },
++ { "Implies", "⇒" },
++ { "in", "∈" },
++ { "integers", "ℤ" },
++ { "Integral", "∫" },
++ { "intercal", "⊺" },
++ { "Intersection", "⋂" },
++ { "intprod", "⨼" },
++ { "InvisibleComma", "⁣" },
++ { "InvisibleTimes", "⁢" },
++ { "langle", "〈" },
++ { "Laplacetrf", "ℒ" },
++ { "lbrace", "{" },
++ { "lbrack", "[" },
++ { "LeftAngleBracket", "〈" },
++ { "LeftArrow", "←" },
++ { "Leftarrow", "⇐" },
++ { "leftarrow", "←" },
++ { "LeftArrowBar", "⇤" },
++ { "LeftArrowRightArrow", "⇆" },
++ { "leftarrowtail", "↢" },
++ { "LeftCeiling", "⌈" },
++ { "LeftDoubleBracket", "〚" },
++ { "LeftDownVector", "⇃" },
++ { "LeftFloor", "⌊" },
++ { "leftharpoondown", "↽" },
++ { "leftharpoonup", "↼" },
++ { "leftleftarrows", "⇇" },
++ { "LeftRightArrow", "↔" },
++ { "Leftrightarrow", "⇔" },
++ { "leftrightarrow", "↔" },
++ { "leftrightarrows", "⇆" },
++ { "leftrightharpoons", "⇋" },
++ { "leftrightsquigarrow", "↭" },
++ { "LeftTee", "⊣" },
++ { "LeftTeeArrow", "↤" },
++ { "leftthreetimes", "⋋" },
++ { "LeftTriangle", "⊲" },
++ { "LeftTriangleEqual", "⊴" },
++ { "LeftUpVector", "↿" },
++ { "LeftVector", "↼" },
++ { "leq", "≤" },
++ { "leqq", "≦" },
++ { "leqslant", "⩽" },
++ { "lessapprox", "⪅" },
++ { "lessdot", "⋖" },
++ { "lesseqgtr", "⋚" },
++ { "lesseqqgtr", "⪋" },
++ { "LessEqualGreater", "⋚" },
++ { "LessFullEqual", "≦" },
++ { "LessGreater", "≶" },
++ { "lessgtr", "≶" },
++ { "lesssim", "≲" },
++ { "LessSlantEqual", "⩽" },
++ { "LessTilde", "≲" },
++ { "ll", "≪" },
++ { "llcorner", "⌞" },
++ { "Lleftarrow", "⇚" },
++ { "lmoustache", "⎰" },
++ { "lnapprox", "⪉" },
++ { "lneq", "⪇" },
++ { "lneqq", "≨" },
++ { "LongLeftArrow", "⟵" },
++ { "Longleftarrow", "⟸" },
++ { "longleftarrow", "⟵" },
++ { "LongLeftRightArrow", "⟷" },
++ { "Longleftrightarrow", "⟺" },
++ { "longleftrightarrow", "⟷" },
++ { "longmapsto", "⟼" },
++ { "LongRightArrow", "⟶" },
++ { "Longrightarrow", "⟹" },
++ { "longrightarrow", "⟶" },
++ { "looparrowleft", "↫" },
++ { "looparrowright", "↬" },
++ { "LowerLeftArrow", "↙" },
++ { "LowerRightArrow", "↘" },
++ { "lozenge", "◊" },
++ { "lrcorner", "⌟" },
++ { "Lsh", "↰" },
++ { "lvertneqq", "≨︀" },
++ { "maltese", "✠" },
++ { "mapsto", "↦" },
++ { "measuredangle", "∡" },
++ { "Mellintrf", "ℳ" },
++ { "MinusPlus", "∓" },
++ { "mp", "∓" },
++ { "multimap", "⊸" },
++ { "napprox", "≉" },
++ { "natural", "♮" },
++ { "naturals", "ℕ" },
++ { "nearrow", "↗" },
++ { "NegativeMediumSpace", "​" },
++ { "NegativeThickSpace", "​" },
++ { "NegativeThinSpace", "​" },
++ { "NegativeVeryThinSpace", "​" },
++ { "NestedGreaterGreater", "≫" },
++ { "NestedLessLess", "≪" },
++ { "nexists", "∄" },
++ { "ngeq", "≱" },
++ { "ngeqq", "≧̸" },
++ { "ngeqslant", "⩾̸" },
++ { "ngtr", "≯" },
++ { "nLeftarrow", "⇍" },
++ { "nleftarrow", "↚" },
++ { "nLeftrightarrow", "⇎" },
++ { "nleftrightarrow", "↮" },
++ { "nleq", "≰" },
++ { "nleqq", "≦̸" },
++ { "nleqslant", "⩽̸" },
++ { "nless", "≮" },
++ { "NonBreakingSpace", " " },
++ { "NotCongruent", "≢" },
++ { "NotDoubleVerticalBar", "∦" },
++ { "NotElement", "∉" },
++ { "NotEqual", "≠" },
++ { "NotEqualTilde", "≂̸" },
++ { "NotExists", "∄" },
++ { "NotGreater", "≯" },
++ { "NotGreaterEqual", "≱" },
++ { "NotGreaterFullEqual", "≦̸" },
++ { "NotGreaterGreater", "≫̸" },
++ { "NotGreaterLess", "≹" },
++ { "NotGreaterSlantEqual", "⩾̸" },
++ { "NotGreaterTilde", "≵" },
++ { "NotHumpDownHump", "≎̸" },
++ { "NotLeftTriangle", "⋪" },
++ { "NotLeftTriangleEqual", "⋬" },
++ { "NotLess", "≮" },
++ { "NotLessEqual", "≰" },
++ { "NotLessGreater", "≸" },
++ { "NotLessLess", "≪̸" },
++ { "NotLessSlantEqual", "⩽̸" },
++ { "NotLessTilde", "≴" },
++ { "NotPrecedes", "⊀" },
++ { "NotPrecedesEqual", "⪯̸" },
++ { "NotPrecedesSlantEqual", "⋠" },
++ { "NotReverseElement", "∌" },
++ { "NotRightTriangle", "⋫" },
++ { "NotRightTriangleEqual", "⋭" },
++ { "NotSquareSubsetEqual", "⋢" },
++ { "NotSquareSupersetEqual", "⋣" },
++ { "NotSubset", "⊂⃒" },
++ { "NotSubsetEqual", "⊈" },
++ { "NotSucceeds", "⊁" },
++ { "NotSucceedsEqual", "⪰̸" },
++ { "NotSucceedsSlantEqual", "⋡" },
++ { "NotSuperset", "⊃⃒" },
++ { "NotSupersetEqual", "⊉" },
++ { "NotTilde", "≁" },
++ { "NotTildeEqual", "≄" },
++ { "NotTildeFullEqual", "≇" },
++ { "NotTildeTilde", "≉" },
++ { "NotVerticalBar", "∤" },
++ { "nparallel", "∦" },
++ { "nprec", "⊀" },
++ { "npreceq", "⪯̸" },
++ { "nRightarrow", "⇏" },
++ { "nrightarrow", "↛" },
++ { "nshortmid", "∤" },
++ { "nshortparallel", "∦" },
++ { "nsimeq", "≄" },
++ { "nsubset", "⊂⃒" },
++ { "nsubseteq", "⊈" },
++ { "nsubseteqq", "⫅̸" },
++ { "nsucc", "⊁" },
++ { "nsucceq", "⪰̸" },
++ { "nsupset", "⊃⃒" },
++ { "nsupseteq", "⊉" },
++ { "nsupseteqq", "⫆̸" },
++ { "ntriangleleft", "⋪" },
++ { "ntrianglelefteq", "⋬" },
++ { "ntriangleright", "⋫" },
++ { "ntrianglerighteq", "⋭" },
++ { "nwarrow", "↖" },
++ { "oint", "∮" },
++ { "OpenCurlyDoubleQuote", "“" },
++ { "OpenCurlyQuote", "‘" },
++ { "orderof", "ℴ" },
++ { "parallel", "∥" },
++ { "PartialD", "∂" },
++ { "pitchfork", "⋔" },
++ { "PlusMinus", "±" },
++ { "pm", "±" },
++ { "Poincareplane", "ℌ" },
++ { "prec", "≺" },
++ { "precapprox", "⪷" },
++ { "preccurlyeq", "≼" },
++ { "Precedes", "≺" },
++ { "PrecedesEqual", "⪯" },
++ { "PrecedesSlantEqual", "≼" },
++ { "PrecedesTilde", "≾" },
++ { "preceq", "⪯" },
++ { "precnapprox", "⪹" },
++ { "precneqq", "⪵" },
++ { "precnsim", "⋨" },
++ { "precsim", "≾" },
++ { "primes", "ℙ" },
++ { "Proportion", "∷" },
++ { "Proportional", "∝" },
++ { "propto", "∝" },
++ { "quaternions", "ℍ" },
++ { "questeq", "≟" },
++ { "rangle", "〉" },
++ { "rationals", "ℚ" },
++ { "rbrace", "}" },
++ { "rbrack", "]" },
++ { "Re", "ℜ" },
++ { "realine", "ℛ" },
++ { "realpart", "ℜ" },
++ { "reals", "ℝ" },
++ { "ReverseElement", "∋" },
++ { "ReverseEquilibrium", "⇋" },
++ { "ReverseUpEquilibrium", "⥯" },
++ { "RightAngleBracket", "〉" },
++ { "RightArrow", "→" },
++ { "Rightarrow", "⇒" },
++ { "rightarrow", "→" },
++ { "RightArrowBar", "⇥" },
++ { "RightArrowLeftArrow", "⇄" },
++ { "rightarrowtail", "↣" },
++ { "RightCeiling", "⌉" },
++ { "RightDoubleBracket", "〛" },
++ { "RightDownVector", "⇂" },
++ { "RightFloor", "⌋" },
++ { "rightharpoondown", "⇁" },
++ { "rightharpoonup", "⇀" },
++ { "rightleftarrows", "⇄" },
++ { "rightleftharpoons", "⇌" },
++ { "rightrightarrows", "⇉" },
++ { "rightsquigarrow", "↝" },
++ { "RightTee", "⊢" },
++ { "RightTeeArrow", "↦" },
++ { "rightthreetimes", "⋌" },
++ { "RightTriangle", "⊳" },
++ { "RightTriangleEqual", "⊵" },
++ { "RightUpVector", "↾" },
++ { "RightVector", "⇀" },
++ { "risingdotseq", "≓" },
++ { "rmoustache", "⎱" },
++ { "Rrightarrow", "⇛" },
++ { "Rsh", "↱" },
++ { "searrow", "↘" },
++ { "setminus", "∖" },
++ { "ShortDownArrow", "↓" },
++ { "ShortLeftArrow", "←" },
++ { "shortmid", "∣" },
++ { "shortparallel", "∥" },
++ { "ShortRightArrow", "→" },
++ { "ShortUpArrow", "↑" },
++ { "simeq", "≃" },
++ { "SmallCircle", "∘" },
++ { "smallsetminus", "∖" },
++ { "spadesuit", "♠" },
++ { "Sqrt", "√" },
++ { "sqsubset", "⊏" },
++ { "sqsubseteq", "⊑" },
++ { "sqsupset", "⊐" },
++ { "sqsupseteq", "⊒" },
++ { "Square", "□" },
++ { "SquareIntersection", "⊓" },
++ { "SquareSubset", "⊏" },
++ { "SquareSubsetEqual", "⊑" },
++ { "SquareSuperset", "⊐" },
++ { "SquareSupersetEqual", "⊒" },
++ { "SquareUnion", "⊔" },
++ { "Star", "⋆" },
++ { "straightepsilon", "ε" },
++ { "straightphi", "ϕ" },
++ { "Subset", "⋐" },
++ { "subset", "⊂" },
++ { "subseteq", "⊆" },
++ { "subseteqq", "⫅" },
++ { "SubsetEqual", "⊆" },
++ { "subsetneq", "⊊" },
++ { "subsetneqq", "⫋" },
++ { "succ", "≻" },
++ { "succapprox", "⪸" },
++ { "succcurlyeq", "≽" },
++ { "Succeeds", "≻" },
++ { "SucceedsEqual", "⪰" },
++ { "SucceedsSlantEqual", "≽" },
++ { "SucceedsTilde", "≿" },
++ { "succeq", "⪰" },
++ { "succnapprox", "⪺" },
++ { "succneqq", "⪶" },
++ { "succnsim", "⋩" },
++ { "succsim", "≿" },
++ { "SuchThat", "∋" },
++ { "Sum", "∑" },
++ { "Superset", "⊃" },
++ { "SupersetEqual", "⊇" },
++ { "Supset", "⋑" },
++ { "supset", "⊃" },
++ { "supseteq", "⊇" },
++ { "supseteqq", "⫆" },
++ { "supsetneq", "⊋" },
++ { "supsetneqq", "⫌" },
++ { "swarrow", "↙" },
++ { "Therefore", "∴" },
++ { "therefore", "∴" },
++ { "thickapprox", "≈" },
++ { "thicksim", "∼" },
++ { "ThinSpace", " " },
++ { "Tilde", "∼" },
++ { "TildeEqual", "≃" },
++ { "TildeFullEqual", "≅" },
++ { "TildeTilde", "≈" },
++ { "toea", "⤨" },
++ { "tosa", "⤩" },
++ { "triangle", "▵" },
++ { "triangledown", "▿" },
++ { "triangleleft", "◃" },
++ { "trianglelefteq", "⊴" },
++ { "triangleq", "≜" },
++ { "triangleright", "▹" },
++ { "trianglerighteq", "⊵" },
++ { "TripleDot", "⃛" },
++ { "twoheadleftarrow", "↞" },
++ { "twoheadrightarrow", "↠" },
++ { "ulcorner", "⌜" },
++ { "Union", "⋃" },
++ { "UnionPlus", "⊎" },
++ { "UpArrow", "↑" },
++ { "Uparrow", "⇑" },
++ { "uparrow", "↑" },
++ { "UpArrowDownArrow", "⇅" },
++ { "UpDownArrow", "↕" },
++ { "Updownarrow", "⇕" },
++ { "updownarrow", "↕" },
++ { "UpEquilibrium", "⥮" },
++ { "upharpoonleft", "↿" },
++ { "upharpoonright", "↾" },
++ { "UpperLeftArrow", "↖" },
++ { "UpperRightArrow", "↗" },
++ { "upsilon", "υ" },
++ { "UpTee", "⊥" },
++ { "UpTeeArrow", "↥" },
++ { "upuparrows", "⇈" },
++ { "urcorner", "⌝" },
++ { "varepsilon", "ɛ" },
++ { "varkappa", "ϰ" },
++ { "varnothing", "∅" },
++ { "varphi", "φ" },
++ { "varpi", "ϖ" },
++ { "varpropto", "∝" },
++ { "varrho", "ϱ" },
++ { "varsigma", "ς" },
++ { "varsubsetneq", "⊊︀" },
++ { "varsubsetneqq", "⫋︀" },
++ { "varsupsetneq", "⊋︀" },
++ { "varsupsetneqq", "⫌︀" },
++ { "vartheta", "ϑ" },
++ { "vartriangleleft", "⊲" },
++ { "vartriangleright", "⊳" },
++ { "Vee", "⋁" },
++ { "vee", "∨" },
++ { "Vert", "‖" },
++ { "vert", "|" },
++ { "VerticalBar", "∣" },
++ { "VerticalTilde", "≀" },
++ { "VeryThinSpace", " " },
++ { "Wedge", "⋀" },
++ { "wedge", "∧" },
++ { "wp", "℘" },
++ { "wr", "≀" },
++ { "zeetrf", "ℨ" },
++ { 0, 0 }
++};
++
++// *******************************************************************
++// MmlDocument
++// *******************************************************************
++
++QString MmlDocument::fontName(QtMmlWidget::MmlFont type) const
++{
++ switch (type) {
++ case QtMmlWidget::NormalFont:
++ return m_normal_font_name;
++ case QtMmlWidget::FrakturFont:
++ return m_fraktur_font_name;
++ case QtMmlWidget::SansSerifFont:
++ return m_sans_serif_font_name;
++ case QtMmlWidget::ScriptFont:
++ return m_script_font_name;
++ case QtMmlWidget::MonospaceFont:
++ return m_monospace_font_name;
++ case QtMmlWidget::DoublestruckFont:
++ return m_doublestruck_font_name;
++ };
++
++ return QString::null;
++}
++
++void MmlDocument::setFontName(QtMmlWidget::MmlFont type, const QString &name)
++{
++ switch (type) {
++ case QtMmlWidget::NormalFont:
++ m_normal_font_name = name;
++ break;
++ case QtMmlWidget::FrakturFont:
++ m_fraktur_font_name = name;
++ break;
++ case QtMmlWidget::SansSerifFont:
++ m_sans_serif_font_name = name;
++ break;
++ case QtMmlWidget::ScriptFont:
++ m_script_font_name = name;
++ break;
++ case QtMmlWidget::MonospaceFont:
++ m_monospace_font_name = name;
++ break;
++ case QtMmlWidget::DoublestruckFont:
++ m_doublestruck_font_name = name;
++ break;
++ };
++}
++
++Mml::NodeType domToMmlNodeType(const QDomNode &dom_node)
++{
++ Mml::NodeType mml_type = Mml::NoNode;
++
++ switch (dom_node.nodeType()) {
++ case QDomNode::ElementNode: {
++ QString tag = dom_node.nodeName();
++ const NodeSpec *spec = mmlFindNodeSpec(tag);
++
++ // treat urecognised tags as mrow
++ if (spec == 0)
++ mml_type = Mml::UnknownNode;
++ else
++ mml_type = spec->type;
++
++ break;
++ }
++ case QDomNode::TextNode:
++ mml_type = Mml::TextNode;
++ break;
++
++ case QDomNode::DocumentNode:
++ mml_type = Mml::MrowNode;
++ break;
++
++ case QDomNode::EntityReferenceNode:
++// qWarning("EntityReferenceNode: name=\"" + dom_node.nodeName() + "\" value=\"" + dom_node.nodeValue() + "\"");
++ break;
++
++ case QDomNode::AttributeNode:
++ case QDomNode::CDATASectionNode:
++ case QDomNode::EntityNode:
++ case QDomNode::ProcessingInstructionNode:
++ case QDomNode::CommentNode:
++ case QDomNode::DocumentTypeNode:
++ case QDomNode::DocumentFragmentNode:
++ case QDomNode::NotationNode:
++ case QDomNode::BaseNode:
++ case QDomNode::CharacterDataNode:
++ break;
++ }
++
++ return mml_type;
++}
++
++
++MmlDocument::MmlDocument()
++{
++ m_root_node = 0;
++
++ // Some defaults which happen to work on my computer,
++ // but probably won't work on other's
++#if defined(Q_WS_WIN)
++ m_normal_font_name = "Times New Roman";
++#else
++ m_normal_font_name = "Century Schoolbook L";
++#endif
++ m_fraktur_font_name = "Fraktur";
++ m_sans_serif_font_name = "Luxi Sans";
++ m_script_font_name = "Urw Chancery L";
++ m_monospace_font_name = "Luxi Mono";
++ m_doublestruck_font_name = "Doublestruck";
++ m_base_font_point_size = 16;
++ m_foreground_color = Qt::black;
++ m_background_color = Qt::white;
++}
++
++MmlDocument::~MmlDocument()
++{
++ clear();
++}
++
++void MmlDocument::clear()
++{
++ delete m_root_node;
++ m_root_node = 0;
++}
++
++void MmlDocument::dump() const
++{
++ if (m_root_node == 0)
++ return;
++
++ QString indent;
++ _dump(m_root_node, indent);
++}
++
++void MmlDocument::_dump(const MmlNode *node, QString &indent) const
++{
++ if (node == 0) return;
++
++ qWarning((indent + node->toStr()).toLatin1().data());
++
++ indent += " ";
++ const MmlNode *child = node->firstChild();
++ for (; child != 0; child = child->nextSibling())
++ _dump(child, indent);
++ indent.truncate(indent.length() - 2);
++}
++
++bool MmlDocument::setContent(QString text, QString *errorMsg,
++ int *errorLine, int *errorColumn)
++{
++ clear();
++
++ QString prefix = "<?xml version=\"2.0\"?>\n";
++ prefix.append(entityDeclarations());
++
++ uint prefix_lines = 0;
++ for (int i = 0; i < prefix.length(); ++i) {
++ if (prefix.at(i) == '\n')
++ ++prefix_lines;
++ }
++
++ QDomDocument dom;
++ if (!dom.setContent(prefix + text, false, errorMsg, errorLine, errorColumn)) {
++ if (errorLine != 0)
++ *errorLine -= prefix_lines;
++ return false;
++ }
++
++ // we don't have access to line info from now on
++ if (errorLine != 0) *errorLine = -1;
++ if (errorColumn != 0) *errorColumn = -1;
++
++ bool ok;
++ MmlNode *root_node = domToMml(dom, &ok, errorMsg);
++ if (!ok)
++ return false;
++
++ if (root_node == 0) {
++ if (errorMsg != 0)
++ *errorMsg = "empty document";
++ return false;
++ }
++
++ insertChild(0, root_node, 0);
++ layout();
++
++/* QFile of("/tmp/dump.xml");
++ of.open(IO_WriteOnly);
++ QTextStream os(&of);
++ os.setEncoding(QTextStream::UnicodeUTF8);
++ os << dom.toString(); */
++
++ return true;
++}
++
++void MmlDocument::layout()
++{
++ if (m_root_node == 0)
++ return;
++
++ m_root_node->layout();
++ m_root_node->stretch();
++// dump();
++}
++
++bool MmlDocument::insertChild(MmlNode *parent, MmlNode *new_node,
++ QString *errorMsg)
++{
++ if (new_node == 0)
++ return true;
++
++ Q_ASSERT(new_node->parent() == 0
++ && new_node->nextSibling() == 0
++ && new_node->previousSibling() == 0);
++
++ if (parent != 0) {
++ if (!mmlCheckChildType(parent->nodeType(), new_node->nodeType(), errorMsg))
++ return false;
++ }
++
++ if (parent == 0) {
++ if (m_root_node == 0)
++ m_root_node = new_node;
++ else {
++ MmlNode *n = m_root_node->lastSibling();
++ n->m_next_sibling = new_node;
++ new_node->m_previous_sibling = n;
++ }
++ }
++ else {
++ new_node->m_parent = parent;
++ if (parent->hasChildNodes()) {
++ MmlNode *n = parent->firstChild()->lastSibling();
++ n->m_next_sibling = new_node;
++ new_node->m_previous_sibling = n;
++ }
++ else parent->m_first_child = new_node;
++ }
++
++ return true;
++}
++
++MmlNode *MmlDocument::createNode(NodeType type,
++ const MmlAttributeMap &mml_attr,
++ const QString &mml_value,
++ QString *errorMsg)
++{
++ Q_ASSERT(type != NoNode);
++
++ MmlNode *mml_node = 0;
++
++ if (!mmlCheckAttributes(type, mml_attr, errorMsg))
++ return 0;
++
++ switch (type) {
++ case MiNode:
++ mml_node = new MmlMiNode(this, mml_attr);
++ break;
++ case MnNode:
++ mml_node = new MmlMnNode(this, mml_attr);
++ break;
++ case MfracNode:
++ mml_node = new MmlMfracNode(this, mml_attr);
++ break;
++ case MrowNode:
++ mml_node = new MmlMrowNode(this, mml_attr);
++ break;
++ case MsqrtNode:
++ mml_node = new MmlMsqrtNode(this, mml_attr);
++ break;
++ case MrootNode:
++ mml_node = new MmlMrootNode(this, mml_attr);
++ break;
++ case MsupNode:
++ mml_node = new MmlMsupNode(this, mml_attr);
++ break;
++ case MsubNode:
++ mml_node = new MmlMsubNode(this, mml_attr);
++ break;
++ case MsubsupNode:
++ mml_node = new MmlMsubsupNode(this, mml_attr);
++ break;
++ case MoNode:
++ mml_node = new MmlMoNode(this, mml_attr);
++ break;
++ case MstyleNode:
++ mml_node = new MmlMstyleNode(this, mml_attr);
++ break;
++ case TextNode:
++ mml_node = new MmlTextNode(mml_value, this);
++ break;
++ case MphantomNode:
++ mml_node = new MmlMphantomNode(this, mml_attr);
++ break;
++ case MfencedNode:
++ mml_node = new MmlMfencedNode(this, mml_attr);
++ break;
++ case MtableNode:
++ mml_node = new MmlMtableNode(this, mml_attr);
++ break;
++ case MtrNode:
++ mml_node = new MmlMtrNode(this, mml_attr);
++ break;
++ case MtdNode:
++ mml_node = new MmlMtdNode(this, mml_attr);
++ break;
++ case MoverNode:
++ mml_node = new MmlMoverNode(this, mml_attr);
++ break;
++ case MunderNode:
++ mml_node = new MmlMunderNode(this, mml_attr);
++ break;
++ case MunderoverNode:
++ mml_node = new MmlMunderoverNode(this, mml_attr);
++ break;
++ case MalignMarkNode:
++ mml_node = new MmlMalignMarkNode(this);
++ break;
++ case MerrorNode:
++ mml_node = new MmlMerrorNode(this, mml_attr);
++ break;
++ case MtextNode:
++ mml_node = new MmlMtextNode(this, mml_attr);
++ break;
++ case MpaddedNode:
++ mml_node = new MmlMpaddedNode(this, mml_attr);
++ break;
++ case MspaceNode:
++ mml_node = new MmlMspaceNode(this, mml_attr);
++ break;
++ case UnknownNode:
++ mml_node = new MmlUnknownNode(this, mml_attr);
++ break;
++ case NoNode:
++ mml_node = 0;
++ break;
++ }
++
++ return mml_node;
++}
++
++void MmlDocument::insertOperator(MmlNode *node, const QString &text)
++{
++ MmlNode *text_node = createNode(TextNode, MmlAttributeMap(), text, 0);
++ MmlNode *mo_node = createNode(MoNode, MmlAttributeMap(), QString::null, 0);
++
++ bool ok = insertChild(node, mo_node, 0);
++ Q_ASSERT( ok );
++ ok = insertChild(mo_node, text_node, 0);
++ Q_ASSERT( ok );
++}
++
++MmlNode *MmlDocument::domToMml(const QDomNode &dom_node, bool *ok, QString *errorMsg)
++{
++ // create the node
++
++ Q_ASSERT(ok != 0);
++
++ NodeType mml_type = domToMmlNodeType(dom_node);
++
++ if (mml_type == NoNode) {
++ *ok = true;
++ return 0;
++ }
++
++ QDomNamedNodeMap dom_attr = dom_node.attributes();
++ MmlAttributeMap mml_attr;
++ for (unsigned i = 0; i < dom_attr.length(); ++i) {
++ QDomNode attr_node = dom_attr.item(i);
++ Q_ASSERT(!attr_node.nodeName().isNull());
++ Q_ASSERT(!attr_node.nodeValue().isNull());
++ mml_attr[attr_node.nodeName()] = attr_node.nodeValue();
++ }
++
++ QString mml_value;
++ if (mml_type == TextNode)
++ mml_value = dom_node.nodeValue();
++ MmlNode *mml_node = createNode(mml_type, mml_attr, mml_value, errorMsg);
++ if (mml_node == 0) {
++ *ok = false;
++ return 0;
++ }
++
++ // create the node's children according to the child_spec
++
++ const NodeSpec *spec = mmlFindNodeSpec(mml_type);
++ QDomNodeList dom_child_list = dom_node.childNodes();
++ int child_cnt = dom_child_list.count();
++ MmlNode *mml_child = 0;
++
++ QString separator_list;
++ if (mml_type == MfencedNode)
++ separator_list = mml_node->explicitAttribute("separators", ",");
++
++ switch (spec->child_spec) {
++ case NodeSpec::ChildIgnore:
++ break;
++
++ case NodeSpec::ImplicitMrow:
++
++ if (child_cnt > 0) {
++ mml_child = createImplicitMrowNode(dom_node, ok, errorMsg);
++ if (!*ok) {
++ delete mml_node;
++ return 0;
++ }
++
++ if (!insertChild(mml_node, mml_child, errorMsg)) {
++ delete mml_node;
++ delete mml_child;
++ *ok = false;
++ return 0;
++ }
++ }
++
++ break;
++
++ default:
++ // exact ammount of children specified - check...
++ if (spec->child_spec != child_cnt) {
++ if (errorMsg != 0)
++ *errorMsg = QString("element ")
++ + spec->tag
++ + " requires exactly "
++ + QString::number(spec->child_spec)
++ + " arguments, got "
++ + QString::number(child_cnt);
++ delete mml_node;
++ *ok = false;
++ return 0;
++ }
++
++ // ...and continue just as in ChildAny
++
++ case NodeSpec::ChildAny:
++ if (mml_type == MfencedNode)
++ insertOperator(mml_node, mml_node->explicitAttribute("open", "("));
++
++ for (int i = 0; i < child_cnt; ++i) {
++ QDomNode dom_child = dom_child_list.item(i);
++
++ MmlNode *mml_child = domToMml(dom_child, ok, errorMsg);
++ if (!*ok) {
++ delete mml_node;
++ return 0;
++ }
++
++ if (mml_type == MtableNode && mml_child->nodeType() != MtrNode) {
++ MmlNode *mtr_node = createNode(MtrNode, MmlAttributeMap(), QString::null, 0);
++ insertChild(mml_node, mtr_node, 0);
++ if (!insertChild(mtr_node, mml_child, errorMsg)) {
++ delete mml_node;
++ delete mml_child;
++ *ok = false;
++ return 0;
++ }
++ }
++ else if (mml_type == MtrNode && mml_child->nodeType() != MtdNode) {
++ MmlNode *mtd_node = createNode(MtdNode, MmlAttributeMap(), QString::null, 0);
++ insertChild(mml_node, mtd_node, 0);
++ if (!insertChild(mtd_node, mml_child, errorMsg)) {
++ delete mml_node;
++ delete mml_child;
++ *ok = false;
++ return 0;
++ }
++ }
++ else {
++ if (!insertChild(mml_node, mml_child, errorMsg)) {
++ delete mml_node;
++ delete mml_child;
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (i < child_cnt - 1 && mml_type == MfencedNode && !separator_list.isEmpty()) {
++ QChar separator;
++ if (i >= (int)separator_list.length())
++ separator = separator_list.at(separator_list.length() - 1);
++ else
++ separator = separator_list[i];
++ insertOperator(mml_node, QString(separator));
++ }
++ }
++
++ if (mml_type == MfencedNode)
++ insertOperator(mml_node, mml_node->explicitAttribute("close", ")"));
++
++ break;
++ }
++
++ *ok = true;
++ return mml_node;
++}
++
++MmlNode *MmlDocument::createImplicitMrowNode(const QDomNode &dom_node, bool *ok,
++ QString *errorMsg)
++{
++ QDomNodeList dom_child_list = dom_node.childNodes();
++ int child_cnt = dom_child_list.count();
++
++ if (child_cnt == 0) {
++ *ok = true;
++ return 0;
++ }
++
++ if (child_cnt == 1)
++ return domToMml(dom_child_list.item(0), ok, errorMsg);
++
++ MmlNode *mml_node = createNode(MrowNode, MmlAttributeMap(),
++ QString::null, errorMsg);
++ Q_ASSERT(mml_node != 0); // there is no reason in heaven or hell for this to fail
++
++ for (int i = 0; i < child_cnt; ++i) {
++ QDomNode dom_child = dom_child_list.item(i);
++
++ MmlNode *mml_child = domToMml(dom_child, ok, errorMsg);
++ if (!*ok) {
++ delete mml_node;
++ return 0;
++ }
++
++ if (!insertChild(mml_node, mml_child, errorMsg)) {
++ delete mml_node;
++ delete mml_child;
++ *ok = false;
++ return 0;
++ }
++ }
++
++ return mml_node;
++}
++
++void MmlDocument::paint(QPainter *p, const QPoint &pos) const
++{
++ if (m_root_node == 0)
++ return;
++
++/* p->save();
++ p->setPen(Qt::blue);
++ p->drawLine(pos.x() - 5, pos.y(), pos.x() + 5, pos.y());
++ p->drawLine(pos.x(), pos.y() - 5, pos.x(), pos.y() + 5);
++ p->restore(); */
++
++ QRect mr = m_root_node->myRect();
++ m_root_node->setRelOrigin(pos - mr.topLeft());
++ m_root_node->paint(p);
++}
++
++QSize MmlDocument::size() const
++{
++ if (m_root_node == 0)
++ return QSize(0, 0);
++ return m_root_node->deviceRect().size();
++}
++
++
++
++
++// *******************************************************************
++// MmlNode
++// *******************************************************************
++
++
++MmlNode::MmlNode(NodeType type, MmlDocument *document, const MmlAttributeMap &attribute_map)
++{
++ m_parent = 0;
++ m_first_child = 0;
++ m_next_sibling = 0;
++ m_previous_sibling = 0;
++
++ m_node_type = type;
++ m_document = document;
++ m_attribute_map = attribute_map;
++
++ m_my_rect = m_parent_rect = QRect(0, 0, 0, 0);
++ m_rel_origin = QPoint(0, 0);
++ m_stretched = false;
++}
++
++MmlNode::~MmlNode()
++{
++ MmlNode *n = firstChild();
++ while (n != 0) {
++ MmlNode *tmp = n->nextSibling();
++ delete n;
++ n = tmp;
++ }
++}
++
++static QString rectToStr(const QRect &rect)
++{
++ return QString("[(%1, %2), %3x%4]")
++ .arg(rect.x())
++ .arg(rect.y())
++ .arg(rect.width())
++ .arg(rect.height());
++}
++
++QString MmlNode::toStr() const
++{
++ const NodeSpec *spec = mmlFindNodeSpec(nodeType());
++ Q_ASSERT(spec != 0);
++
++ return QString("%1 %2 mr=%3 pr=%4 dr=%5 ro=(%7, %8) str=%9")
++ .arg(spec->type_str)
++ .arg((unsigned long)this, 0, 16)
++ .arg(rectToStr(myRect()))
++ .arg(rectToStr(parentRect()))
++ .arg(rectToStr(deviceRect()))
++ .arg(m_rel_origin.x())
++ .arg(m_rel_origin.y())
++ .arg((int)isStretched());
++}
++
++int MmlNode::interpretSpacing(const QString &value, bool *ok) const
++{
++ return ::interpretSpacing(value, em(), ex(), ok);
++}
++
++int MmlNode::basePos() const
++{
++ QFontMetrics fm(font());
++ return fm.strikeOutPos();
++}
++
++int MmlNode::underlinePos() const
++{
++ QFontMetrics fm(font());
++ return basePos() + fm.underlinePos();
++}
++int MmlNode::overlinePos() const
++{
++ QFontMetrics fm(font());
++ return basePos() - fm.overlinePos();
++}
++
++MmlNode *MmlNode::lastSibling() const
++{
++ const MmlNode *n = this;
++ while (!n->isLastSibling())
++ n = n->nextSibling();
++ return const_cast<MmlNode*>(n);
++}
++
++MmlNode *MmlNode::firstSibling() const
++{
++ const MmlNode *n = this;
++ while (!n->isFirstSibling())
++ n = n->previousSibling();
++ return const_cast<MmlNode*>(n);
++}
++
++int MmlNode::em() const
++{
++ return QFontMetrics(font()).boundingRect('m').width();
++}
++
++int MmlNode::ex() const
++{
++ return QFontMetrics(font()).boundingRect('x').height();
++}
++
++int MmlNode::scriptlevel(const MmlNode *) const
++{
++ int parent_sl;
++ const MmlNode *p = parent();
++ if (p == 0)
++ parent_sl = 0;
++ else
++ parent_sl = p->scriptlevel(this);
++
++ QString expl_sl_str = explicitAttribute("scriptlevel");
++ if (expl_sl_str.isNull())
++ return parent_sl;
++
++ if (expl_sl_str.startsWith("+") || expl_sl_str.startsWith("-")) {
++ bool ok;
++ int expl_sl = expl_sl_str.toInt(&ok);
++ if (ok) {
++ return parent_sl + expl_sl;
++ }
++ else {
++ qWarning(("MmlNode::scriptlevel(): bad value " + expl_sl_str).toLatin1().data());
++ return parent_sl;
++ }
++ }
++
++ bool ok;
++ int expl_sl = expl_sl_str.toInt(&ok);
++ if (ok)
++ return expl_sl;
++
++
++ if (expl_sl_str == "+")
++ return parent_sl + 1;
++ else if (expl_sl_str == "-")
++ return parent_sl - 1;
++ else {
++ qWarning(("MmlNode::scriptlevel(): could not parse value: \"" + expl_sl_str + "\"").toLatin1().data());
++ return parent_sl;
++ }
++}
++
++QPoint MmlNode::devicePoint(const QPoint &p) const
++{
++ QRect mr = myRect();
++ QRect dr = deviceRect();
++
++ if (isStretched())
++ return dr.topLeft() + QPoint((p.x() - mr.left())*dr.width()/mr.width(),
++ (p.y() - mr.top())*dr.height()/mr.height());
++ else
++ return dr.topLeft() + p - mr.topLeft();
++}
++
++QString MmlNode::inheritAttributeFromMrow(const QString &name,
++ const QString &def) const
++{
++ const MmlNode *p = this;
++ for (; p != 0; p = p->parent()) {
++ if (p == this || p->nodeType() == MstyleNode) {
++ QString value = p->explicitAttribute(name);
++ if (!value.isNull())
++ return value;
++ }
++ }
++
++ return def;
++}
++
++QColor MmlNode::color() const
++{
++ // If we are child of <merror> return red
++ const MmlNode *p = this;
++ for (; p != 0; p = p->parent()) {
++ if (p->nodeType() == MerrorNode)
++ return QColor("red");
++ }
++
++ QString value_str = inheritAttributeFromMrow("mathcolor");
++ if (value_str.isNull())
++ value_str = inheritAttributeFromMrow("color");
++ if (value_str.isNull())
++ return QColor();
++
++ return QColor(value_str);
++}
++
++QColor MmlNode::background() const
++{
++ QString value_str = inheritAttributeFromMrow("mathbackground");
++ if (value_str.isNull())
++ value_str = inheritAttributeFromMrow("background");
++ if (value_str.isNull())
++ return QColor();
++
++ return QColor(value_str);
++}
++
++static void updateFontAttr(MmlAttributeMap &font_attr, const MmlNode *n,
++ const QString &name, const QString &preferred_name = QString::null)
++{
++ if (font_attr.contains(preferred_name) || font_attr.contains(name))
++ return;
++ QString value = n->explicitAttribute(name);
++ if (!value.isNull())
++ font_attr[name] = value;
++}
++
++static MmlAttributeMap collectFontAttributes(const MmlNode *node)
++{
++ MmlAttributeMap font_attr;
++
++ for (const MmlNode *n = node; n != 0; n = n->parent()) {
++ if (n == node || n->nodeType() == Mml::MstyleNode) {
++ updateFontAttr(font_attr, n, "mathvariant");
++ updateFontAttr(font_attr, n, "mathsize");
++
++ // depreciated attributes
++ updateFontAttr(font_attr, n, "fontsize", "mathsize");
++ updateFontAttr(font_attr, n, "fontweight", "mathvariant");
++ updateFontAttr(font_attr, n, "fontstyle", "mathvariant");
++ updateFontAttr(font_attr, n, "fontfamily", "mathvariant");
++ }
++ }
++
++ return font_attr;
++}
++
++QFont MmlNode::font() const
++{
++ QFont fn(document()->fontName(QtMmlWidget::NormalFont),
++ document()->baseFontPointSize());
++
++ int ps = fn.pointSize();
++ int sl = scriptlevel();
++ if (sl >= 0) {
++ for (int i = 0; i < sl; ++i)
++ ps = (int)(ps*g_script_size_multiplier);
++ }
++ else {
++ for (int i = 0; i > sl; --i)
++ ps = (int)(ps/g_script_size_multiplier);
++ }
++ if (ps < g_min_font_point_size)
++ ps = g_min_font_point_size;
++ fn.setPointSize(ps);
++
++ int em = QFontMetrics(fn).boundingRect('m').width();
++ int ex = QFontMetrics(fn).boundingRect('x').height();
++
++ MmlAttributeMap font_attr = collectFontAttributes(this);
++
++ if (font_attr.contains("mathvariant")) {
++ QString value = font_attr["mathvariant"];
++
++ bool ok;
++ uint mv = interpretMathVariant(value, &ok);
++
++ if (ok) {
++ if (mv & ScriptMV)
++ fn.setFamily(document()->fontName(QtMmlWidget::ScriptFont));
++
++ if (mv & FrakturMV)
++ fn.setFamily(document()->fontName(QtMmlWidget::FrakturFont));
++
++ if (mv & SansSerifMV)
++ fn.setFamily(document()->fontName(QtMmlWidget::SansSerifFont));
++
++ if (mv & MonospaceMV)
++ fn.setFamily(document()->fontName(QtMmlWidget::MonospaceFont));
++
++ if (mv & DoubleStruckMV)
++ fn.setFamily(document()->fontName(QtMmlWidget::DoublestruckFont));
++
++ if (mv & BoldMV)
++ fn.setBold(true);
++
++ if (mv & ItalicMV)
++ fn.setItalic(true);
++ }
++ }
++
++ if (font_attr.contains("mathsize")) {
++ QString value = font_attr["mathsize"];
++ fn = interpretMathSize(value, fn, em, ex, 0);
++ }
++
++ fn = interpretDepreciatedFontAttr(font_attr, fn, em, ex);
++
++ if (nodeType() == MiNode
++ && !font_attr.contains("mathvariant")
++ && !font_attr.contains("fontstyle")) {
++ const MmlMiNode *mi_node = (const MmlMiNode*) this;
++ if (mi_node->text().length() == 1)
++ fn.setItalic(true);
++ }
++
++ if (nodeType() == MoNode) {
++ fn.setItalic(false);
++ fn.setBold(false);
++ }
++
++ return fn;
++}
++
++QString MmlNode::explicitAttribute(const QString &name, const QString &def) const
++{
++ MmlAttributeMap::const_iterator it = m_attribute_map.find(name);
++ if (it != m_attribute_map.end())
++ return *it;
++ return def;
++}
++
++
++QRect MmlNode::parentRect() const
++{
++ if (isStretched())
++ return m_parent_rect;
++
++ QRect mr = myRect();
++ QPoint ro = relOrigin();
++
++ return QRect(ro + mr.topLeft(), mr.size());
++}
++
++
++void MmlNode::stretchTo(const QRect &rect)
++{
++ m_parent_rect = rect;
++ m_stretched = true;
++}
++
++void MmlNode::setRelOrigin(const QPoint &rel_origin)
++{
++ m_rel_origin = rel_origin + QPoint(-myRect().left(), 0);
++ m_stretched = false;
++}
++
++void MmlNode::updateMyRect()
++{
++ m_my_rect = symbolRect();
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling())
++ m_my_rect |= child->parentRect();
++}
++
++void MmlNode::layout()
++{
++ m_parent_rect = QRect(0, 0, 0, 0);
++ m_stretched = false;
++ m_rel_origin = QPoint(0, 0);
++
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling())
++ child->layout();
++
++ layoutSymbol();
++
++ updateMyRect();
++
++ if (parent() == 0)
++ m_rel_origin = QPoint(0, 0);
++}
++
++
++QRect MmlNode::deviceRect() const
++{
++ if (parent() == 0)
++ return QRect(relOrigin() + myRect().topLeft(), myRect().size());
++
++/* if (!isStretched()) {
++ QRect pdr = parent()->deviceRect();
++ QRect pmr = parent()->myRect();
++ QRect pr = parentRect();
++ QRect mr = myRect();
++ return QRect(pdr.left() + pr.left() - pmr.left(),
++ pdr.top() + pr.top() - pmr.top(),
++ mr.width(), mr.height());
++ }
++*/
++ QRect pdr = parent()->deviceRect();
++ QRect pr = parentRect();
++ QRect pmr = parent()->myRect();
++
++ float scale_w = 0;
++ if (pmr.width() != 0)
++ scale_w = (float)pdr.width()/pmr.width();
++ float scale_h = 0;
++ if (pmr.height() != 0)
++ scale_h = (float)pdr.height()/pmr.height();
++
++ return QRect(pdr.left() + ROUND((pr.left() - pmr.left())*scale_w),
++ pdr.top() + ROUND((pr.top() - pmr.top())*scale_h),
++ ROUND((pr.width()*scale_w)),
++ ROUND((pr.height()*scale_h)));
++}
++
++void MmlNode::layoutSymbol()
++{
++ // default behaves like an mrow
++
++ // now lay them out in a neat row, aligning their origins to my origin
++ int w = 0;
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling()) {
++ child->setRelOrigin(QPoint(w, 0));
++ w += child->parentRect().width() + 1;
++ }
++}
++
++void MmlNode::paint(QPainter *p)
++{
++ if (!myRect().isValid())
++ return;
++ p->save();
++ p->setViewport(deviceRect());
++ p->setWindow(myRect());
++
++
++ QColor fg = color();
++ QColor bg = background();
++ if (bg.isValid())
++ p->fillRect(myRect(), bg);
++ if (fg.isValid())
++ p->setPen(color());
++
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling())
++ child->paint(p);
++
++ paintSymbol(p);
++
++ p->restore();
++}
++
++void MmlNode::paintSymbol(QPainter *p) const
++{
++ if (g_draw_frames && myRect().isValid()) {
++ p->save();
++ p->setPen(Qt::red);
++ p->drawRect(m_my_rect);
++ QPen pen = p->pen();
++ pen.setStyle(Qt::DotLine);
++ p->setPen(pen);
++ p->drawLine(myRect().left(), 0, myRect().right(), 0);
++ p->restore();
++ }
++}
++
++void MmlNode::stretch()
++{
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling())
++ child->stretch();
++}
++
++QString MmlTokenNode::text() const
++{
++ QString result;
++
++ const MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling()) {
++ if (child->nodeType() != TextNode) continue;
++ if (!result.isEmpty())
++ result += ' ';
++ result += ((MmlTextNode*)child)->text();
++ }
++
++ return result;
++}
++
++MmlNode *MmlMfracNode::numerator() const
++{
++ MmlNode *node = firstChild();
++ Q_ASSERT(node != 0);
++ return node;
++}
++
++MmlNode *MmlMfracNode::denominator() const
++{
++ MmlNode *node = numerator()->nextSibling();
++ Q_ASSERT(node != 0);
++ return node;
++}
++
++QRect MmlMfracNode::symbolRect() const
++{
++ int num_width = numerator()->myRect().width();
++ int denom_width = denominator()->myRect().width();
++ int my_width = qMax(num_width, denom_width) + 4;
++
++ return QRect(-my_width/2, 0, my_width, 1);
++}
++
++void MmlMfracNode::layoutSymbol()
++{
++ MmlNode *num = numerator();
++ MmlNode *denom = denominator();
++
++ QRect num_rect = num->myRect();
++ QRect denom_rect = denom->myRect();
++
++ int spacing = (int)(g_mfrac_spacing*(num_rect.height() + denom_rect.height()));
++
++ num->setRelOrigin(QPoint(-num_rect.width()/2, - spacing - num_rect.bottom()));
++ denom->setRelOrigin(QPoint(-denom_rect.width()/2, spacing - denom_rect.top()));
++}
++
++static bool zeroLineThickness(const QString &s)
++{
++ if (s.length() == 0 || !s[0].isDigit())
++ return false;
++
++ for (int i = 0; i < s.length(); ++i) {
++ QChar c = s.at(i);
++ if (c.isDigit() && c != '0')
++ return false;
++ }
++ return true;
++}
++
++void MmlMfracNode::paintSymbol(QPainter *p) const
++{
++ QString linethickness_str = inheritAttributeFromMrow("linethickness", "1");
++
++ /* InterpretSpacing returns an int, which might be 0 even if the thickness
++ is > 0, though very very small. That's ok, because the painter then paints
++ a line of thickness 1. However, we have to run this check if the line
++ thickness really is zero */
++ if (!zeroLineThickness(linethickness_str)) {
++ bool ok;
++ int linethickness = interpretSpacing(linethickness_str, &ok);
++ if (!ok)
++ linethickness = 1;
++
++ p->save();
++ QPen pen = p->pen();
++ pen.setWidth(linethickness);
++ p->setPen(pen);
++ QSize s = myRect().size();
++ p->drawLine(-s.width()/2, 0, s.width()/2, 0);
++ p->restore();
++ }
++}
++
++MmlNode *MmlRootBaseNode::base() const
++{
++ MmlNode *node = firstChild();
++// Q_ASSERT(node != 0);
++ return node;
++}
++
++MmlNode *MmlRootBaseNode::index() const
++{
++ MmlNode *b = base();
++ if (b == 0)
++ return 0;
++ return b->nextSibling();
++}
++
++int MmlRootBaseNode::scriptlevel(const MmlNode *child) const
++{
++ int sl = MmlNode::scriptlevel();
++
++ MmlNode *i = index();
++ if (child != 0 && child == i)
++ return sl + 1;
++ else
++ return sl;
++}
++
++
++QRect MmlRootBaseNode::symbolRect() const
++{
++ MmlNode *b = base();
++ QRect base_rect;
++ if (b == 0)
++ base_rect = QRect(0, 0, 1, 1);
++ else
++ base_rect = base()->myRect();
++
++ int margin = (int)(g_mroot_base_margin*base_rect.height());
++ int tw = tailWidth();
++
++ return QRect(-tw, base_rect.top() - margin, tw,
++ base_rect.height() + 2*margin);
++}
++
++int MmlRootBaseNode::tailWidth() const
++{
++ QFontMetrics fm(font());
++ return fm.boundingRect(g_radical_char).width();
++}
++
++void MmlRootBaseNode::layoutSymbol()
++{
++ MmlNode *b = base();
++ QSize base_size;
++ if (b != 0) {
++ b->setRelOrigin(QPoint(0, 0));
++ base_size = base()->myRect().size();
++ } else
++ base_size = QSize(1, 1);
++
++ MmlNode *i = index();
++ if (i != 0) {
++ int tw = tailWidth();
++
++ QRect i_rect = i->myRect();
++ i->setRelOrigin(QPoint(-tw/2 - i_rect.width(),
++ -i_rect.bottom() - 4));
++ }
++}
++
++void MmlRootBaseNode::paintSymbol(QPainter *p) const
++{
++ QFont fn = font();
++
++ p->save();
++
++ QRect sr = symbolRect();
++
++ QRect r = sr;
++ r.moveTopLeft(devicePoint(sr.topLeft()));
++ p->setViewport(r);
++ p->setWindow(QFontMetrics(fn).boundingRect(g_radical_char));
++ p->setFont(font());
++ p->drawText(0, 0, QString(g_radical_char));
++
++ p->restore();
++
++ p->drawLine(sr.right(), sr.top(), myRect().right(), sr.top());
++}
++
++MmlTextNode::MmlTextNode(const QString &text, MmlDocument *document)
++ : MmlNode(TextNode, document, MmlAttributeMap())
++{
++ m_text = text;
++ // Trim whitespace from ends, but keep nbsp and thinsp
++ m_text.remove(QRegExp("^[^\\S\\x00a0\\x2009]+"));
++ m_text.remove(QRegExp("[^\\S\\x00a0\\x2009]+$"));
++
++ if (m_text == QString(QChar(0x62, 0x20)) // ⁢
++ || m_text == QString(QChar(0x63, 0x20)) // ⁣
++ || m_text == QString(QChar(0x61, 0x20))) // ⁡
++ m_text = "";
++}
++
++QString MmlTextNode::toStr() const
++{
++ return MmlNode::toStr() + ", text=\"" + m_text + "\"";
++}
++
++void MmlTextNode::paintSymbol(QPainter *p) const
++{
++ MmlNode::paintSymbol(p);
++
++ QFont fn = font();
++
++ QFontInfo fi(fn);
++// qWarning("MmlTextNode::paintSymbol(): requested: %s, used: %s, size=%d, italic=%d, bold=%d, text=\"%s\" sl=%d",
++// fn.family().latin1(), fi.family().latin1(), fi.pointSize(), (int)fi.italic(), (int)fi.bold(), m_text.latin1(), scriptlevel());
++
++ QFontMetrics fm(fn);
++
++ p->save();
++ p->setFont(fn);
++
++ p->drawText(0, fm.strikeOutPos(), m_text);
++ p->restore();
++}
++
++QRect MmlTextNode::symbolRect() const
++{
++ QFontMetrics fm(font());
++
++ QRect br = fm.tightBoundingRect(m_text);
++ br.translate(0, fm.strikeOutPos());
++
++ return br;
++}
++
++MmlNode *MmlSubsupBaseNode::base() const
++{
++ MmlNode *b = firstChild();
++ Q_ASSERT(b != 0);
++ return b;
++}
++
++MmlNode *MmlSubsupBaseNode::sscript() const
++{
++ MmlNode *s = base()->nextSibling();
++ Q_ASSERT(s != 0);
++ return s;
++}
++
++int MmlSubsupBaseNode::scriptlevel(const MmlNode *child) const
++{
++ int sl = MmlNode::scriptlevel();
++
++ MmlNode *s = sscript();
++ if (child != 0 && child == s)
++ return sl + 1;
++ else
++ return sl;
++}
++
++void MmlMsupNode::layoutSymbol()
++{
++ MmlNode *b = base();
++ MmlNode *s = sscript();
++
++ b->setRelOrigin(QPoint(-b->myRect().width(), 0));
++ s->setRelOrigin(QPoint(0, b->myRect().top()));
++}
++
++void MmlMsubNode::layoutSymbol()
++{
++ MmlNode *b = base();
++ MmlNode *s = sscript();
++
++ b->setRelOrigin(QPoint(-b->myRect().width(), 0));
++ s->setRelOrigin(QPoint(0, b->myRect().bottom()));
++}
++
++MmlNode *MmlMsubsupNode::base() const
++{
++ MmlNode *b = firstChild();
++ Q_ASSERT(b != 0);
++ return b;
++}
++
++MmlNode *MmlMsubsupNode::subscript() const
++{
++ MmlNode *sub = base()->nextSibling();
++ Q_ASSERT(sub != 0);
++ return sub;
++}
++
++MmlNode *MmlMsubsupNode::superscript() const
++{
++ MmlNode *sup = subscript()->nextSibling();
++ Q_ASSERT(sup != 0);
++ return sup;
++}
++
++void MmlMsubsupNode::layoutSymbol()
++{
++ MmlNode *b = base();
++ MmlNode *sub = subscript();
++ MmlNode *sup = superscript();
++
++ b->setRelOrigin(QPoint(-b->myRect().width(), 0));
++ sub->setRelOrigin(QPoint(0, b->myRect().bottom()));
++ sup->setRelOrigin(QPoint(0, b->myRect().top()));
++}
++
++int MmlMsubsupNode::scriptlevel(const MmlNode *child) const
++{
++ int sl = MmlNode::scriptlevel();
++
++ MmlNode *sub = subscript();
++ MmlNode *sup = superscript();
++
++ if (child != 0 && (child == sup || child == sub))
++ return sl + 1;
++ else
++ return sl;
++}
++
++QString MmlMoNode::toStr() const
++{
++ return MmlNode::toStr() + QString(" form=%1").arg((int)form());
++}
++
++void MmlMoNode::layoutSymbol()
++{
++ MmlNode *child = firstChild();
++ if (child == 0)
++ return;
++
++ child->setRelOrigin(QPoint(0, 0));
++
++ if (m_oper_spec == 0)
++ m_oper_spec = mmlFindOperSpec(text(), form());
++}
++
++MmlMoNode::MmlMoNode(MmlDocument *document, const MmlAttributeMap &attribute_map)
++ : MmlTokenNode(MoNode, document, attribute_map)
++{
++ m_oper_spec = 0;
++}
++
++QString MmlMoNode::dictionaryAttribute(const QString &name) const
++{
++ const MmlNode *p = this;
++ for (; p != 0; p = p->parent()) {
++ if (p == this || p->nodeType() == MstyleNode) {
++ QString expl_attr = p->explicitAttribute(name);
++ if (!expl_attr.isNull())
++ return expl_attr;
++ }
++ }
++
++ return mmlDictAttribute(name, m_oper_spec);
++}
++
++Mml::FormType MmlMoNode::form() const
++{
++ QString value_str = inheritAttributeFromMrow("form");
++ if (!value_str.isNull()) {
++ bool ok;
++ FormType value = interpretForm(value_str, &ok);
++ if (ok)
++ return value;
++ else
++ qWarning("Could not convert %s to form", value_str.toLatin1().data());
++
++ }
++
++ // Default heuristic.
++ if (firstSibling() == (MmlNode*)this && lastSibling() != (MmlNode*)this)
++ return PrefixForm;
++ else if (lastSibling() == (MmlNode*)this && firstSibling() != (MmlNode*)this)
++ return PostfixForm;
++ else return InfixForm;
++
++}
++
++void MmlMoNode::stretch()
++{
++ if (parent() == 0)
++ return;
++
++ if (m_oper_spec == 0)
++ return;
++
++ if (m_oper_spec->stretch_dir == OperSpec::HStretch
++ && parent()->nodeType() == MrowNode
++ && (nextSibling() != 0 || previousSibling() != 0))
++ return;
++
++ QRect pmr = parent()->myRect();
++ QRect pr = parentRect();
++
++ switch (m_oper_spec->stretch_dir) {
++ case OperSpec::VStretch:
++ stretchTo(QRect(pr.left(), pmr.top(), pr.width(), pmr.height()));
++ break;
++ case OperSpec::HStretch:
++ stretchTo(QRect(pmr.left(), pr.top(), pmr.width(), pr.height()));
++ break;
++ case OperSpec::HVStretch:
++ stretchTo(pmr);
++ break;
++ case OperSpec::NoStretch:
++ break;
++ }
++}
++
++int MmlMoNode::lspace() const
++{
++ Q_ASSERT(m_oper_spec != 0);
++ if (parent() == 0
++ || (parent()->nodeType() != MrowNode
++ && parent()->nodeType() != MfencedNode
++ && parent()->nodeType() != UnknownNode)
++ || (previousSibling() == 0 && nextSibling() == 0))
++ return 0;
++ else
++ return interpretSpacing(dictionaryAttribute("lspace"), 0);
++}
++
++int MmlMoNode::rspace() const
++{
++ Q_ASSERT(m_oper_spec != 0);
++ if (parent() == 0
++ || (parent()->nodeType() != MrowNode
++ && parent()->nodeType() != MfencedNode
++ && parent()->nodeType() != UnknownNode)
++ || (previousSibling() == 0 && nextSibling() == 0))
++ return 0;
++ else
++ return interpretSpacing(dictionaryAttribute("rspace"), 0);
++}
++
++QRect MmlMoNode::symbolRect() const
++{
++ const MmlNode *child = firstChild();
++
++ if (child == 0)
++ return QRect(0, 0, 0, 0);
++
++ QRect cmr = child->myRect();
++
++ return QRect(-lspace(), cmr.top(),
++ cmr.width() + lspace() + rspace(), cmr.height());
++}
++
++int MmlMtableNode::rowspacing() const
++{
++ QString value = explicitAttribute("rowspacing");
++ if (value.isNull())
++ return ex();
++ bool ok;
++ int r = interpretSpacing(value, &ok);
++
++ if (ok)
++ return r;
++ else
++ return ex();
++}
++
++int MmlMtableNode::columnspacing() const
++{
++ QString value = explicitAttribute("columnspacing");
++ if (value.isNull())
++ return (int)(0.8*em());
++ bool ok;
++ int r = interpretSpacing(value, &ok);
++
++ if (ok)
++ return r;
++ else
++ return (int)(0.8*em());
++}
++
++uint MmlMtableNode::CellSizeData::colWidthSum() const
++{
++ uint w = 0;
++ for (int i = 0; i < col_widths.count(); ++i)
++ w += col_widths[i];
++ return w;
++}
++
++uint MmlMtableNode::CellSizeData::rowHeightSum() const
++{
++ uint h = 0;
++ for (int i = 0; i < row_heights.count(); ++i)
++ h += row_heights[i];
++ return h;
++}
++
++void MmlMtableNode::CellSizeData::init(const MmlNode *first_row)
++{
++ col_widths.clear();
++ row_heights.clear();
++
++ const MmlNode *mtr = first_row;
++ for (; mtr != 0; mtr = mtr->nextSibling()) {
++
++ Q_ASSERT(mtr->nodeType() == MtrNode);
++
++ int col_cnt = 0;
++ const MmlNode *mtd = mtr->firstChild();
++ for (; mtd != 0; mtd = mtd->nextSibling(), ++col_cnt) {
++
++ Q_ASSERT(mtd->nodeType() == MtdNode);
++
++ QRect mtdmr = mtd->myRect();
++
++ if (col_cnt == col_widths.count())
++ col_widths.append(mtdmr.width());
++ else
++ col_widths[col_cnt] = qMax(col_widths[col_cnt], mtdmr.width());
++ }
++
++ row_heights.append(mtr->myRect().height());
++ }
++}
++
++void MmlMtableNode::layoutSymbol()
++{
++ // Obtain natural widths of columns
++ m_cell_size_data.init(firstChild());
++
++ int col_spc = columnspacing();
++ int row_spc = rowspacing();
++ int frame_spc_hor = framespacing_hor();
++ QString columnwidth_attr = explicitAttribute("columnwidth", "auto");
++
++ // Is table width set by user? If so, set col_width_sum and never ever change it.
++ int col_width_sum = m_cell_size_data.colWidthSum();
++ bool width_set_by_user = false;
++ QString width_str = explicitAttribute("width", "auto");
++ if (width_str != "auto") {
++ bool ok;
++
++ int w = interpretSpacing(width_str, &ok);
++ if (ok) {
++ col_width_sum = w
++ - col_spc*(m_cell_size_data.numCols() - 1)
++ - frame_spc_hor*2;
++ width_set_by_user = true;
++ }
++ }
++
++ // Find out what kind of columns we are dealing with and set the widths of
++ // statically sized columns.
++ int fixed_width_sum = 0; // sum of widths of statically sized set columns
++ int auto_width_sum = 0; // sum of natural widths of auto sized columns
++ int relative_width_sum = 0; // sum of natural widths of relatively sized columns
++ double relative_fraction_sum = 0; // total fraction of width taken by relatively
++ // sized columns
++ int i;
++ for (i = 0; i < m_cell_size_data.numCols(); ++i) {
++ QString value = interpretListAttr(columnwidth_attr, i, "auto");
++
++ // Is it an auto sized column?
++ if (value == "auto" || value == "fit") {
++ auto_width_sum += m_cell_size_data.col_widths[i];
++ continue;
++ }
++
++ // Is it a statically sized column?
++ bool ok;
++ int w = interpretSpacing(value, &ok);
++ if (ok) {
++ // Yup, sets its width to the user specified value
++ m_cell_size_data.col_widths[i] = w;
++ fixed_width_sum += w;
++ continue;
++ }
++
++ // Is it a relatively sized column?
++ if (value.endsWith("%")) {
++ value.truncate(value.length() - 1);
++ double factor = value.toFloat(&ok);
++ if (ok && !value.isEmpty()) {
++ factor /= 100.0;
++ relative_width_sum += m_cell_size_data.col_widths[i];
++ relative_fraction_sum += factor;
++ if (!width_set_by_user) {
++ // If the table width was not set by the user, we are free to increase
++ // it so that the width of this column will be >= than its natural width
++ int min_col_width_sum = ROUND(m_cell_size_data.col_widths[i]/factor);
++ if (min_col_width_sum > col_width_sum)
++ col_width_sum = min_col_width_sum;
++ }
++ continue;
++ }
++ else
++ qWarning("MmlMtableNode::layoutSymbol(): could not parse value %s%%", value.toLatin1().data());
++ }
++
++ // Relatively sized column, but we failed to parse the factor. Treat is like an auto
++ // column.
++ auto_width_sum += m_cell_size_data.col_widths[i];
++ }
++
++ // Work out how much space remains for the auto olumns, after allocating
++ // the statically sized and the relatively sized columns.
++ int required_auto_width_sum = col_width_sum
++ - ROUND(relative_fraction_sum*col_width_sum)
++ - fixed_width_sum;
++
++ if (!width_set_by_user && required_auto_width_sum < auto_width_sum) {
++ if (relative_fraction_sum < 1)
++ col_width_sum = ROUND((fixed_width_sum + auto_width_sum)/(1 - relative_fraction_sum));
++ else
++ col_width_sum = fixed_width_sum + auto_width_sum + relative_width_sum;
++ required_auto_width_sum = auto_width_sum;
++ }
++
++ // Ratio by which we have to shring/grow all auto sized columns to make it all fit
++ double auto_width_scale = 1;
++ if (auto_width_sum > 0)
++ auto_width_scale = (float)required_auto_width_sum/auto_width_sum;
++
++ // Set correct sizes for the auto sized and the relatively sized columns.
++ for (i = 0; i < m_cell_size_data.numCols(); ++i) {
++ QString value = interpretListAttr(columnwidth_attr, i, "auto");
++
++ // Is it a relatively sized column?
++ if (value.endsWith("%")) {
++ bool ok;
++ int w = interpretPercentSpacing(value, col_width_sum, &ok);
++ if (ok)
++ m_cell_size_data.col_widths[i] = w;
++ else
++ // We're treating parsing errors here as auto sized columns
++ m_cell_size_data.col_widths[i]
++ = ROUND(auto_width_scale*m_cell_size_data.col_widths[i]);
++ }
++ // Is it an auto sized column?
++ else if (value == "auto") {
++ m_cell_size_data.col_widths[i]
++ = ROUND(auto_width_scale*m_cell_size_data.col_widths[i]);
++ }
++ }
++
++ QString s;
++ QList<int> &col_widths = m_cell_size_data.col_widths;
++ for (i = 0; i < col_widths.count(); ++i) {
++ s += QString("[w=%1 %2%%]")
++ .arg(col_widths[i])
++ .arg(100*col_widths[i]/m_cell_size_data.colWidthSum());
++ }
++// qWarning(s);
++
++ m_content_width = m_cell_size_data.colWidthSum()
++ + col_spc*(m_cell_size_data.numCols() - 1);
++ m_content_height = m_cell_size_data.rowHeightSum()
++ + row_spc*(m_cell_size_data.numRows() - 1);
++
++ int bottom = -m_content_height/2;
++ MmlNode *child = firstChild();
++ for (; child != 0; child = child->nextSibling()) {
++ Q_ASSERT(child->nodeType() == MtrNode);
++ MmlMtrNode *row = (MmlMtrNode*) child;
++
++ row->layoutCells(m_cell_size_data.col_widths, col_spc);
++ QRect rmr = row->myRect();
++ row->setRelOrigin(QPoint(0, bottom - rmr.top()));
++ bottom += rmr.height() + row_spc;
++ }
++}
++
++QRect MmlMtableNode::symbolRect() const
++{
++ int frame_spc_hor = framespacing_hor();
++ int frame_spc_ver = framespacing_ver();
++
++ return QRect(-frame_spc_hor,
++ -m_content_height/2 - frame_spc_ver,
++ m_content_width + 2*frame_spc_hor,
++ m_content_height + 2*frame_spc_ver);
++}
++
++Mml::FrameType MmlMtableNode::frame() const
++{
++ QString value = explicitAttribute("frame", "none");
++ return interpretFrameType(value, 0, 0);
++}
++
++Mml::FrameType MmlMtableNode::columnlines(int idx) const
++{
++ QString value = explicitAttribute("columnlines", "none");
++ return interpretFrameType(value, idx, 0);
++}
++
++Mml::FrameType MmlMtableNode::rowlines(int idx) const
++{
++ QString value = explicitAttribute("rowlines", "none");
++ return interpretFrameType(value, idx, 0);
++}
++
++void MmlMtableNode::paintSymbol(QPainter *p) const
++{
++ FrameType f = frame();
++ if (f != FrameNone) {
++ p->save();
++
++ QPen pen = p->pen();
++ if (f == FrameDashed)
++ pen.setStyle(Qt::DashLine);
++ else
++ pen.setStyle(Qt::SolidLine);
++ p->setPen(pen);
++ p->drawRect(myRect());
++
++ p->restore();
++ }
++
++ p->save();
++
++ int col_spc = columnspacing();
++ int row_spc = rowspacing();
++
++ QPen pen = p->pen();
++ int col_offset = 0;
++ int i;
++ for (i = 0; i < m_cell_size_data.numCols() - 1; ++i) {
++ FrameType f = columnlines(i);
++ col_offset += m_cell_size_data.col_widths[i];
++
++ if (f != FrameNone) {
++ if (f == FrameDashed)
++ pen.setStyle(Qt::DashLine);
++ else if (f == FrameSolid)
++ pen.setStyle(Qt::SolidLine);
++
++ p->setPen(pen);
++ int x = col_offset + col_spc/2;
++ p->drawLine(x, -m_content_height/2, x, m_content_height/2 );
++ }
++ col_offset += col_spc;
++ }
++
++ int row_offset = 0;
++ for (i = 0; i < m_cell_size_data.numRows() - 1; ++i) {
++ FrameType f = rowlines(i);
++ row_offset += m_cell_size_data.row_heights[i];
++
++ if (f != FrameNone) {
++ if (f == FrameDashed)
++ pen.setStyle(Qt::DashLine);
++ else if (f == FrameSolid)
++ pen.setStyle(Qt::SolidLine);
++
++ p->setPen(pen);
++ int y = row_offset + row_spc/2 - m_content_height/2;
++ p->drawLine(0, y, m_content_width, y);
++ }
++ row_offset += row_spc;
++ }
++
++ p->restore();
++}
++
++int MmlMtableNode::framespacing_ver() const
++{
++ if (frame() == FrameNone)
++ return (int)(0.2*em());
++
++ QString value = explicitAttribute("framespacing", "0.4em 0.5ex");
++
++ bool ok;
++ FrameSpacing fs = interpretFrameSpacing(value, em(), ex(), &ok);
++ if (ok)
++ return fs.m_ver;
++ else
++ return (int)(0.5*ex());
++}
++
++int MmlMtableNode::framespacing_hor() const
++{
++ if (frame() == FrameNone)
++ return (int)(0.2*em());
++
++ QString value = explicitAttribute("framespacing", "0.4em 0.5ex");
++
++ bool ok;
++ FrameSpacing fs = interpretFrameSpacing(value, em(), ex(), &ok);
++ if (ok)
++ return fs.m_hor;
++ else
++ return (int)(0.4*em());
++}
++
++void MmlMtrNode::layoutCells(const QList<int> &col_widths,
++ int col_spc)
++{
++ QRect mr = myRect();
++
++ MmlNode *child = firstChild();
++ int col_offset = 0;
++ uint colnum = 0;
++ for (; child != 0; child = child->nextSibling(), ++colnum) {
++ Q_ASSERT(child->nodeType() == MtdNode);
++ MmlMtdNode *mtd = (MmlMtdNode*) child;
++
++ QRect r = QRect(0, mr.top(), col_widths[colnum], mr.height());
++ mtd->setMyRect(r);
++ mtd->setRelOrigin(QPoint(col_offset, 0));
++ col_offset += col_widths[colnum] + col_spc;
++ }
++
++ updateMyRect();
++}
++
++int MmlMtdNode::scriptlevel(const MmlNode *child) const
++{
++ int sl = MmlNode::scriptlevel();
++ if (child != 0 && child == firstChild())
++ return sl + m_scriptlevel_adjust;
++ else
++ return sl;
++}
++
++void MmlMtdNode::setMyRect(const QRect &rect)
++{
++ MmlNode::setMyRect(rect);
++ MmlNode *child = firstChild();
++ if (child == 0)
++ return;
++
++ if (rect.width() < child->myRect().width()) {
++ while (rect.width() < child->myRect().width()
++ && child->font().pointSize() > g_min_font_point_size) {
++
++// qWarning("MmlMtdNode::setMyRect(): rect.width()=%d, child()->myRect().width=%d sl=%d",
++// rect.width(), child->myRect().width(), m_scriptlevel_adjust);
++
++ ++m_scriptlevel_adjust;
++ child->layout();
++ }
++
++// qWarning("MmlMtdNode::setMyRect(): rect.width()=%d, child()->myRect().width=%d sl=%d",
++// rect.width(), child->myRect().width(), m_scriptlevel_adjust);
++ }
++
++ QRect mr = myRect();
++ QRect cmr = child->myRect();
++
++ QPoint child_rel_origin;
++
++ switch (columnalign()) {
++ case ColAlignLeft:
++ child_rel_origin.setX(0);
++ break;
++ case ColAlignCenter:
++ child_rel_origin.setX(mr.left() + (mr.width() - cmr.width())/2);
++ break;
++ case ColAlignRight:
++ child_rel_origin.setX(mr.right() - cmr.width());
++ break;
++ }
++
++ switch (rowalign()) {
++ case RowAlignTop:
++ child_rel_origin.setY(mr.top() - cmr.top());
++ break;
++ case RowAlignCenter:
++ case RowAlignBaseline:
++ child_rel_origin.setY(mr.top() -cmr.top() + (mr.height() - cmr.height())/2);
++ break;
++ case RowAlignBottom:
++ child_rel_origin.setY(mr.bottom() - cmr.bottom());
++ break;
++ case RowAlignAxis:
++ child_rel_origin.setY(0);
++ break;
++ }
++
++ child->setRelOrigin(child_rel_origin);
++}
++
++uint MmlMtdNode::colNum()
++{
++ MmlNode *syb = previousSibling();
++
++ uint i = 0;
++ for (; syb != 0; syb = syb->previousSibling())
++ ++i;
++
++ return i;
++}
++
++uint MmlMtdNode::rowNum()
++{
++ MmlNode *row = parent()->previousSibling();
++
++ uint i = 0;
++ for (; row != 0; row = row->previousSibling())
++ ++i;
++
++ return i;
++}
++
++MmlMtdNode::ColAlign MmlMtdNode::columnalign()
++{
++ QString val = explicitAttribute("columnalign");
++ if (!val.isNull())
++ return interpretColAlign(val, 0, 0);
++
++ MmlNode *node = parent(); // <mtr>
++ if (node == 0)
++ return ColAlignCenter;
++
++ uint colnum = colNum();
++ val = node->explicitAttribute("columnalign");
++ if (!val.isNull())
++ return interpretColAlign(val, colnum, 0);
++
++ node = node->parent(); // <mtable>
++ if (node == 0)
++ return ColAlignCenter;
++
++ val = node->explicitAttribute("columnalign");
++ if (!val.isNull())
++ return interpretColAlign(val, colnum, 0);
++
++ return ColAlignCenter;
++}
++
++MmlMtdNode::RowAlign MmlMtdNode::rowalign()
++{
++ QString val = explicitAttribute("rowalign");
++ if (!val.isNull())
++ return interpretRowAlign(val, 0, 0);
++
++ MmlNode *node = parent(); // <mtr>
++ if (node == 0)
++ return RowAlignAxis;
++
++ uint rownum = rowNum();
++ val = node->explicitAttribute("rowalign");
++ if (!val.isNull())
++ return interpretRowAlign(val, rownum, 0);
++
++ node = node->parent(); // <mtable>
++ if (node == 0)
++ return RowAlignAxis;
++
++ val = node->explicitAttribute("rowalign");
++ if (!val.isNull())
++ return interpretRowAlign(val, rownum, 0);
++
++ return RowAlignAxis;
++}
++
++void MmlMoverNode::layoutSymbol()
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *over = base->nextSibling();
++ Q_ASSERT(over != 0);
++
++ QRect base_rect = base->myRect();
++ QRect over_rect = over->myRect();
++
++ int spacing = (int)(g_mfrac_spacing*(over_rect.height()
++ + base_rect.height()));
++
++ base->setRelOrigin(QPoint(-base_rect.width()/2, 0));
++ over->setRelOrigin(QPoint(-over_rect.width()/2,
++ base_rect.top() - spacing - over_rect.bottom()));
++}
++
++int MmlMoverNode::scriptlevel(const MmlNode *node) const
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *over = base->nextSibling();
++ Q_ASSERT(over != 0);
++
++ int sl = MmlNode::scriptlevel();
++ if (node != 0 && node == over)
++ return sl + 1;
++ else
++ return sl;
++}
++
++void MmlMunderNode::layoutSymbol()
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *under = base->nextSibling();
++ Q_ASSERT(under != 0);
++
++ QRect base_rect = base->myRect();
++ QRect under_rect = under->myRect();
++
++ int spacing = (int)(g_mfrac_spacing*(under_rect.height() + base_rect.height()));
++
++ base->setRelOrigin(QPoint(-base_rect.width()/2, 0));
++ under->setRelOrigin(QPoint(-under_rect.width()/2, base_rect.bottom() + spacing - under_rect.top()));
++}
++
++int MmlMunderNode::scriptlevel(const MmlNode *node) const
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *under = base->nextSibling();
++ Q_ASSERT(under != 0);
++
++ int sl = MmlNode::scriptlevel();
++ if (node != 0 && node == under)
++ return sl + 1;
++ else
++ return sl;
++}
++
++void MmlMunderoverNode::layoutSymbol()
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *under = base->nextSibling();
++ Q_ASSERT(under != 0);
++ MmlNode *over = under->nextSibling();
++ Q_ASSERT(over != 0);
++
++ QRect base_rect = base->myRect();
++ QRect under_rect = under->myRect();
++ QRect over_rect = over->myRect();
++
++ int spacing = (int)(g_mfrac_spacing*( base_rect.height()
++ + under_rect.height()
++ + over_rect.height()) );
++
++ base->setRelOrigin(QPoint(-base_rect.width()/2, 0));
++ under->setRelOrigin(QPoint(-under_rect.width()/2, base_rect.bottom() + spacing - under_rect.top()));
++ over->setRelOrigin(QPoint(-over_rect.width()/2, base_rect.top() - spacing - under_rect.bottom()));
++}
++
++int MmlMunderoverNode::scriptlevel(const MmlNode *node) const
++{
++ MmlNode *base = firstChild();
++ Q_ASSERT(base != 0);
++ MmlNode *under = base->nextSibling();
++ Q_ASSERT(under != 0);
++ MmlNode *over = under->nextSibling();
++ Q_ASSERT(over != 0);
++
++ int sl = MmlNode::scriptlevel();
++ if (node != 0 && (node == under || node == over))
++ return sl + 1;
++ else
++ return sl;
++}
++
++int MmlMpaddedNode::interpretSpacing(QString value, int base_value, bool *ok) const
++{
++ if (ok != 0)
++ *ok = false;
++
++ value.replace(' ', "");
++
++ QString sign, factor_str, pseudo_unit;
++ bool percent = false;
++
++ // extract the sign
++ int idx = 0;
++ if (idx < value.length() && (value.at(idx) == '+' || value.at(idx) == '-'))
++ sign = value.at(idx++);
++
++ // extract the factor
++ while (idx < value.length() && (value.at(idx).isDigit() || value.at(idx) == '.'))
++ factor_str.append(value.at(idx++));
++
++ // extract the % sign
++ if (idx < value.length() && value.at(idx) == '%') {
++ percent = true;
++ ++idx;
++ }
++
++ // extract the pseudo-unit
++ pseudo_unit = value.mid(idx);
++
++ bool float_ok;
++ double factor = factor_str.toFloat(&float_ok);
++ if (!float_ok || factor < 0) {
++ qWarning("MmlMpaddedNode::interpretSpacing(): could not parse \"%s\"", value.toLatin1().data());
++ return 0;
++ }
++
++ if (percent)
++ factor /= 100.0;
++
++ QRect cr;
++ if (firstChild() == 0)
++ cr = QRect(0, 0, 0, 0);
++ else
++ cr = firstChild()->myRect();
++
++ int unit_size;
++
++ if (pseudo_unit.isEmpty())
++ unit_size = base_value;
++ else if (pseudo_unit == "width")
++ unit_size = cr.width();
++ else if (pseudo_unit == "height")
++ unit_size = -cr.top();
++ else if (pseudo_unit == "depth")
++ unit_size = cr.bottom();
++ else {
++ bool unit_ok;
++ unit_size = MmlNode::interpretSpacing("1" + pseudo_unit, &unit_ok);
++ if (!unit_ok) {
++ qWarning("MmlMpaddedNode::interpretSpacing(): could not parse \"%s\"", value.toLatin1().data());
++ return 0;
++ }
++ }
++
++ if (ok != 0)
++ *ok = true;
++
++ if (sign.isNull())
++ return (int)(factor*unit_size);
++ else if (sign == "+")
++ return base_value + (int)(factor*unit_size);
++ else // sign == "-"
++ return base_value - (int)(factor*unit_size);
++}
++
++int MmlMpaddedNode::lspace() const
++{
++ QString value = explicitAttribute("lspace");
++
++ if (value.isNull())
++ return 0;
++
++ bool ok;
++ int lspace = interpretSpacing(value, 0, &ok);
++
++ if (ok)
++ return lspace;
++
++ return 0;
++}
++
++int MmlMpaddedNode::width() const
++{
++ int child_width = 0;
++ if (firstChild() != 0)
++ child_width = firstChild()->myRect().width();
++
++ QString value = explicitAttribute("width");
++ if (value.isNull())
++ return child_width;
++
++ bool ok;
++ int w = interpretSpacing(value, child_width, &ok);
++ if (ok)
++ return w;
++
++ return child_width;
++}
++
++int MmlMpaddedNode::height() const
++{
++ QRect cr;
++ if (firstChild() == 0)
++ cr = QRect(0, 0, 0, 0);
++ else
++ cr = firstChild()->myRect();
++
++ QString value = explicitAttribute("height");
++ if (value.isNull())
++ return -cr.top();
++
++ bool ok;
++ int h = interpretSpacing(value, -cr.top(), &ok);
++ if (ok)
++ return h;
++
++ return -cr.top();
++}
++
++int MmlMpaddedNode::depth() const
++{
++ QRect cr;
++ if (firstChild() == 0)
++ cr = QRect(0, 0, 0, 0);
++ else
++ cr = firstChild()->myRect();
++
++ QString value = explicitAttribute("depth");
++ if (value.isNull())
++ return cr.bottom();
++
++ bool ok;
++ int h = interpretSpacing(value, cr.bottom(), &ok);
++ if (ok)
++ return h;
++
++ return cr.bottom();
++}
++
++void MmlMpaddedNode::layoutSymbol()
++{
++ MmlNode *child = firstChild();
++ if (child == 0)
++ return;
++
++ child->setRelOrigin(QPoint(0, 0));
++}
++
++
++QRect MmlMpaddedNode::symbolRect() const
++{
++ return QRect(-lspace(), -height(), lspace() + width(), height() + depth());
++}
++
++// *******************************************************************
++// QtMmlWidget
++// *******************************************************************
++
++/*!
++ \class QtMmlWidget
++
++ \brief The QtMmlWidget class renders mathematical formulas written in MathML 2.0.
++
++ QtMmlWidget implements the Presentation Markup subset of the
++ MathML 2.0 specification, with a few \link overview.html exceptions\endlink.
++
++ \code
++ QtMmlWidget *mmlWidget = new QtMmlWidget(this);
++ QString errorMsg;
++ int errorLine;
++ int errorColumn;
++ bool ok = mmlWidget->setContent(mmlText, &errorMsg, &errorLine, &errorColumn);
++ if (!ok) {
++ qWarning("MathML error: %s, Line: %d, Column: %d",
++ errorMsg.latin1(), errorLine, errorColumn);
++ }
++ \endcode
++
++*/
++
++
++/*!
++ \enum QtMmlWidget::MmlFont
++
++ This ennumerated type is used in fontName() and setFontName() to
++ specify a font type.
++
++ \value NormalFont The default font type, used to render
++ expressions for which no mathvariant or fontfamily is specified,
++ or for which the "normal" mathvariant is specified.
++
++ \value FrakturFont The font type used to render expressions for
++ which the "fraktur" mathvariant is specified.
++
++ \value SansSerifFont The font type used to render expressions
++ for which the "sans-serif" mathvariant is specified.
++
++ \value ScriptFont The font type used to render expressions
++ for which the "script" mathvariant is specified.
++
++ \value MonospaceFont The font type used to render expressions
++ for which the "monospace" mathvariant is specified.
++
++ \value DoublestruckFont The font type used to render expressions
++ for which the "doublestruck" mathvariant is specified.
++
++ \sa setFontName() fontName() setBaseFontPointSize() baseFontPointSize()
++*/
++
++/*!
++ Constructs a QtMmlWidget object. The \a parent
++ parameter is passed to QFrame's constructor.
++*/
++
++QtMmlWidget::QtMmlWidget(QWidget *parent)
++ : QFrame(parent)
++{
++ m_doc = new MmlDocument;
++}
++
++/*!
++ Destructs a QtMmlWidget object.
++*/
++
++QtMmlWidget::~QtMmlWidget()
++{
++ delete m_doc;
++}
++
++/*!
++ Returns the name of the font used to render the font \a type.
++
++ \sa setFontName() setBaseFontPointSize() baseFontPointSize() QtMmlWidget::MmlFont
++*/
++
++QString QtMmlWidget::fontName(MmlFont type) const
++{
++ return m_doc->fontName(type);
++}
++
++/*!
++ Sets the name of the font used to render the font \a type to \a name.
++
++ \sa fontName() setBaseFontPointSize() baseFontPointSize() QtMmlWidget::MmlFont
++*/
++
++void QtMmlWidget::setFontName(MmlFont type, const QString &name)
++{
++ m_doc->setFontName(type, name);
++ m_doc->layout();
++ update();
++}
++
++/*!
++ If \a b is true, draws a red bounding rectangle around each
++ expression; if \a b is false, no such rectangle is drawn.
++ This is mostly useful for debugging MathML expressions.
++
++ \sa drawFrames()
++*/
++
++void QtMmlWidget::setDrawFrames(bool b)
++{
++ g_draw_frames = b;
++ update();
++}
++
++/*!
++ Returns true if each expression should be drawn with a red
++ bounding rectangle; otherwise returns false.
++ This is mostly useful for debugging MathML expressions.
++
++ \sa setDrawFrames()
++*/
++
++bool QtMmlWidget::drawFrames() const
++{
++ return g_draw_frames;
++}
++
++/*!
++ Clears the contents of this widget.
++*/
++void QtMmlWidget::clear()
++{
++ m_doc->clear();
++}
++
++/*!
++ Returns the point size of the font used to render expressions
++ whose scriptlevel is 0.
++
++ \sa setBaseFontPointSize() fontName() setFontName()
++*/
++
++int QtMmlWidget::baseFontPointSize() const
++{
++ return m_doc->baseFontPointSize();
++}
++
++/*!
++ Sets the point \a size of the font used to render expressions
++ whose scriptlevel is 0.
++
++ \sa baseFontPointSize() fontName() setFontName()
++*/
++
++void QtMmlWidget::setBaseFontPointSize(int size)
++{
++ if (size < g_min_font_point_size)
++ return;
++
++ m_doc->setBaseFontPointSize(size);
++ m_doc->layout();
++ update();
++}
++
++/*!
++ Returns the size of the formula in pixels.
++*/
++
++QSize QtMmlWidget::sizeHint() const
++{
++ QSize size = m_doc->size();
++ if (size == QSize(0, 0))
++ return QSize(100, 50);
++ return m_doc->size();
++}
++
++/*!
++ Sets the MathML expression to be rendered. The expression is given
++ in the string \a text. If the expression is successfully parsed,
++ this method returns true; otherwise it returns false. If an error
++ occured \a errorMsg is set to a diagnostic message, while \a
++ errorLine and \a errorColumn contain the location of the error.
++ Any of \a errorMsg, \a errorLine and \a errorColumn may be 0,
++ in which case they are not set.
++
++ \a text should contain MathML 2.0 presentation markup elements enclosed
++ in a <math> element.
++*/
++
++bool QtMmlWidget::setContent(const QString &text, QString *errorMsg,
++ int *errorLine, int *errorColumn)
++{
++ bool result = m_doc->setContent(text, errorMsg, errorLine, errorColumn);
++ if (result)
++ update();
++ return result;
++}
++
++/*! \internal */
++
++void QtMmlWidget::paintEvent(QPaintEvent *e)
++{
++ QFrame::paintEvent(e);
++ QPainter p(this);
++ if (e->rect().intersects(contentsRect()))
++ p.setClipRegion(e->region().intersect(contentsRect()));
++
++ QSize s = m_doc->size();
++ int x = (width() - s.width())/2;
++ int y = (height() - s.height())/2;
++ m_doc->paint(&p, QPoint(x, y));
++}
++
++/*! \internal */
++
++void QtMmlWidget::dump() const
++{
++ m_doc->dump();
++}
++
++// *******************************************************************
++// Static helper functions
++// *******************************************************************
++
++static QString entityDeclarations()
++{
++ QString result = "<!DOCTYPE math [\n";
++
++ const EntitySpec *ent = g_xml_entity_data;
++ for (; ent->name != 0; ++ent) {
++ result += "\t<!ENTITY " + QString(ent->name) + " \"" + ent->value + "\">\n";
++ }
++
++ result += "]>\n";
++
++ return result;
++}
++
++static int interpretSpacing(QString value, int em, int ex, bool *ok)
++{
++ if (ok != 0)
++ *ok = true;
++
++ if (value == "thin")
++ return 1;
++
++ if (value == "medium")
++ return 2;
++
++ if (value == "thick")
++ return 3;
++
++ struct HSpacingValue {
++ const char *name;
++ float factor;
++ };
++
++ static const HSpacingValue g_h_spacing_data[] =
++ {
++ { "veryverythinmathspace", (float) 0.0555556 },
++ { "verythinmathspace", (float) 0.111111 },
++ { "thinmathspace", (float) 0.166667 },
++ { "mediummathspace", (float) 0.222222 },
++ { "thickmathspace", (float) 0.277778 },
++ { "verythickmathspace", (float) 0.333333 },
++ { "veryverythickmathspace", (float) 0.388889 },
++ { 0, (float) 0 }
++ };
++
++ const HSpacingValue *v = g_h_spacing_data;
++ for (; v->name != 0; ++v) {
++ if (value == v->name)
++ return (int)(em*v->factor);
++ }
++
++ if (value.endsWith("em")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0)
++ return (int)(em*factor);
++ else {
++ qWarning("interpretSpacing(): could not parse \"%sem\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (value.endsWith("ex")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0)
++ return (int)(ex*factor);
++ else {
++ qWarning("interpretSpacing(): could not parse \"%sex\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (value.endsWith("cm")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0) {
++ Q_ASSERT(qApp->desktop() != 0);
++ QDesktopWidget *dw = qApp->desktop();
++ Q_ASSERT(dw->width() != 0);
++ Q_ASSERT(dw->widthMM() != 0);
++ return (int)(factor*10*dw->width()/dw->widthMM());
++ }
++ else {
++ qWarning("interpretSpacing(): could not parse \"%scm\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (value.endsWith("mm")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0) {
++ Q_ASSERT(qApp->desktop() != 0);
++ QDesktopWidget *dw = qApp->desktop();
++ Q_ASSERT(dw->width() != 0);
++ Q_ASSERT(dw->widthMM() != 0);
++ return (int)(factor*dw->width()/dw->widthMM());
++ }
++ else {
++ qWarning("interpretSpacing(): could not parse \"%smm\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (value.endsWith("in")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0) {
++ Q_ASSERT(qApp->desktop() != 0);
++ QDesktopWidget *dw = qApp->desktop();
++ Q_ASSERT(dw->width() != 0);
++ Q_ASSERT(dw->widthMM() != 0);
++ return (int)(factor*10*dw->width()/(2.54*dw->widthMM()));
++ }
++ else {
++ qWarning("interpretSpacing(): could not parse \"%sin\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ if (value.endsWith("px")) {
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ int i = (int) value.toFloat(&float_ok);
++ if (float_ok && i >= 0)
++ return i;
++ else {
++ qWarning("interpretSpacing(): could not parse \"%spx\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++ }
++
++ bool float_ok;
++ int i = (int)value.toFloat(&float_ok);
++ if (float_ok && i >= 0)
++ return i;
++
++ qWarning("interpretSpacing(): could not parse \"%s\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++}
++
++static int interpretPercentSpacing(QString value, int base, bool *ok)
++{
++ if (!value.endsWith("%")) {
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++
++ value.truncate(value.length() - 1);
++ bool float_ok;
++ float factor = value.toFloat(&float_ok);
++ if (float_ok && factor >= 0) {
++ if (ok != 0)
++ *ok = true;
++ return (int)(base*factor/100.0);
++ }
++
++ qWarning("interpretPercentSpacing(): could not parse \"%s%%\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++}
++
++static int interpretPointSize(QString value, bool *ok)
++{
++ if (!value.endsWith("pt")) {
++ if (ok != 0)
++ *ok = false;
++ return 0;
++ }
++
++ value.truncate(value.length() - 2);
++ bool float_ok;
++ int pt_size = (int) value.toFloat(&float_ok);
++ if (float_ok && pt_size > 0) {
++ if (ok != 0)
++ *ok = true;
++ return pt_size;
++ }
++
++ qWarning("interpretPointSize(): could not parse \"%spt\"", value.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return 0;
++}
++
++static const NodeSpec *mmlFindNodeSpec(Mml::NodeType type)
++{
++ const NodeSpec *spec = g_node_spec_data;
++ for (; spec->type != Mml::NoNode; ++spec) {
++ if (type == spec->type) return spec;
++ }
++ return 0;
++}
++
++static const NodeSpec *mmlFindNodeSpec(const QString &tag)
++{
++ const NodeSpec *spec = g_node_spec_data;
++ for (; spec->type != Mml::NoNode; ++spec) {
++ if (tag == spec->tag) return spec;
++ }
++ return 0;
++}
++
++static bool mmlCheckChildType(Mml::NodeType parent_type, Mml::NodeType child_type,
++ QString *error_str)
++{
++ if (parent_type == Mml::UnknownNode || child_type == Mml::UnknownNode)
++ return true;
++
++ const NodeSpec *child_spec = mmlFindNodeSpec(child_type);
++ const NodeSpec *parent_spec = mmlFindNodeSpec(parent_type);
++
++ Q_ASSERT(parent_spec != 0);
++ Q_ASSERT(child_spec != 0);
++
++ QString allowed_child_types(parent_spec->child_types);
++ // null list means any child type is valid
++ if (allowed_child_types.isNull())
++ return true;
++
++ QString child_type_str = QString(" ") + child_spec->type_str + " ";
++ if (!allowed_child_types.contains(child_type_str)) {
++ if (error_str != 0)
++ *error_str = QString("illegal child ")
++ + child_spec->type_str
++ + " for parent "
++ + parent_spec->type_str;
++ return false;
++ }
++
++ return true;
++}
++
++static bool mmlCheckAttributes(Mml::NodeType child_type, const MmlAttributeMap &attr,
++ QString *error_str)
++{
++ const NodeSpec *spec = mmlFindNodeSpec(child_type);
++ Q_ASSERT(spec != 0);
++
++ QString allowed_attr(spec->attributes);
++ // empty list means any attr is valid
++ if (allowed_attr.isEmpty())
++ return true;
++
++ MmlAttributeMap::const_iterator it = attr.begin(), end = attr.end();
++ for (; it != end; ++it) {
++ QString name = it.key();
++
++ if (name.indexOf(':') != -1)
++ continue;
++
++ QString padded_name = " " + name + " ";
++ if (!allowed_attr.contains(padded_name)) {
++ if (error_str != 0)
++ *error_str = QString("illegal attribute ")
++ + name
++ + " in "
++ + spec->type_str;
++ return false;
++ }
++ }
++
++ return true;
++}
++
++static int attributeIndex(const QString &name)
++{
++ for (unsigned i = 0; i < g_oper_spec_rows; ++i) {
++ if (name == g_oper_spec_names[i])
++ return i;
++ }
++ return -1;
++}
++
++static QString decodeEntityValue(QString literal)
++{
++ QString result;
++
++ while (!literal.isEmpty()) {
++
++ if (!literal.startsWith("&#")) {
++ qWarning(("decodeEntityValue(): bad entity literal: \"" + literal + "\"").toLatin1().data());
++ return QString::null;
++ }
++
++ literal = literal.right(literal.length() - 2);
++
++ int i = literal.indexOf(';');
++ if (i == -1) {
++ qWarning(("decodeEntityValue(): bad entity literal: \"" + literal + "\"").toLatin1().data());
++ return QString::null;
++ }
++
++ QString char_code = literal.left(i);
++ literal = literal.right(literal.length() - i - 1);
++
++ if (char_code.isEmpty()) {
++ qWarning(("decodeEntityValue(): bad entity literal: \"" + literal + "\"").toLatin1().data());
++ return QString::null;
++ }
++
++ if (char_code.at(0) == 'x') {
++ char_code = char_code.right(char_code.length() - 1);
++ bool ok;
++ unsigned c = char_code.toUInt(&ok, 16);
++ if (!ok) {
++ qWarning(("decodeEntityValue(): bad entity literal: \"" + literal + "\"").toLatin1().data());
++ return QString::null;
++ }
++ result += QChar(c);
++ }
++ else {
++ bool ok;
++ unsigned c = char_code.toUInt(&ok, 10);
++ if (!ok) {
++ qWarning(("decodeEntityValue(): bad entity literal: \"" + literal + "\"").toLatin1().data());
++ return QString::null;
++ }
++ result += QChar(c);
++ }
++ }
++
++ return result;
++}
++
++static const EntitySpec *searchEntitySpecData(const QString &value, const EntitySpec *from = 0)
++{
++ const EntitySpec *ent = from;
++ if (ent == 0)
++ ent = g_xml_entity_data;
++ for (; ent->name != 0; ++ent) {
++ QString ent_value = decodeEntityValue(ent->value);
++ if (value == ent_value)
++ return ent;
++ }
++ return 0;
++}
++
++struct OperSpecSearchResult
++{
++ OperSpecSearchResult() { prefix_form = infix_form = postfix_form = 0; }
++
++ const OperSpec *prefix_form,
++ *infix_form,
++ *postfix_form;
++
++ const OperSpec *&getForm(Mml::FormType f);
++ bool haveForm(Mml::FormType f)
++ { return getForm(f) != 0; }
++ void addForm(const OperSpec *spec)
++ { getForm(spec->form) = spec; }
++};
++
++const OperSpec *&OperSpecSearchResult::getForm(Mml::FormType f)
++{
++ switch (f) {
++ case Mml::PrefixForm:
++ return prefix_form;
++ case Mml::InfixForm:
++ return infix_form;
++ case Mml::PostfixForm:
++ return postfix_form;
++ }
++ return postfix_form; // just to avoid warning
++}
++
++/*
++ Searches g_oper_spec_data and returns any instance of operator name. There may
++ be more instances, but since the list is sorted, they will be next to each other.
++*/
++static const OperSpec *searchOperSpecData(const QString &name)
++{
++ const char *name_latin1 = name.toLatin1().data();
++
++ // binary search
++ // establish invariant g_oper_spec_data[begin].name < name < g_oper_spec_data[end].name
++
++ int cmp = qstrcmp(name_latin1, g_oper_spec_data[0].name);
++ if (cmp < 0)
++ return 0;
++
++ if (cmp == 0)
++ return g_oper_spec_data;
++
++ uint begin = 0;
++ uint end = g_oper_spec_count;
++
++ // invariant holds
++ while (end - begin > 1) {
++ uint mid = (begin + end)/2;
++
++ const OperSpec *spec = g_oper_spec_data + mid;
++ int cmp = qstrcmp(name_latin1, spec->name);
++ if (cmp < 0)
++ end = mid;
++ else if (cmp > 0)
++ begin = mid;
++ else
++ return spec;
++ }
++
++ return 0;
++}
++
++/*
++ This searches g_oper_spec_data until at least one name in name_list is found with FormType form,
++ or until name_list is exhausted. The idea here is that if we don't find the operator in the
++ specified form, we still want to use some other available form of that operator.
++*/
++static OperSpecSearchResult _mmlFindOperSpec(const QStringList &name_list, Mml::FormType form)
++{
++ OperSpecSearchResult result;
++
++ QStringList::const_iterator it = name_list.begin();
++ for (; it != name_list.end(); ++it) {
++ const QString &name = *it;
++
++ const OperSpec *spec = searchOperSpecData(name);
++
++ if (spec == 0)
++ continue;
++
++ const char *name_latin1 = name.toLatin1().data();
++
++ // backtrack to the first instance of name
++ while (spec > g_oper_spec_data && qstrcmp((spec - 1)->name, name_latin1) == 0)
++ --spec;
++
++ // iterate over instances of name until the instances are exhausted or until we
++ // find an instance in the specified form.
++ do {
++ result.addForm(spec++);
++ if (result.haveForm(form))
++ break;
++ } while (qstrcmp(spec->name, name_latin1) == 0);
++
++ if (result.haveForm(form))
++ break;
++ }
++
++ return result;
++}
++
++/*
++ text is a string between <mo> and </mo>. It can be a character ('+'), an
++ entity reference ("∞") or a character reference ("∞"). Our
++ job is to find an operator spec in the operator dictionary (g_oper_spec_data)
++ that matches text. Things are further complicated by the fact, that many
++ operators come in several forms (prefix, infix, postfix).
++
++ If available, this function returns an operator spec matching text in the specified
++ form. If such operator is not available, returns an operator spec that matches
++ text, but of some other form in the preference order specified by the MathML spec.
++ If that's not available either, returns the default operator spec.
++*/
++static const OperSpec *mmlFindOperSpec(const QString &text, Mml::FormType form)
++{
++ QStringList name_list;
++ name_list.append(text);
++
++ // First, just try to find text in the operator dictionary.
++ OperSpecSearchResult result = _mmlFindOperSpec(name_list, form);
++
++ if (!result.haveForm(form)) {
++ // Try to find other names for the operator represented by text.
++
++ const EntitySpec *ent = 0;
++ for (;;) {
++ ent = searchEntitySpecData(text, ent);
++ if (ent == 0)
++ break;
++ name_list.append('&' + QString(ent->name) + ';');
++ ++ent;
++ }
++
++ result = _mmlFindOperSpec(name_list, form);
++ }
++
++ const OperSpec *spec = result.getForm(form);
++ if (spec != 0)
++ return spec;
++
++ spec = result.getForm(Mml::InfixForm);
++ if (spec != 0)
++ return spec;
++
++ spec = result.getForm(Mml::PostfixForm);
++ if (spec != 0)
++ return spec;
++
++ spec = result.getForm(Mml::PrefixForm);
++ if (spec != 0)
++ return spec;
++
++ return &g_oper_spec_defaults;
++}
++
++static QString mmlDictAttribute(const QString &name, const OperSpec *spec)
++{
++ int i = attributeIndex(name);
++ if (i == -1)
++ return QString::null;
++ else
++ return spec->attributes[i];
++}
++
++static uint interpretMathVariant(const QString &value, bool *ok)
++{
++ struct MathVariantValue {
++ const char *value;
++ uint mv;
++ };
++
++ static const MathVariantValue g_mv_data[] =
++ {
++ { "normal", Mml::NormalMV },
++ { "bold", Mml::BoldMV },
++ { "italic", Mml::ItalicMV },
++ { "bold-italic", Mml::BoldMV | Mml::ItalicMV },
++ { "double-struck", Mml::DoubleStruckMV },
++ { "bold-fraktur", Mml::BoldMV | Mml::FrakturMV },
++ { "script", Mml::ScriptMV },
++ { "bold-script", Mml::BoldMV | Mml::ScriptMV },
++ { "fraktur", Mml::FrakturMV },
++ { "sans-serif", Mml::SansSerifMV },
++ { "bold-sans-serif", Mml::BoldMV | Mml::SansSerifMV },
++ { "sans-serif-italic", Mml::SansSerifMV | Mml::ItalicMV },
++ { "sans-serif-bold-italic", Mml::SansSerifMV | Mml::ItalicMV | Mml::BoldMV },
++ { "monospace", Mml::MonospaceMV },
++ { 0, 0 }
++ };
++
++ const MathVariantValue *v = g_mv_data;
++ for (; v->value != 0; ++v) {
++ if (value == v->value) {
++ if (ok != 0)
++ *ok = true;
++ return v->mv;
++ }
++ }
++
++ if (ok != 0)
++ *ok = false;
++
++ qWarning("interpretMathVariant(): could not parse value: \"%s\"", value.toLatin1().data());
++
++ return Mml::NormalMV;
++}
++
++static Mml::FormType interpretForm(const QString &value, bool *ok)
++{
++ if (ok != 0)
++ *ok = true;
++
++ if (value == "prefix")
++ return Mml::PrefixForm;
++ if (value == "infix")
++ return Mml::InfixForm;
++ if (value == "postfix")
++ return Mml::PostfixForm;
++
++ if (ok != 0)
++ *ok = false;
++
++ qWarning("interpretForm(): could not parse value \"%s\"", value.toLatin1().data());
++ return Mml::InfixForm;
++}
++
++static Mml::ColAlign interpretColAlign(const QString &value_list, uint colnum, bool *ok)
++{
++ QString value = interpretListAttr(value_list, colnum, "center");
++
++ if (ok != 0)
++ *ok = true;
++
++ if (value == "left")
++ return Mml::ColAlignLeft;
++ if (value == "right")
++ return Mml::ColAlignRight;
++ if (value == "center")
++ return Mml::ColAlignCenter;
++
++ if (ok != 0)
++ *ok = false;
++
++ qWarning("interpretColAlign(): could not parse value \"%s\"", value.toLatin1().data());
++ return Mml::ColAlignCenter;
++}
++
++static Mml::RowAlign interpretRowAlign(const QString &value_list, uint rownum, bool *ok)
++{
++ QString value = interpretListAttr(value_list, rownum, "axis");
++
++ if (ok != 0)
++ *ok = true;
++
++ if (value == "top")
++ return Mml::RowAlignTop;
++ if (value == "center")
++ return Mml::RowAlignCenter;
++ if (value == "bottom")
++ return Mml::RowAlignBottom;
++ if (value == "baseline")
++ return Mml::RowAlignBaseline;
++ if (value == "axis")
++ return Mml::RowAlignAxis;
++
++ if (ok != 0)
++ *ok = false;
++
++ qWarning("interpretRowAlign(): could not parse value \"%s\"", value.toLatin1().data());
++ return Mml::RowAlignAxis;
++}
++
++static QString interpretListAttr(const QString &value_list, int idx, const QString &def)
++{
++ QStringList l = value_list.split(' ');
++
++ if (l.count() == 0)
++ return def;
++
++ if (l.count() <= idx)
++ return l[l.count() - 1];
++ else
++ return l[idx];
++}
++
++static Mml::FrameType interpretFrameType(const QString &value_list, uint idx, bool *ok)
++{
++ if (ok != 0)
++ *ok = true;
++
++ QString value = interpretListAttr(value_list, idx, "none");
++
++ if (value == "none")
++ return Mml::FrameNone;
++ if (value == "solid")
++ return Mml::FrameSolid;
++ if (value == "dashed")
++ return Mml::FrameDashed;
++
++ if (ok != 0)
++ *ok = false;
++
++ qWarning("interpretFrameType(): could not parse value \"%s\"", value.toLatin1().data());
++ return Mml::FrameNone;
++}
++
++
++static Mml::FrameSpacing interpretFrameSpacing(const QString &value_list, int em, int ex, bool *ok)
++{
++ Mml::FrameSpacing fs;
++
++ QStringList l = value_list.split(' ');
++ if (l.count() != 2) {
++ qWarning("interpretFrameSpacing: could not parse value \"%s\"", value_list.toLatin1().data());
++ if (ok != 0)
++ *ok = false;
++ return Mml::FrameSpacing((int)(0.4*em), (int)(0.5*ex));
++ }
++
++ bool hor_ok, ver_ok;
++ fs.m_hor = interpretSpacing(l[0], em, ex, &hor_ok);
++ fs.m_ver = interpretSpacing(l[1], em, ex, &ver_ok);
++
++ if (ok != 0)
++ *ok = hor_ok && ver_ok;
++
++ return fs;
++}
++
++static QFont interpretDepreciatedFontAttr(const MmlAttributeMap &font_attr, QFont &fn, int em, int ex)
++{
++ if (font_attr.contains("fontsize")) {
++ QString value = font_attr["fontsize"];
++
++ for (;;) {
++
++ bool ok;
++ int ptsize = interpretPointSize(value, &ok);
++ if (ok) {
++ fn.setPointSize(ptsize);
++ break;
++ }
++
++ ptsize = interpretPercentSpacing(value, fn.pointSize(), &ok);
++ if (ok) {
++ fn.setPointSize(ptsize);
++ break;
++ }
++
++ int size = interpretSpacing(value, em, ex, &ok);
++ if (ok) {
++ fn.setPixelSize(size);
++ break;
++ }
++
++ break;
++ }
++ }
++
++ if (font_attr.contains("fontweight")) {
++ QString value = font_attr["fontweight"];
++ if (value == "normal")
++ fn.setBold(false);
++ else if (value == "bold")
++ fn.setBold(true);
++ else
++ qWarning("interpretDepreciatedFontAttr(): could not parse fontweight \"%s\"", value.toLatin1().data());
++ }
++
++ if (font_attr.contains("fontstyle")) {
++ QString value = font_attr["fontstyle"];
++ if (value == "normal")
++ fn.setItalic(false);
++ else if (value == "italic")
++ fn.setItalic(true);
++ else
++ qWarning("interpretDepreciatedFontAttr(): could not parse fontstyle \"%s\"", value.toLatin1().data());
++ }
++
++ if (font_attr.contains("fontfamily")) {
++ QString value = font_attr["fontfamily"];
++ fn.setFamily(value);
++ }
++
++ return fn;
++}
++
++static QFont interpretMathSize(QString value, QFont &fn, int em, int ex, bool *ok)
++{
++ if (ok != 0)
++ *ok = true;
++
++ if (value == "small") {
++ fn.setPointSize((int)(fn.pointSize()*0.7));
++ return fn;
++ }
++
++ if (value == "normal")
++ return fn;
++
++ if (value == "big") {
++ fn.setPointSize((int)(fn.pointSize()*1.5));
++ return fn;
++ }
++
++ bool size_ok;
++
++ int ptsize = interpretPointSize(value, &size_ok);
++ if (size_ok) {
++ fn.setPointSize(ptsize);
++ return fn;
++ }
++
++ int size = interpretSpacing(value, em, ex, &size_ok);
++ if (size_ok) {
++ fn.setPixelSize(size);
++ return fn;
++ }
++
++ if (ok != 0)
++ *ok = false;
++ qWarning("interpretMathSize(): could not parse mathsize \"%s\"", value.toLatin1().data());
++ return fn;
++}
++
++/*!
++ \class QtMmlDocument
++
++ \brief The QtMmlDocument class renders mathematical formulas written in MathML 2.0.
++
++ This class provides a direct API to the rendering engine used by
++ QtMmlWidget. It can be used to paint MathML inside other widgets.
++
++ All methods work the same as the corresponding methods in QtMmlWidget.
++*/
++
++/*!
++ Constructs an empty MML document.
++*/
++QtMmlDocument::QtMmlDocument()
++{
++ m_doc = new MmlDocument;
++}
++
++/*!
++ Destroys the MML document.
++*/
++QtMmlDocument::~QtMmlDocument()
++{
++ delete m_doc;
++}
++
++/*!
++ Clears the contents of this MML document.
++*/
++void QtMmlDocument::clear()
++{
++ m_doc->clear();
++}
++
++/*!
++ Sets the MathML expression to be rendered. The expression is given
++ in the string \a text. If the expression is successfully parsed,
++ this method returns true; otherwise it returns false. If an error
++ occured \a errorMsg is set to a diagnostic message, while \a
++ errorLine and \a errorColumn contain the location of the error.
++ Any of \a errorMsg, \a errorLine and \a errorColumn may be 0,
++ in which case they are not set.
++
++ \a text should contain MathML 2.0 presentation markup elements enclosed
++ in a <math> element.
++*/
++bool QtMmlDocument::setContent(QString text, QString *errorMsg,
++ int *errorLine, int *errorColumn)
++{
++ return m_doc->setContent(text, errorMsg, errorLine, errorColumn);
++}
++
++/*!
++ Renders this MML document with the painter \a p at position \a pos.
++*/
++void QtMmlDocument::paint(QPainter *p, const QPoint &pos) const
++{
++ m_doc->paint(p, pos);
++}
++
++/*!
++ Returns the size of this MML document, as rendered, in pixels.
++*/
++QSize QtMmlDocument::size() const
++{
++ return m_doc->size();
++}
++
++/*!
++ Returns the name of the font used to render the font \a type.
++
++ \sa setFontName() setBaseFontPointSize() baseFontPointSize() QtMmlWidget::MmlFont
++*/
++QString QtMmlDocument::fontName(QtMmlWidget::MmlFont type) const
++{
++ return m_doc->fontName(type);
++}
++
++/*!
++ Sets the name of the font used to render the font \a type to \a name.
++
++ \sa fontName() setBaseFontPointSize() baseFontPointSize() QtMmlWidget::MmlFont
++*/
++void QtMmlDocument::setFontName(QtMmlWidget::MmlFont type, const QString &name)
++{
++ m_doc->setFontName(type, name);
++}
++
++/*!
++ Returns the point size of the font used to render expressions
++ whose scriptlevel is 0.
++
++ \sa setBaseFontPointSize() fontName() setFontName()
++*/
++int QtMmlDocument::baseFontPointSize() const
++{
++ return m_doc->baseFontPointSize();
++}
++
++/*!
++ Sets the point \a size of the font used to render expressions
++ whose scriptlevel is 0.
++
++ \sa baseFontPointSize() fontName() setFontName()
++*/
++void QtMmlDocument::setBaseFontPointSize(int size)
++{
++ m_doc->setBaseFontPointSize(size);
++}
+--- /dev/null
++++ copasi-4.8.35/copasi/mml/qtmmlwidget.h
+@@ -0,0 +1,124 @@
++/****************************************************************************
++**
++** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
++** All rights reserved.
++** Contact: Nokia Corporation (qt-info at nokia.com)
++**
++** This file is part of a Qt Solutions component.
++**
++** Commercial Usage
++** Licensees holding valid Qt Commercial licenses may use this file in
++** accordance with the Qt Solutions Commercial License Agreement provided
++** with the Software or, alternatively, in accordance with the terms
++** contained in a written agreement between you and Nokia.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 2.1 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 2.1 requirements
++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Nokia gives you certain
++** additional rights. These rights are described in the Nokia Qt LGPL
++** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
++** package.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 3.0 as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU General Public License version 3.0 requirements will be
++** met: http://www.gnu.org/copyleft/gpl.html.
++**
++** Please note Third Party Software included with Qt Solutions may impose
++** additional restrictions and it is the user's responsibility to ensure
++** that they have met the licensing requirements of the GPL, LGPL, or Qt
++** Solutions Commercial license and the relevant license of the Third
++** Party Software they are using.
++**
++** If you are unsure which license is appropriate for your use, please
++** contact Nokia at qt-info at nokia.com.
++**
++****************************************************************************/
++
++#ifndef QTMMLWIDGET_H
++#define QTMMLWIDGET_H
++
++#include <QtGui/QFrame>
++#include <QtXml/QtXml>
++
++class MmlDocument;
++
++#if defined(Q_WS_WIN)
++# if !defined(QT_QTMMLWIDGET_EXPORT) && !defined(QT_QTMMLWIDGET_IMPORT)
++# define QT_QTMMLWIDGET_EXPORT
++# elif defined(QT_QTMMLWIDGET_IMPORT)
++# if defined(QT_QTMMLWIDGET_EXPORT)
++# undef QT_QTMMLWIDGET_EXPORT
++# endif
++# define QT_QTMMLWIDGET_EXPORT __declspec(dllimport)
++# elif defined(QT_QTMMLWIDGET_EXPORT)
++# undef QT_QTMMLWIDGET_EXPORT
++# define QT_QTMMLWIDGET_EXPORT __declspec(dllexport)
++# endif
++#else
++# define QT_QTMMLWIDGET_EXPORT
++#endif
++
++class QT_QTMMLWIDGET_EXPORT QtMmlWidget : public QFrame
++{
++ public:
++ enum MmlFont { NormalFont, FrakturFont, SansSerifFont, ScriptFont,
++ MonospaceFont, DoublestruckFont };
++
++ QtMmlWidget(QWidget *parent = 0);
++ ~QtMmlWidget();
++
++ QString fontName(MmlFont type) const;
++ void setFontName(MmlFont type, const QString &name);
++ int baseFontPointSize() const;
++ void setBaseFontPointSize(int size);
++
++ bool setContent(const QString &text, QString *errorMsg = 0,
++ int *errorLine = 0, int *errorColumn = 0);
++ void dump() const;
++ virtual QSize sizeHint() const;
++
++ void setDrawFrames(bool b);
++ bool drawFrames() const;
++
++ void clear();
++
++ protected:
++ virtual void paintEvent(QPaintEvent *e);
++
++ private:
++ MmlDocument *m_doc;
++};
++
++
++class QT_QTMMLWIDGET_EXPORT QtMmlDocument
++{
++public:
++ QtMmlDocument();
++ ~QtMmlDocument();
++ void clear();
++
++ bool setContent(QString text, QString *errorMsg = 0,
++ int *errorLine = 0, int *errorColumn = 0);
++ void paint(QPainter *p, const QPoint &pos) const;
++ QSize size() const;
++
++ QString fontName(QtMmlWidget::MmlFont type) const;
++ void setFontName(QtMmlWidget::MmlFont type, const QString &name);
++
++ int baseFontPointSize() const;
++ void setBaseFontPointSize(int size);
++private:
++ MmlDocument *m_doc;
++};
++
++#endif
Added: trunk/packages/copasi/trunk/debian/patches/series
===================================================================
--- trunk/packages/copasi/trunk/debian/patches/series (rev 0)
+++ trunk/packages/copasi/trunk/debian/patches/series 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1 @@
+main.patch
Added: trunk/packages/copasi/trunk/debian/rules
===================================================================
--- trunk/packages/copasi/trunk/debian/rules (rev 0)
+++ trunk/packages/copasi/trunk/debian/rules 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1,32 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+export QMAKE_ARG="DEFINES+=HAVE_MML"
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/debhelper.mk
+
+DEB_CONFIGURE_EXTRA_FLAGS := --enable-release \
+ --enable-python \
+ --enable-java \
+ --enable-octave \
+ --enable-r \
+ --with-qwt=/usr \
+ --with-qwt3d=/usr \
+ --with-lapack=/usr \
+ --with-python=/usr \
+ --with-sbml=/usr \
+ --with-expat=/usr \
+ --with-raptor=/usr \
+ --with-python-libs=/usr/lib/python2.7 \
+ --with-python-includes=/usr/includes/python.27
+
+makebuilddir::
+ autoconf
+ mkdir -p debian/tmp
Property changes on: trunk/packages/copasi/trunk/debian/rules
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/packages/copasi/trunk/debian/source/format
===================================================================
--- trunk/packages/copasi/trunk/debian/source/format (rev 0)
+++ trunk/packages/copasi/trunk/debian/source/format 2012-01-29 09:23:35 UTC (rev 9493)
@@ -0,0 +1 @@
+3.0 (quilt)
More information about the debian-med-commit
mailing list