/**************************************************************************** ** ** This file is part of a Qt Solutions component. ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Qt Software Information (qt-info@nokia.com) ** ** 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.0, 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 the sales department at qt-sales@nokia.com. ** ****************************************************************************/ #include #include #include #include #include #include #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 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 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 &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(); 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 = "\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(n); } MmlNode *MmlNode::firstSibling() const { const MmlNode *n = this; while (!n->isFirstSibling()) n = n->previousSibling(); return const_cast(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; 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; 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 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.trimmed(); 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.boundingRect(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 &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 &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(); // if (node == 0) return ColAlignCenter; uint colnum = colNum(); val = node->explicitAttribute("columnalign"); if (!val.isNull()) return interpretColAlign(val, colnum, 0); node = node->parent(); // 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(); // if (node == 0) return RowAlignAxis; uint rownum = rowNum(); val = node->explicitAttribute("rowalign"); if (!val.isNull()) return interpretRowAlign(val, rownum, 0); node = node->parent(); // 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 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 = "name != 0; ++ent) { result += "\tname) + " \"" + 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; return QString::null; } literal = literal.right(literal.length() - 2); int i = literal.indexOf(';'); if (i == -1) { qWarning() << "decodeEntityValue(): bad entity literal: " << literal; 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; 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; return QString::null; } result += QChar(c); } else { bool ok; unsigned c = char_code.toUInt(&ok, 10); if (!ok) { qWarning() << "decodeEntityValue(): bad entity literal: " << literal; 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 and . 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 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); }