summaryrefslogtreecommitdiff
path: root/Source/WebCore/mathml
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/mathml')
-rw-r--r--Source/WebCore/mathml/MathMLAllInOne.cpp42
-rw-r--r--Source/WebCore/mathml/MathMLAnnotationElement.cpp107
-rw-r--r--Source/WebCore/mathml/MathMLAnnotationElement.h49
-rw-r--r--Source/WebCore/mathml/MathMLElement.cpp156
-rw-r--r--Source/WebCore/mathml/MathMLElement.h110
-rw-r--r--Source/WebCore/mathml/MathMLFractionElement.cpp117
-rw-r--r--Source/WebCore/mathml/MathMLFractionElement.h60
-rw-r--r--Source/WebCore/mathml/MathMLInlineContainerElement.cpp94
-rw-r--r--Source/WebCore/mathml/MathMLMathElement.cpp53
-rw-r--r--Source/WebCore/mathml/MathMLMathElement.h23
-rw-r--r--[-rwxr-xr-x]Source/WebCore/mathml/MathMLMencloseElement.cpp171
-rw-r--r--[-rwxr-xr-x]Source/WebCore/mathml/MathMLMencloseElement.h54
-rw-r--r--Source/WebCore/mathml/MathMLOperatorDictionary.cpp1143
-rw-r--r--Source/WebCore/mathml/MathMLOperatorDictionary.h60
-rw-r--r--Source/WebCore/mathml/MathMLOperatorElement.cpp271
-rw-r--r--Source/WebCore/mathml/MathMLOperatorElement.h81
-rw-r--r--Source/WebCore/mathml/MathMLPaddedElement.cpp97
-rw-r--r--Source/WebCore/mathml/MathMLPaddedElement.h57
-rw-r--r--Source/WebCore/mathml/MathMLPresentationElement.cpp396
-rw-r--r--Source/WebCore/mathml/MathMLPresentationElement.h73
-rw-r--r--Source/WebCore/mathml/MathMLRowElement.cpp86
-rw-r--r--Source/WebCore/mathml/MathMLRowElement.h (renamed from Source/WebCore/mathml/MathMLInlineContainerElement.h)28
-rw-r--r--Source/WebCore/mathml/MathMLScriptsElement.cpp76
-rw-r--r--Source/WebCore/mathml/MathMLScriptsElement.h53
-rw-r--r--Source/WebCore/mathml/MathMLSelectElement.cpp111
-rw-r--r--Source/WebCore/mathml/MathMLSelectElement.h30
-rw-r--r--Source/WebCore/mathml/MathMLSpaceElement.cpp (renamed from Source/WebCore/mathml/MathMLTextElement.cpp)56
-rw-r--r--Source/WebCore/mathml/MathMLSpaceElement.h54
-rw-r--r--Source/WebCore/mathml/MathMLTokenElement.cpp93
-rw-r--r--Source/WebCore/mathml/MathMLTokenElement.h (renamed from Source/WebCore/mathml/MathMLTextElement.h)33
-rw-r--r--Source/WebCore/mathml/MathMLUnderOverElement.cpp76
-rw-r--r--Source/WebCore/mathml/MathMLUnderOverElement.h51
-rw-r--r--Source/WebCore/mathml/MathMLUnknownElement.h48
-rw-r--r--Source/WebCore/mathml/mathattrs.in16
-rw-r--r--Source/WebCore/mathml/mathtags.in82
35 files changed, 3661 insertions, 446 deletions
diff --git a/Source/WebCore/mathml/MathMLAllInOne.cpp b/Source/WebCore/mathml/MathMLAllInOne.cpp
new file mode 100644
index 000000000..cc2563d96
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLAllInOne.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
+
+#include "MathMLAnnotationElement.cpp"
+#include "MathMLElement.cpp"
+#include "MathMLFractionElement.cpp"
+#include "MathMLMathElement.cpp"
+#include "MathMLMencloseElement.cpp"
+#include "MathMLOperatorDictionary.cpp"
+#include "MathMLOperatorElement.cpp"
+#include "MathMLPaddedElement.cpp"
+#include "MathMLPresentationElement.cpp"
+#include "MathMLRowElement.cpp"
+#include "MathMLScriptsElement.cpp"
+#include "MathMLSelectElement.cpp"
+#include "MathMLTokenElement.cpp"
+#include "MathMLUnderOverElement.cpp"
+
diff --git a/Source/WebCore/mathml/MathMLAnnotationElement.cpp b/Source/WebCore/mathml/MathMLAnnotationElement.cpp
new file mode 100644
index 000000000..a7e8628ad
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLAnnotationElement.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLAnnotationElement.h"
+
+#if ENABLE(MATHML)
+
+#include "HTMLHtmlElement.h"
+#include "MathMLMathElement.h"
+#include "MathMLNames.h"
+#include "MathMLSelectElement.h"
+#include "RenderMathMLBlock.h"
+#include "SVGSVGElement.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLAnnotationElement::MathMLAnnotationElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+ ASSERT(hasTagName(annotationTag) || hasTagName(annotation_xmlTag));
+}
+
+Ref<MathMLAnnotationElement> MathMLAnnotationElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLAnnotationElement(tagName, document));
+}
+
+RenderPtr<RenderElement> MathMLAnnotationElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition& insertionPosition)
+{
+ if (hasTagName(MathMLNames::annotationTag))
+ return MathMLElement::createElementRenderer(WTFMove(style), insertionPosition);
+
+ ASSERT(hasTagName(annotation_xmlTag));
+ return createRenderer<RenderMathMLBlock>(*this, WTFMove(style));
+}
+
+bool MathMLAnnotationElement::childShouldCreateRenderer(const Node& child) const
+{
+ // For <annotation>, only text children are allowed.
+ if (hasTagName(MathMLNames::annotationTag))
+ return child.isTextNode();
+
+ // For <annotation-xml>, we follow these definitions from the HTML5 RelaxNG schema:
+ // - annotation-xml.model.mathml
+ // - annotation-xml.model.svg
+ // - annotation-xml.model.xhtml
+
+ ASSERT(hasTagName(annotation_xmlTag));
+ auto& value = attributeWithoutSynchronization(encodingAttr);
+
+ if (is<MathMLElement>(child) && (MathMLSelectElement::isMathMLEncoding(value) || MathMLSelectElement::isHTMLEncoding(value))) {
+ auto& mathmlElement = downcast<MathMLElement>(child);
+ return is<MathMLMathElement>(mathmlElement);
+ }
+
+ if (is<SVGElement>(child) && (MathMLSelectElement::isSVGEncoding(value) || MathMLSelectElement::isHTMLEncoding(value))) {
+ auto& svgElement = downcast<SVGElement>(child);
+ return is<SVGSVGElement>(svgElement);
+ }
+
+ if (is<HTMLElement>(child) && MathMLSelectElement::isHTMLEncoding(value)) {
+ auto& htmlElement = downcast<HTMLElement>(child);
+ return is<HTMLHtmlElement>(htmlElement) || (isFlowContent(htmlElement) && StyledElement::childShouldCreateRenderer(child));
+ }
+
+ return false;
+}
+
+void MathMLAnnotationElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
+{
+ if (name == MathMLNames::srcAttr || name == MathMLNames::encodingAttr) {
+ auto* parent = parentElement();
+ if (is<MathMLElement>(parent) && parent->hasTagName(semanticsTag))
+ downcast<MathMLElement>(*parent).updateSelectedChild();
+ }
+ MathMLPresentationElement::attributeChanged(name, oldValue, newValue, reason);
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLAnnotationElement.h b/Source/WebCore/mathml/MathMLAnnotationElement.h
new file mode 100644
index 000000000..4c084334b
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLAnnotationElement.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLPresentationElement.h"
+
+namespace WebCore {
+
+class MathMLAnnotationElement final : public MathMLPresentationElement {
+public:
+ static Ref<MathMLAnnotationElement> create(const QualifiedName& tagName, Document&);
+private:
+ MathMLAnnotationElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+
+ bool isSemanticAnnotation() const final { return true; }
+
+ bool childShouldCreateRenderer(const Node&) const final;
+ void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) final;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLElement.cpp b/Source/WebCore/mathml/MathMLElement.cpp
index 42fe25d8a..128b41508 100644
--- a/Source/WebCore/mathml/MathMLElement.cpp
+++ b/Source/WebCore/mathml/MathMLElement.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2010 François Sausset (sausset@gmail.com). All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,57 +27,61 @@
*/
#include "config.h"
+#include "MathMLElement.h"
#if ENABLE(MATHML)
-#include "MathMLElement.h"
-
+#include "EventHandler.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLParserIdioms.h"
#include "MathMLNames.h"
+#include "MouseEvent.h"
#include "RenderTableCell.h"
namespace WebCore {
-
+
using namespace MathMLNames;
-
+
MathMLElement::MathMLElement(const QualifiedName& tagName, Document& document)
: StyledElement(tagName, document, CreateMathMLElement)
{
}
-
-PassRefPtr<MathMLElement> MathMLElement::create(const QualifiedName& tagName, Document& document)
-{
- return adoptRef(new MathMLElement(tagName, document));
-}
-bool MathMLElement::isPresentationMathML() const
+Ref<MathMLElement> MathMLElement::create(const QualifiedName& tagName, Document& document)
{
- return hasTagName(MathMLNames::mtrTag) || hasTagName(MathMLNames::mtdTag) || hasTagName(MathMLNames::maligngroupTag) || hasTagName(MathMLNames::malignmarkTag) || hasTagName(MathMLNames::mencloseTag) || hasTagName(MathMLNames::mglyphTag) || hasTagName(MathMLNames::mlabeledtrTag) || hasTagName(MathMLNames::mlongdivTag) || hasTagName(MathMLNames::mpaddedTag) || hasTagName(MathMLNames::msTag) || hasTagName(MathMLNames::mscarriesTag) || hasTagName(MathMLNames::mscarryTag) || hasTagName(MathMLNames::msgroupTag) || hasTagName(MathMLNames::mslineTag) || hasTagName(MathMLNames::msrowTag) || hasTagName(MathMLNames::mstackTag);
+ return adoptRef(*new MathMLElement(tagName, document));
}
-int MathMLElement::colSpan() const
+unsigned MathMLElement::colSpan() const
{
if (!hasTagName(mtdTag))
- return 1;
- const AtomicString& colSpanValue = fastGetAttribute(columnspanAttr);
- return std::max(1, colSpanValue.toInt());
+ return 1u;
+ auto& colSpanValue = attributeWithoutSynchronization(columnspanAttr);
+ return std::max(1u, limitToOnlyHTMLNonNegative(colSpanValue, 1u));
}
-int MathMLElement::rowSpan() const
+unsigned MathMLElement::rowSpan() const
{
if (!hasTagName(mtdTag))
- return 1;
- const AtomicString& rowSpanValue = fastGetAttribute(rowspanAttr);
- return std::max(1, rowSpanValue.toInt());
+ return 1u;
+ auto& rowSpanValue = attributeWithoutSynchronization(rowspanAttr);
+ static const unsigned maxRowspan = 8190; // This constant comes from HTMLTableCellElement.
+ return std::max(1u, std::min(limitToOnlyHTMLNonNegative(rowSpanValue, 1u), maxRowspan));
}
void MathMLElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- if (name == rowspanAttr) {
- if (renderer() && renderer()->isTableCell() && hasTagName(mtdTag))
- toRenderTableCell(renderer())->colSpanOrRowSpanChanged();
+ if (name == hrefAttr) {
+ bool wasLink = isLink();
+ setIsLink(!value.isNull() && !shouldProhibitLinks(this));
+ if (wasLink != isLink())
+ invalidateStyleForSubtree();
+ } else if (name == rowspanAttr) {
+ if (is<RenderTableCell>(renderer()) && hasTagName(mtdTag))
+ downcast<RenderTableCell>(*renderer()).colSpanOrRowSpanChanged();
} else if (name == columnspanAttr) {
- if (renderer() && renderer()->isTableCell() && hasTagName(mtdTag))
- toRenderTableCell(renderer())->colSpanOrRowSpanChanged();
+ if (is<RenderTableCell>(renderer()) && hasTagName(mtdTag))
+ downcast<RenderTableCell>(renderer())->colSpanOrRowSpanChanged();
} else
StyledElement::parseAttribute(name, value);
}
@@ -123,23 +128,102 @@ void MathMLElement::collectStyleForPresentationAttribute(const QualifiedName& na
bool MathMLElement::childShouldCreateRenderer(const Node& child) const
{
- if (hasTagName(annotationTag))
- return child.isTextNode();
- if (hasTagName(annotation_xmlTag))
- return StyledElement::childShouldCreateRenderer(child);
+ // In general, only MathML children are allowed. Text nodes are only visible in token MathML elements.
+ return is<MathMLElement>(child);
+}
+
+bool MathMLElement::willRespondToMouseClickEvents()
+{
+ return isLink() || StyledElement::willRespondToMouseClickEvents();
+}
+
+void MathMLElement::defaultEventHandler(Event& event)
+{
+ if (isLink()) {
+ if (focused() && isEnterKeyKeydownEvent(event)) {
+ event.setDefaultHandled();
+ dispatchSimulatedClick(&event);
+ return;
+ }
+ if (MouseEvent::canTriggerActivationBehavior(event)) {
+ auto& href = attributeWithoutSynchronization(hrefAttr);
+ const auto& url = stripLeadingAndTrailingHTMLSpaces(href);
+ event.setDefaultHandled();
+ if (auto* frame = document().frame())
+ frame->loader().urlSelected(document().completeURL(url), "_self", &event, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, document().shouldOpenExternalURLsPolicyToPropagate());
+ return;
+ }
+ }
+
+ StyledElement::defaultEventHandler(event);
+}
+
+bool MathMLElement::canStartSelection() const
+{
+ if (!isLink())
+ return StyledElement::canStartSelection();
+
+ return hasEditableStyle();
+}
+
+bool MathMLElement::isFocusable() const
+{
+ if (renderer() && renderer()->absoluteClippedOverflowRect().isEmpty())
+ return false;
+
+ return StyledElement::isFocusable();
+}
+
+bool MathMLElement::isKeyboardFocusable(KeyboardEvent& event) const
+{
+ if (isFocusable() && StyledElement::supportsFocus())
+ return StyledElement::isKeyboardFocusable(event);
+
+ if (isLink())
+ return document().frame()->eventHandler().tabsToLinks(event);
+
+ return StyledElement::isKeyboardFocusable(event);
+}
+
+bool MathMLElement::isMouseFocusable() const
+{
+ // Links are focusable by default, but only allow links with tabindex or contenteditable to be mouse focusable.
+ // https://bugs.webkit.org/show_bug.cgi?id=26856
+ if (isLink())
+ return StyledElement::supportsFocus();
+
+ return StyledElement::isMouseFocusable();
+}
+
+bool MathMLElement::isURLAttribute(const Attribute& attribute) const
+{
+ return attribute.name().localName() == hrefAttr || StyledElement::isURLAttribute(attribute);
+}
- // Only create renderers for MathML elements or text. MathML prohibits non-MathML markup inside a <math> element.
- return child.isTextNode() || child.isMathMLElement();
+bool MathMLElement::supportsFocus() const
+{
+ if (hasEditableStyle())
+ return StyledElement::supportsFocus();
+ // If not a link we should still be able to focus the element if it has tabIndex.
+ return isLink() || StyledElement::supportsFocus();
+}
+
+int MathMLElement::tabIndex() const
+{
+ // Skip the supportsFocus check in StyledElement.
+ return Element::tabIndex();
}
-void MathMLElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
+StringView MathMLElement::stripLeadingAndTrailingWhitespace(const StringView& stringView)
{
- if (isSemanticAnnotation() && (name == MathMLNames::srcAttr || name == MathMLNames::encodingAttr)) {
- Element* parent = parentElement();
- if (parent && parent->isMathMLElement() && parent->hasTagName(semanticsTag))
- toMathMLElement(parent)->updateSelectedChild();
+ unsigned start = 0, stringLength = stringView.length();
+ while (stringLength > 0 && isHTMLSpace(stringView[start])) {
+ start++;
+ stringLength--;
}
- StyledElement::attributeChanged(name, oldValue, newValue, reason);
+ while (stringLength > 0 && isHTMLSpace(stringView[start + stringLength - 1]))
+ stringLength--;
+ return stringView.substring(start, stringLength);
}
}
diff --git a/Source/WebCore/mathml/MathMLElement.h b/Source/WebCore/mathml/MathMLElement.h
index 9f988a9a9..9de13d9d6 100644
--- a/Source/WebCore/mathml/MathMLElement.h
+++ b/Source/WebCore/mathml/MathMLElement.h
@@ -2,6 +2,7 @@
* Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
* Copyright (C) 2010 Apple Inc. All rights reserved.
* Copyright (C) 2010 François Sausset (sausset@gmail.com). All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,8 +26,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLElement_h
-#define MathMLElement_h
+#pragma once
#if ENABLE(MATHML)
@@ -37,43 +37,93 @@ namespace WebCore {
class MathMLElement : public StyledElement {
public:
- static PassRefPtr<MathMLElement> create(const QualifiedName& tagName, Document&);
+ static Ref<MathMLElement> create(const QualifiedName& tagName, Document&);
+
+ unsigned colSpan() const;
+ unsigned rowSpan() const;
+
+ virtual bool isMathMLToken() const { return false; }
+ virtual bool isSemanticAnnotation() const { return false; }
+ virtual bool isPresentationMathML() const { return false; }
+
+ bool hasTagName(const MathMLQualifiedName& name) const { return hasLocalName(name.localName()); }
+
+ // MathML lengths (https://www.w3.org/TR/MathML3/chapter2.html#fund.units)
+ // TeX's Math Unit is used internally for named spaces (1 mu = 1/18 em).
+ // Unitless values are interpreted as a multiple of a reference value.
+ enum class LengthType { Cm, Em, Ex, In, MathUnit, Mm, ParsingFailed, Pc, Percentage, Pt, Px, UnitLess, Infinity };
+ struct Length {
+ LengthType type { LengthType::ParsingFailed };
+ float value { 0 };
+ };
+
+ enum class BooleanValue { True, False, Default };
+
+ // These are the mathvariant values from the MathML recommendation.
+ // The special value none means that no explicit mathvariant value has been specified.
+ // Note that the numeral values are important for the computation performed in the mathVariant function of RenderMathMLToken, do not change them!
+ enum class MathVariant {
+ None = 0,
+ Normal = 1,
+ Bold = 2,
+ Italic = 3,
+ BoldItalic = 4,
+ Script = 5,
+ BoldScript = 6,
+ Fraktur = 7,
+ DoubleStruck = 8,
+ BoldFraktur = 9,
+ SansSerif = 10,
+ BoldSansSerif = 11,
+ SansSerifItalic = 12,
+ SansSerifBoldItalic = 13,
+ Monospace = 14,
+ Initial = 15,
+ Tailed = 16,
+ Looped = 17,
+ Stretched = 18
+ };
+
+ virtual std::optional<bool> specifiedDisplayStyle() { return std::nullopt; }
+ virtual std::optional<MathVariant> specifiedMathVariant() { return std::nullopt; }
+
+ virtual void updateSelectedChild() { }
- int colSpan() const;
- int rowSpan() const;
+protected:
+ MathMLElement(const QualifiedName& tagName, Document&);
- bool isMathMLToken() const
- {
- return hasTagName(MathMLNames::miTag) || hasTagName(MathMLNames::mnTag) || hasTagName(MathMLNames::moTag) || hasTagName(MathMLNames::msTag) || hasTagName(MathMLNames::mtextTag);
- }
+ static StringView stripLeadingAndTrailingWhitespace(const StringView&);
- bool isSemanticAnnotation() const
- {
- return hasTagName(MathMLNames::annotationTag) || hasTagName(MathMLNames::annotation_xmlTag);
- }
+ void parseAttribute(const QualifiedName&, const AtomicString&) override;
+ bool childShouldCreateRenderer(const Node&) const override;
- virtual bool isPresentationMathML() const;
+ bool isPresentationAttribute(const QualifiedName&) const override;
+ void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) override;
-protected:
- MathMLElement(const QualifiedName& tagName, Document&);
+ bool willRespondToMouseClickEvents() override;
+ void defaultEventHandler(Event&) override;
- virtual void parseAttribute(const QualifiedName&, const AtomicString&) override;
- virtual bool childShouldCreateRenderer(const Node&) const override;
- virtual void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason) override;
+private:
+ bool canStartSelection() const final;
+ bool isFocusable() const final;
+ bool isKeyboardFocusable(KeyboardEvent&) const final;
+ bool isMouseFocusable() const final;
+ bool isURLAttribute(const Attribute&) const final;
+ bool supportsFocus() const final;
+ int tabIndex() const final;
+};
- virtual bool isPresentationAttribute(const QualifiedName&) const override;
- virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) override;
-private:
+inline bool Node::hasTagName(const MathMLQualifiedName& name) const
+{
+ return isMathMLElement() && downcast<MathMLElement>(*this).hasTagName(name);
+}
- virtual void updateSelectedChild() { };
-};
+} // namespace WebCore
-void isMathMLElement(const MathMLElement&); // Catch unnecessary runtime check of type known at compile time.
-inline bool isMathMLElement(const Node& node) { return node.isMathMLElement(); }
-NODE_TYPE_CASTS(MathMLElement)
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MathMLElement)
+ static bool isType(const WebCore::Node& node) { return node.isMathMLElement(); }
+SPECIALIZE_TYPE_TRAITS_END()
-}
+#include "MathMLElementTypeHelpers.h"
#endif // ENABLE(MATHML)
-
-#endif // MathMLElement_h
diff --git a/Source/WebCore/mathml/MathMLFractionElement.cpp b/Source/WebCore/mathml/MathMLFractionElement.cpp
new file mode 100644
index 000000000..ee2181e36
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLFractionElement.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLFractionElement.h"
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLFraction.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+inline MathMLFractionElement::MathMLFractionElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+}
+
+Ref<MathMLFractionElement> MathMLFractionElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLFractionElement(tagName, document));
+}
+
+const MathMLElement::Length& MathMLFractionElement::lineThickness()
+{
+ if (m_lineThickness)
+ return m_lineThickness.value();
+
+ // The MathML3 recommendation states that "medium" is the default thickness.
+ // However, it only states that "thin" and "thick" are respectively thiner and thicker.
+ // The MathML in HTML5 implementation note suggests 50% and 200% and these values are also used in Gecko.
+ auto& thickness = attributeWithoutSynchronization(linethicknessAttr);
+ m_lineThickness = Length();
+ if (equalLettersIgnoringASCIICase(thickness, "thin")) {
+ m_lineThickness.value().type = LengthType::UnitLess;
+ m_lineThickness.value().value = .5;
+ } else if (equalLettersIgnoringASCIICase(thickness, "medium")) {
+ m_lineThickness.value().type = LengthType::UnitLess;
+ m_lineThickness.value().value = 1;
+ } else if (equalLettersIgnoringASCIICase(thickness, "thick")) {
+ m_lineThickness.value().type = LengthType::UnitLess;
+ m_lineThickness.value().value = 2;
+ } else
+ m_lineThickness = parseMathMLLength(thickness);
+ return m_lineThickness.value();
+}
+
+MathMLFractionElement::FractionAlignment MathMLFractionElement::cachedFractionAlignment(const QualifiedName& name, std::optional<FractionAlignment>& alignment)
+{
+ if (alignment)
+ return alignment.value();
+
+ auto& value = attributeWithoutSynchronization(name);
+ if (equalLettersIgnoringASCIICase(value, "left"))
+ alignment = FractionAlignmentLeft;
+ else if (equalLettersIgnoringASCIICase(value, "right"))
+ alignment = FractionAlignmentRight;
+ else
+ alignment = FractionAlignmentCenter;
+ return alignment.value();
+}
+
+MathMLFractionElement::FractionAlignment MathMLFractionElement::numeratorAlignment()
+{
+ return cachedFractionAlignment(numalignAttr, m_numeratorAlignment);
+}
+
+MathMLFractionElement::FractionAlignment MathMLFractionElement::denominatorAlignment()
+{
+ return cachedFractionAlignment(denomalignAttr, m_denominatorAlignment);
+}
+
+void MathMLFractionElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == linethicknessAttr)
+ m_lineThickness = std::nullopt;
+ else if (name == numalignAttr)
+ m_numeratorAlignment = std::nullopt;
+ else if (name == denomalignAttr)
+ m_denominatorAlignment = std::nullopt;
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+RenderPtr<RenderElement> MathMLFractionElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(MathMLNames::mfracTag));
+ return createRenderer<RenderMathMLFraction>(*this, WTFMove(style));
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLFractionElement.h b/Source/WebCore/mathml/MathMLFractionElement.h
new file mode 100644
index 000000000..cfff5b6b3
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLFractionElement.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLPresentationElement.h"
+
+namespace WebCore {
+
+class MathMLFractionElement final : public MathMLPresentationElement {
+public:
+ static Ref<MathMLFractionElement> create(const QualifiedName& tagName, Document&);
+ const Length& lineThickness();
+ enum FractionAlignment {
+ FractionAlignmentCenter,
+ FractionAlignmentLeft,
+ FractionAlignmentRight
+ };
+ FractionAlignment numeratorAlignment();
+ FractionAlignment denominatorAlignment();
+
+private:
+ MathMLFractionElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+
+ FractionAlignment cachedFractionAlignment(const QualifiedName&, std::optional<FractionAlignment>&);
+
+ std::optional<Length> m_lineThickness;
+ std::optional<FractionAlignment> m_numeratorAlignment;
+ std::optional<FractionAlignment> m_denominatorAlignment;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLInlineContainerElement.cpp b/Source/WebCore/mathml/MathMLInlineContainerElement.cpp
deleted file mode 100644
index edc809cd1..000000000
--- a/Source/WebCore/mathml/MathMLInlineContainerElement.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
- * Copyright (C) 2010 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if ENABLE(MATHML)
-
-#include "MathMLInlineContainerElement.h"
-
-#include "MathMLNames.h"
-#include "RenderMathMLBlock.h"
-#include "RenderMathMLFenced.h"
-#include "RenderMathMLFraction.h"
-#include "RenderMathMLMenclose.h"
-#include "RenderMathMLRoot.h"
-#include "RenderMathMLRow.h"
-#include "RenderMathMLScripts.h"
-#include "RenderMathMLSquareRoot.h"
-#include "RenderMathMLUnderOver.h"
-
-namespace WebCore {
-
-using namespace MathMLNames;
-
-MathMLInlineContainerElement::MathMLInlineContainerElement(const QualifiedName& tagName, Document& document)
- : MathMLElement(tagName, document)
-{
-}
-
-PassRefPtr<MathMLInlineContainerElement> MathMLInlineContainerElement::create(const QualifiedName& tagName, Document& document)
-{
- return adoptRef(new MathMLInlineContainerElement(tagName, document));
-}
-
-RenderPtr<RenderElement> MathMLInlineContainerElement::createElementRenderer(PassRef<RenderStyle> style)
-{
- if (hasLocalName(annotation_xmlTag))
- return createRenderer<RenderMathMLRow>(*this, std::move(style));
- if (hasLocalName(merrorTag) || hasLocalName(mphantomTag) || hasLocalName(mrowTag) || hasLocalName(mstyleTag))
- return createRenderer<RenderMathMLRow>(*this, std::move(style));
- if (hasLocalName(msubTag))
- return createRenderer<RenderMathMLScripts>(*this, std::move(style));
- if (hasLocalName(msupTag))
- return createRenderer<RenderMathMLScripts>(*this, std::move(style));
- if (hasLocalName(msubsupTag))
- return createRenderer<RenderMathMLScripts>(*this, std::move(style));
- if (hasLocalName(mmultiscriptsTag))
- return createRenderer<RenderMathMLScripts>(*this, std::move(style));
- if (hasLocalName(moverTag))
- return createRenderer<RenderMathMLUnderOver>(*this, std::move(style));
- if (hasLocalName(munderTag))
- return createRenderer<RenderMathMLUnderOver>(*this, std::move(style));
- if (hasLocalName(munderoverTag))
- return createRenderer<RenderMathMLUnderOver>(*this, std::move(style));
- if (hasLocalName(mfracTag))
- return createRenderer<RenderMathMLFraction>(*this, std::move(style));
- if (hasLocalName(msqrtTag))
- return createRenderer<RenderMathMLSquareRoot>(*this, std::move(style));
- if (hasLocalName(mrootTag))
- return createRenderer<RenderMathMLRoot>(*this, std::move(style));
- if (hasLocalName(mfencedTag))
- return createRenderer<RenderMathMLFenced>(*this, std::move(style));
- if (hasLocalName(mtableTag))
- return createRenderer<RenderMathMLTable>(*this, std::move(style));
-
- return createRenderer<RenderMathMLBlock>(*this, std::move(style));
-}
-
-}
-
-#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLMathElement.cpp b/Source/WebCore/mathml/MathMLMathElement.cpp
index 6f2f389ba..783e9ff95 100644
--- a/Source/WebCore/mathml/MathMLMathElement.cpp
+++ b/Source/WebCore/mathml/MathMLMathElement.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
* Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,35 +26,65 @@
*/
#include "config.h"
+#include "MathMLMathElement.h"
#if ENABLE(MATHML)
-#include "MathMLMathElement.h"
+#include "MathMLNames.h"
#include "RenderMathMLMath.h"
namespace WebCore {
+using namespace MathMLNames;
+
inline MathMLMathElement::MathMLMathElement(const QualifiedName& tagName, Document& document)
- : MathMLInlineContainerElement(tagName, document)
+ : MathMLRowElement(tagName, document)
+{
+ setHasCustomStyleResolveCallbacks();
+}
+
+Ref<MathMLMathElement> MathMLMathElement::create(const QualifiedName& tagName, Document& document)
{
+ return adoptRef(*new MathMLMathElement(tagName, document));
}
-PassRefPtr<MathMLMathElement> MathMLMathElement::create(const QualifiedName& tagName, Document& document)
+RenderPtr<RenderElement> MathMLMathElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
{
- return adoptRef(new MathMLMathElement(tagName, document));
+ return createRenderer<RenderMathMLMath>(*this, WTFMove(style));
}
-Node::InsertionNotificationRequest MathMLMathElement::insertedInto(ContainerNode& insertionPoint)
+std::optional<bool> MathMLMathElement::specifiedDisplayStyle()
{
- // There are sibling rules in the MathML default style.
- if (insertionPoint.inDocument())
- document().styleSheetCollection().setUsesSiblingRulesOverride(true);
- return MathMLInlineContainerElement::insertedInto(insertionPoint);
+ if (cachedBooleanAttribute(displaystyleAttr, m_displayStyle) == BooleanValue::Default) {
+ // The default displaystyle value of the <math> depends on the display attribute, so we parse it here.
+ auto& value = attributeWithoutSynchronization(displayAttr);
+ if (value == "block")
+ m_displayStyle = BooleanValue::True;
+ else if (value == "inline")
+ m_displayStyle = BooleanValue::False;
+ }
+ return toOptionalBool(m_displayStyle.value());
}
-RenderPtr<RenderElement> MathMLMathElement::createElementRenderer(PassRef<RenderStyle> style)
+void MathMLMathElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- return createRenderer<RenderMathMLMath>(*this, std::move(style));
+ bool displayStyleAttribute = (name == displaystyleAttr || name == displayAttr);
+ bool mathVariantAttribute = name == mathvariantAttr;
+ if (displayStyleAttribute)
+ m_displayStyle = std::nullopt;
+ if (mathVariantAttribute)
+ m_mathVariant = std::nullopt;
+ if ((displayStyleAttribute || mathVariantAttribute) && renderer())
+ MathMLStyle::resolveMathMLStyleTree(renderer());
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+void MathMLMathElement::didAttachRenderers()
+{
+ MathMLRowElement::didAttachRenderers();
+
+ MathMLStyle::resolveMathMLStyleTree(renderer());
}
}
diff --git a/Source/WebCore/mathml/MathMLMathElement.h b/Source/WebCore/mathml/MathMLMathElement.h
index 23873e922..a1e377e39 100644
--- a/Source/WebCore/mathml/MathMLMathElement.h
+++ b/Source/WebCore/mathml/MathMLMathElement.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
* Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,26 +25,30 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLMathElement_h
-#define MathMLMathElement_h
+#pragma once
#if ENABLE(MATHML)
-#include "MathMLInlineContainerElement.h"
+
+#include "MathMLRowElement.h"
namespace WebCore {
-class MathMLMathElement : public MathMLInlineContainerElement {
+class MathMLMathElement final : public MathMLRowElement {
public:
- static PassRefPtr<MathMLMathElement> create(const QualifiedName& tagName, Document&);
+ static Ref<MathMLMathElement> create(const QualifiedName& tagName, Document&);
private:
MathMLMathElement(const QualifiedName& tagName, Document&);
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+ void didAttachRenderers() final;
+
+ bool acceptsDisplayStyleAttribute() final { return true; }
+ bool acceptsMathVariantAttribute() final { return true; }
+ std::optional<bool> specifiedDisplayStyle() final;
- virtual InsertionNotificationRequest insertedInto(ContainerNode&) override;
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
};
-
+
}
#endif // ENABLE(MATHML)
-#endif // MathMLMathElement_h
diff --git a/Source/WebCore/mathml/MathMLMencloseElement.cpp b/Source/WebCore/mathml/MathMLMencloseElement.cpp
index 4013d887d..743c4611d 100755..100644
--- a/Source/WebCore/mathml/MathMLMencloseElement.cpp
+++ b/Source/WebCore/mathml/MathMLMencloseElement.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Gurpreet Kaur (k.gurpreet@samsung.com). All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,122 +25,116 @@
*/
#include "config.h"
+#include "MathMLMencloseElement.h"
#if ENABLE(MATHML)
-#include "MathMLMencloseElement.h"
+#include "HTMLParserIdioms.h"
#include "MathMLNames.h"
-#include "RenderElement.h"
#include "RenderMathMLMenclose.h"
-#include "RenderObject.h"
-#include "TextRun.h"
-#include <wtf/Ref.h>
-#include <wtf/text/StringBuilder.h>
-
namespace WebCore {
+using namespace MathMLNames;
+
MathMLMencloseElement::MathMLMencloseElement(const QualifiedName& tagName, Document& document)
- : MathMLInlineContainerElement(tagName, document)
- , m_isRadicalValue(false)
+ : MathMLRowElement(tagName, document)
{
+ // By default we draw a longdiv.
+ clearNotations();
+ addNotation(LongDiv);
}
-PassRefPtr<MathMLMencloseElement> MathMLMencloseElement::create(const QualifiedName& tagName, Document& document)
+Ref<MathMLMencloseElement> MathMLMencloseElement::create(const QualifiedName& tagName, Document& document)
{
- return adoptRef(new MathMLMencloseElement(tagName, document));
+ return adoptRef(*new MathMLMencloseElement(tagName, document));
}
-RenderPtr<RenderElement> MathMLMencloseElement::createElementRenderer(PassRef<RenderStyle> style)
-{
- return createRenderer<RenderMathMLMenclose>(*this, std::move(style));
-}
-
-bool MathMLMencloseElement::isPresentationAttribute(const QualifiedName& name) const
+RenderPtr<RenderElement> MathMLMencloseElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
{
- if (name == MathMLNames::notationAttr)
- return true;
- return MathMLElement::isPresentationAttribute(name);
+ return createRenderer<RenderMathMLMenclose>(*this, WTFMove(style));
}
-void MathMLMencloseElement::finishParsingChildren()
+void MathMLMencloseElement::addNotationFlags(StringView notation)
{
- MathMLInlineContainerElement::finishParsingChildren();
- // When notation value is a radical and menclose does not have any child
- // then we add anonymous squareroot child to menclose so that square root
- // symbol can be rendered.
- if (m_isRadicalValue && !firstElementChild())
- renderer()->addChild(nullptr, nullptr);
+ ASSERT(m_notationFlags);
+ if (notation == "longdiv") {
+ addNotation(LongDiv);
+ } else if (notation == "roundedbox") {
+ addNotation(RoundedBox);
+ } else if (notation == "circle") {
+ addNotation(Circle);
+ } else if (notation == "left") {
+ addNotation(Left);
+ } else if (notation == "right") {
+ addNotation(Right);
+ } else if (notation == "top") {
+ addNotation(Top);
+ } else if (notation == "bottom") {
+ addNotation(Bottom);
+ } else if (notation == "updiagonalstrike") {
+ addNotation(UpDiagonalStrike);
+ } else if (notation == "downdiagonalstrike") {
+ addNotation(DownDiagonalStrike);
+ } else if (notation == "verticalstrike") {
+ addNotation(VerticalStrike);
+ } else if (notation == "horizontalstrike") {
+ addNotation(HorizontalStrike);
+ } else if (notation == "updiagonalarrow") {
+ addNotation(UpDiagonalArrow);
+ } else if (notation == "phasorangle") {
+ addNotation(PhasorAngle);
+ } else if (notation == "box") {
+ addNotation(Left);
+ addNotation(Right);
+ addNotation(Top);
+ addNotation(Bottom);
+ } else if (notation == "actuarial") {
+ addNotation(Right);
+ addNotation(Top);
+ } else if (notation == "madruwb") {
+ addNotation(Right);
+ addNotation(Bottom);
+ }
}
-void MathMLMencloseElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
+void MathMLMencloseElement::parseNotationAttribute()
{
- String val = value;
- if (val.isEmpty())
+ clearNotations();
+ if (!hasAttribute(notationAttr)) {
+ addNotation(LongDiv); // The default value is longdiv.
return;
- if (name == MathMLNames::notationAttr) {
- val.split(" ", m_notationValues);
- size_t notationValueSize = m_notationValues.size();
- for (size_t i = 0; i < notationValueSize; i++) {
- if (m_notationValues[i] == "top" || m_notationValues[i] == "longdiv") {
- if (m_notationValues[i] == "longdiv")
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingLeft, longDivLeftPadding());
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingTop, ".3ex");
- } else if (m_notationValues[i] == "bottom") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingBottom, ".3ex");
- } else if (m_notationValues[i] == "left") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderLeftStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderLeftWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingLeft, ".3ex");
- } else if (m_notationValues[i] == "right") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingRight, ".3ex");
- } else if (m_notationValues[i] == "box" || m_notationValues[i] == "roundedbox") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPadding, ".3ex");
- if (m_notationValues[i] == "roundedbox")
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRadius, ASCIILiteral("5px"));
- } else if (m_notationValues[i] == "actuarial" || m_notationValues[i] == "madruwb") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderRightWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingRight, ".3ex");
- if (m_notationValues[i] == "actuarial") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderTopWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingTop, ".3ex");
- } else if (m_notationValues[i] == "madruwb") {
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomStyle, "solid");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyBorderBottomWidth, "thin");
- addPropertyToPresentationAttributeStyle(style, CSSPropertyPaddingBottom, ".3ex");
- }
- } else if (m_notationValues[i] == "radical")
- m_isRadicalValue = true;
+ }
+ // We parse the list of whitespace-separated notation names.
+ StringView value = attributeWithoutSynchronization(notationAttr).string();
+ unsigned length = value.length();
+ unsigned start = 0;
+ while (start < length) {
+ if (isHTMLSpace(value[start])) {
+ start++;
+ continue;
}
- } else
- MathMLInlineContainerElement::collectStyleForPresentationAttribute(name, value, style);
+ unsigned end = start + 1;
+ while (end < length && !isHTMLSpace(value[end]))
+ end++;
+ addNotationFlags(value.substring(start, end - start));
+ start = end;
+ }
}
+bool MathMLMencloseElement::hasNotation(MencloseNotationFlag notationFlag)
+{
+ if (!m_notationFlags)
+ parseNotationAttribute();
+ return m_notationFlags.value() & notationFlag;
+}
-String MathMLMencloseElement::longDivLeftPadding() const
+void MathMLMencloseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- StringBuilder padding;
- float fontSize = 0;
- String closingBrace = ")";
- TextRun run(closingBrace.impl(), closingBrace.length());
- Node* node = parentNode();
- if (node && node->renderer()) {
- const Font& font = node->renderer()->style().font();
- fontSize = font.width(run);
- padding.append(String::number(fontSize));
- padding.append("px");
- }
- return padding.toString();
+ if (name == notationAttr)
+ m_notationFlags = std::nullopt;
+
+ MathMLRowElement::parseAttribute(name, value);
}
}
diff --git a/Source/WebCore/mathml/MathMLMencloseElement.h b/Source/WebCore/mathml/MathMLMencloseElement.h
index 3c0ee9095..da1d2a746 100755..100644
--- a/Source/WebCore/mathml/MathMLMencloseElement.h
+++ b/Source/WebCore/mathml/MathMLMencloseElement.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Gurpreet Kaur (k.gurpreet@samsung.com). All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,39 +24,48 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLMencloseElement_h
-#define MathMLMencloseElement_h
+#pragma once
#if ENABLE(MATHML)
-#include "MathMLInlineContainerElement.h"
+
+#include "Element.h"
+#include "MathMLRowElement.h"
namespace WebCore {
-class MathMLMencloseElement final: public MathMLInlineContainerElement {
+class MathMLMencloseElement final: public MathMLRowElement {
public:
- static PassRefPtr<MathMLMencloseElement> create(const QualifiedName& tagName, Document&);
- const Vector<String>& notationValues() const { return m_notationValues; }
- bool isRadical() const { return m_isRadicalValue; }
+ static Ref<MathMLMencloseElement> create(const QualifiedName& tagName, Document&);
+
+ enum MencloseNotationFlag {
+ LongDiv = 1 << 1,
+ RoundedBox = 1 << 2,
+ Circle = 1 << 3,
+ Left = 1 << 4,
+ Right = 1 << 5,
+ Top = 1 << 6,
+ Bottom = 1 << 7,
+ UpDiagonalStrike = 1 << 8,
+ DownDiagonalStrike = 1 << 9,
+ VerticalStrike = 1 << 10,
+ HorizontalStrike = 1 << 11,
+ UpDiagonalArrow = 1 << 12, // FIXME: updiagonalarrow is not implemented. See http://wkb.ug/127466
+ PhasorAngle = 1 << 13 // FIXME: phasorangle is not implemented. See http://wkb.ug/127466
+ // We do not implement the Radical notation. Authors should instead use the <msqrt> element.
+ };
+ bool hasNotation(MencloseNotationFlag);
private:
MathMLMencloseElement(const QualifiedName&, Document&);
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
- virtual bool isPresentationAttribute(const QualifiedName&) const override;
- virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) override;
- virtual void finishParsingChildren() override;
- String longDivLeftPadding() const;
-
- Vector<String> m_notationValues;
- bool m_isRadicalValue;
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+ void parseNotationAttribute();
+ void clearNotations() { m_notationFlags = 0; }
+ void addNotation(MencloseNotationFlag notationFlag) { m_notationFlags.value() |= notationFlag; }
+ void addNotationFlags(StringView notation);
+ std::optional<uint16_t> m_notationFlags;
};
-inline MathMLMencloseElement* toMathMLMencloseElement(Node* node)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(!node || (node->isElementNode() && toElement(node)->hasTagName(MathMLNames::mencloseTag)));
- return static_cast<MathMLMencloseElement*>(node);
-}
-
}
#endif // ENABLE(MATHML)
-#endif // MathMLMencloseElement_h
diff --git a/Source/WebCore/mathml/MathMLOperatorDictionary.cpp b/Source/WebCore/mathml/MathMLOperatorDictionary.cpp
new file mode 100644
index 000000000..6854f0dad
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLOperatorDictionary.cpp
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (C) 2015 Frederic Wang (fred.wang@free.fr). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MathMLOperatorDictionary.h"
+
+#if ENABLE(MATHML)
+
+namespace WebCore {
+
+using namespace MathMLOperatorDictionary;
+
+typedef std::pair<UChar32, Form> Key;
+struct Entry {
+ UChar32 character;
+ unsigned form : 2;
+ unsigned lspace : 3;
+ unsigned rspace : 3;
+ unsigned flags : 8;
+};
+static inline Key ExtractKey(const Entry* entry) { return Key(entry->character, static_cast<Form>(entry->form)); }
+static inline UChar32 ExtractChar(const Entry* entry) { return entry->character; }
+static inline Property ExtractProperty(const Entry& entry)
+{
+ Property property;
+ property.form = static_cast<Form>(entry.form);
+ property.leadingSpaceInMathUnit = entry.lspace;
+ property.trailingSpaceInMathUnit = entry.rspace;
+ property.flags = entry.flags;
+ return property;
+}
+
+// This table has been automatically generated from the Operator Dictionary of the MathML3 specification (appendix C).
+// Some people use the binary operator "U+2225 PARALLEL TO" as an opening and closing delimiter, so we add the corresponding stretchy prefix and postfix forms.
+static const unsigned dictionarySize = 1043;
+static const Entry dictionary[dictionarySize] = {
+ { 0x21, Postfix, 1, 0, 0}, // EXCLAMATION MARK
+ { 0x25, Infix, 3, 3, 0}, // PERCENT SIGN
+ { 0x26, Postfix, 0, 0, 0}, // AMPERSAND
+ { 0x27, Postfix, 0, 0, Accent}, // APOSTROPHE
+ { 0x28, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT PARENTHESIS
+ { 0x29, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT PARENTHESIS
+ { 0x2A, Infix, 3, 3, 0}, // ASTERISK
+ { 0x2B, Infix, 4, 4, 0}, // PLUS SIGN
+ { 0x2B, Prefix, 0, 1, 0}, // PLUS SIGN
+ { 0x2C, Infix, 0, 3, Separator}, // COMMA
+ { 0x2D, Infix, 4, 4, 0}, // HYPHEN-MINUS
+ { 0x2D, Prefix, 0, 1, 0}, // HYPHEN-MINUS
+ { 0x2E, Infix, 3, 3, 0}, // FULL STOP
+ { 0x2F, Infix, 1, 1, 0}, // SOLIDUS
+ { 0x3A, Infix, 1, 2, 0}, // COLON
+ { 0x3B, Infix, 0, 3, Separator}, // SEMICOLON
+ { 0x3C, Infix, 5, 5, 0}, // LESS-THAN SIGN
+ { 0x3D, Infix, 5, 5, 0}, // EQUALS SIGN
+ { 0x3E, Infix, 5, 5, 0}, // GREATER-THAN SIGN
+ { 0x3F, Infix, 1, 1, 0}, // QUESTION MARK
+ { 0x40, Infix, 1, 1, 0}, // COMMERCIAL AT
+ { 0x5B, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT SQUARE BRACKET
+ { 0x5C, Infix, 0, 0, 0}, // REVERSE SOLIDUS
+ { 0x5D, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT SQUARE BRACKET
+ { 0x5E, Postfix, 0, 0, Accent | Stretchy}, // CIRCUMFLEX ACCENT
+ { 0x5E, Infix, 1, 1, 0}, // CIRCUMFLEX ACCENT
+ { 0x5F, Postfix, 0, 0, Accent | Stretchy}, // LOW LINE
+ { 0x5F, Infix, 1, 1, 0}, // LOW LINE
+ { 0x60, Postfix, 0, 0, Accent}, // GRAVE ACCENT
+ { 0x7B, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT CURLY BRACKET
+ { 0x7C, Infix, 2, 2, Stretchy | Symmetric | Fence}, // VERTICAL LINE
+ { 0x7C, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // VERTICAL LINE
+ { 0x7C, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // VERTICAL LINE
+ { 0x7D, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT CURLY BRACKET
+ { 0x7E, Postfix, 0, 0, Accent | Stretchy}, // TILDE
+ { 0xA8, Postfix, 0, 0, Accent}, // DIAERESIS
+ { 0xAC, Prefix, 2, 1, 0}, // NOT SIGN
+ { 0xAF, Postfix, 0, 0, Accent | Stretchy}, // MACRON
+ { 0xB0, Postfix, 0, 0, 0}, // DEGREE SIGN
+ { 0xB1, Infix, 4, 4, 0}, // PLUS-MINUS SIGN
+ { 0xB1, Prefix, 0, 1, 0}, // PLUS-MINUS SIGN
+ { 0xB4, Postfix, 0, 0, Accent}, // ACUTE ACCENT
+ { 0xB7, Infix, 4, 4, 0}, // MIDDLE DOT
+ { 0xB8, Postfix, 0, 0, Accent}, // CEDILLA
+ { 0xD7, Infix, 4, 4, 0}, // MULTIPLICATION SIGN
+ { 0xF7, Infix, 4, 4, 0}, // DIVISION SIGN
+ { 0x2C6, Postfix, 0, 0, Accent | Stretchy}, // MODIFIER LETTER CIRCUMFLEX ACCENT
+ { 0x2C7, Postfix, 0, 0, Accent | Stretchy}, // CARON
+ { 0x2C9, Postfix, 0, 0, Accent | Stretchy}, // MODIFIER LETTER MACRON
+ { 0x2CA, Postfix, 0, 0, Accent}, // MODIFIER LETTER ACUTE ACCENT
+ { 0x2CB, Postfix, 0, 0, Accent}, // MODIFIER LETTER GRAVE ACCENT
+ { 0x2CD, Postfix, 0, 0, Accent | Stretchy}, // MODIFIER LETTER LOW MACRON
+ { 0x2D8, Postfix, 0, 0, Accent}, // BREVE
+ { 0x2D9, Postfix, 0, 0, Accent}, // DOT ABOVE
+ { 0x2DA, Postfix, 0, 0, Accent}, // RING ABOVE
+ { 0x2DC, Postfix, 0, 0, Accent | Stretchy}, // SMALL TILDE
+ { 0x2DD, Postfix, 0, 0, Accent}, // DOUBLE ACUTE ACCENT
+ { 0x2F7, Postfix, 0, 0, Accent | Stretchy}, // MODIFIER LETTER LOW TILDE
+ { 0x302, Postfix, 0, 0, Accent | Stretchy}, // COMBINING CIRCUMFLEX ACCENT
+ { 0x311, Postfix, 0, 0, Accent}, // COMBINING INVERTED BREVE
+ { 0x3F6, Infix, 5, 5, 0}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+ { 0x2016, Prefix, 0, 0, Fence | Stretchy}, // DOUBLE VERTICAL LINE
+ { 0x2016, Postfix, 0, 0, Fence | Stretchy}, // DOUBLE VERTICAL LINE
+ { 0x2018, Prefix, 0, 0, Fence}, // LEFT SINGLE QUOTATION MARK
+ { 0x2019, Postfix, 0, 0, Fence}, // RIGHT SINGLE QUOTATION MARK
+ { 0x201C, Prefix, 0, 0, Fence}, // LEFT DOUBLE QUOTATION MARK
+ { 0x201D, Postfix, 0, 0, Fence}, // RIGHT DOUBLE QUOTATION MARK
+ { 0x2022, Infix, 4, 4, 0}, // BULLET
+ { 0x2026, Infix, 0, 0, 0}, // HORIZONTAL ELLIPSIS
+ { 0x2032, Postfix, 0, 2, 0}, // PRIME
+ { 0x203E, Postfix, 0, 0, Accent | Stretchy}, // OVERLINE
+ { 0x2044, Infix, 4, 4, Stretchy}, // FRACTION SLASH
+ { 0x2061, Infix, 0, 0, 0}, // FUNCTION APPLICATION
+ { 0x2062, Infix, 0, 0, 0}, // INVISIBLE TIMES
+ { 0x2063, Infix, 0, 0, Separator}, // INVISIBLE SEPARATOR
+ { 0x2064, Infix, 0, 0, 0}, // INVISIBLE PLUS
+ { 0x20DB, Postfix, 0, 0, Accent}, // COMBINING THREE DOTS ABOVE
+ { 0x20DC, Postfix, 0, 0, Accent}, // COMBINING FOUR DOTS ABOVE
+ { 0x2145, Prefix, 2, 1, 0}, // DOUBLE-STRUCK ITALIC CAPITAL D
+ { 0x2146, Prefix, 2, 0, 0}, // DOUBLE-STRUCK ITALIC SMALL D
+ { 0x2190, Infix, 5, 5, Accent | Stretchy}, // LEFTWARDS ARROW
+ { 0x2191, Infix, 5, 5, Stretchy}, // UPWARDS ARROW
+ { 0x2192, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW
+ { 0x2193, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW
+ { 0x2194, Infix, 5, 5, Stretchy | Accent}, // LEFT RIGHT ARROW
+ { 0x2195, Infix, 5, 5, Stretchy}, // UP DOWN ARROW
+ { 0x2196, Infix, 5, 5, Stretchy}, // NORTH WEST ARROW
+ { 0x2197, Infix, 5, 5, Stretchy}, // NORTH EAST ARROW
+ { 0x2198, Infix, 5, 5, Stretchy}, // SOUTH EAST ARROW
+ { 0x2199, Infix, 5, 5, Stretchy}, // SOUTH WEST ARROW
+ { 0x219A, Infix, 5, 5, Accent}, // LEFTWARDS ARROW WITH STROKE
+ { 0x219B, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH STROKE
+ { 0x219C, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS WAVE ARROW
+ { 0x219D, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS WAVE ARROW
+ { 0x219E, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS TWO HEADED ARROW
+ { 0x219F, Infix, 5, 5, Stretchy | Accent}, // UPWARDS TWO HEADED ARROW
+ { 0x21A0, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS TWO HEADED ARROW
+ { 0x21A1, Infix, 5, 5, Stretchy}, // DOWNWARDS TWO HEADED ARROW
+ { 0x21A2, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW WITH TAIL
+ { 0x21A3, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW WITH TAIL
+ { 0x21A4, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW FROM BAR
+ { 0x21A5, Infix, 5, 5, Stretchy}, // UPWARDS ARROW FROM BAR
+ { 0x21A6, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW FROM BAR
+ { 0x21A7, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW FROM BAR
+ { 0x21A8, Infix, 5, 5, Stretchy}, // UP DOWN ARROW WITH BASE
+ { 0x21A9, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW WITH HOOK
+ { 0x21AA, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW WITH HOOK
+ { 0x21AB, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW WITH LOOP
+ { 0x21AC, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW WITH LOOP
+ { 0x21AD, Infix, 5, 5, Stretchy | Accent}, // LEFT RIGHT WAVE ARROW
+ { 0x21AE, Infix, 5, 5, Accent}, // LEFT RIGHT ARROW WITH STROKE
+ { 0x21AF, Infix, 5, 5, Stretchy}, // DOWNWARDS ZIGZAG ARROW
+ { 0x21B0, Infix, 5, 5, Stretchy}, // UPWARDS ARROW WITH TIP LEFTWARDS
+ { 0x21B1, Infix, 5, 5, Stretchy}, // UPWARDS ARROW WITH TIP RIGHTWARDS
+ { 0x21B2, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW WITH TIP LEFTWARDS
+ { 0x21B3, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW WITH TIP RIGHTWARDS
+ { 0x21B4, Infix, 5, 5, Stretchy}, // RIGHTWARDS ARROW WITH CORNER DOWNWARDS
+ { 0x21B5, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+ { 0x21B6, Infix, 5, 5, Accent}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+ { 0x21B7, Infix, 5, 5, Accent}, // CLOCKWISE TOP SEMICIRCLE ARROW
+ { 0x21B8, Infix, 5, 5, 0}, // NORTH WEST ARROW TO LONG BAR
+ { 0x21B9, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR
+ { 0x21BA, Infix, 5, 5, 0}, // ANTICLOCKWISE OPEN CIRCLE ARROW
+ { 0x21BB, Infix, 5, 5, 0}, // CLOCKWISE OPEN CIRCLE ARROW
+ { 0x21BC, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ { 0x21BD, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ { 0x21BE, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ { 0x21BF, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ { 0x21C0, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ { 0x21C1, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ { 0x21C2, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ { 0x21C3, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ { 0x21C4, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ { 0x21C5, Infix, 5, 5, Stretchy}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+ { 0x21C6, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ { 0x21C7, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS PAIRED ARROWS
+ { 0x21C8, Infix, 5, 5, Stretchy}, // UPWARDS PAIRED ARROWS
+ { 0x21C9, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS PAIRED ARROWS
+ { 0x21CA, Infix, 5, 5, Stretchy}, // DOWNWARDS PAIRED ARROWS
+ { 0x21CB, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ { 0x21CC, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ { 0x21CD, Infix, 5, 5, Accent}, // LEFTWARDS DOUBLE ARROW WITH STROKE
+ { 0x21CE, Infix, 5, 5, Accent}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
+ { 0x21CF, Infix, 5, 5, Accent}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
+ { 0x21D0, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS DOUBLE ARROW
+ { 0x21D1, Infix, 5, 5, Stretchy}, // UPWARDS DOUBLE ARROW
+ { 0x21D2, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS DOUBLE ARROW
+ { 0x21D3, Infix, 5, 5, Stretchy}, // DOWNWARDS DOUBLE ARROW
+ { 0x21D4, Infix, 5, 5, Stretchy | Accent}, // LEFT RIGHT DOUBLE ARROW
+ { 0x21D5, Infix, 5, 5, Stretchy}, // UP DOWN DOUBLE ARROW
+ { 0x21D6, Infix, 5, 5, Stretchy}, // NORTH WEST DOUBLE ARROW
+ { 0x21D7, Infix, 5, 5, Stretchy}, // NORTH EAST DOUBLE ARROW
+ { 0x21D8, Infix, 5, 5, Stretchy}, // SOUTH EAST DOUBLE ARROW
+ { 0x21D9, Infix, 5, 5, Stretchy}, // SOUTH WEST DOUBLE ARROW
+ { 0x21DA, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS TRIPLE ARROW
+ { 0x21DB, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS TRIPLE ARROW
+ { 0x21DC, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS SQUIGGLE ARROW
+ { 0x21DD, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS SQUIGGLE ARROW
+ { 0x21DE, Infix, 5, 5, 0}, // UPWARDS ARROW WITH DOUBLE STROKE
+ { 0x21DF, Infix, 5, 5, 0}, // DOWNWARDS ARROW WITH DOUBLE STROKE
+ { 0x21E0, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS DASHED ARROW
+ { 0x21E1, Infix, 5, 5, Stretchy}, // UPWARDS DASHED ARROW
+ { 0x21E2, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS DASHED ARROW
+ { 0x21E3, Infix, 5, 5, Stretchy}, // DOWNWARDS DASHED ARROW
+ { 0x21E4, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS ARROW TO BAR
+ { 0x21E5, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS ARROW TO BAR
+ { 0x21E6, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS WHITE ARROW
+ { 0x21E7, Infix, 5, 5, Stretchy}, // UPWARDS WHITE ARROW
+ { 0x21E8, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS WHITE ARROW
+ { 0x21E9, Infix, 5, 5, Stretchy}, // DOWNWARDS WHITE ARROW
+ { 0x21EA, Infix, 5, 5, Stretchy}, // UPWARDS WHITE ARROW FROM BAR
+ { 0x21EB, Infix, 5, 5, Stretchy}, // UPWARDS WHITE ARROW ON PEDESTAL
+ { 0x21EC, Infix, 5, 5, Stretchy}, // UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR
+ { 0x21ED, Infix, 5, 5, Stretchy}, // UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR
+ { 0x21EE, Infix, 5, 5, Stretchy}, // UPWARDS WHITE DOUBLE ARROW
+ { 0x21EF, Infix, 5, 5, Stretchy}, // UPWARDS WHITE DOUBLE ARROW ON PEDESTAL
+ { 0x21F0, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS WHITE ARROW FROM WALL
+ { 0x21F1, Infix, 5, 5, 0}, // NORTH WEST ARROW TO CORNER
+ { 0x21F2, Infix, 5, 5, 0}, // SOUTH EAST ARROW TO CORNER
+ { 0x21F3, Infix, 5, 5, Stretchy}, // UP DOWN WHITE ARROW
+ { 0x21F4, Infix, 5, 5, Accent}, // RIGHT ARROW WITH SMALL CIRCLE
+ { 0x21F5, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+ { 0x21F6, Infix, 5, 5, Stretchy | Accent}, // THREE RIGHTWARDS ARROWS
+ { 0x21F7, Infix, 5, 5, Accent}, // LEFTWARDS ARROW WITH VERTICAL STROKE
+ { 0x21F8, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH VERTICAL STROKE
+ { 0x21F9, Infix, 5, 5, Accent}, // LEFT RIGHT ARROW WITH VERTICAL STROKE
+ { 0x21FA, Infix, 5, 5, Accent}, // LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE
+ { 0x21FB, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE
+ { 0x21FC, Infix, 5, 5, Accent}, // LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE
+ { 0x21FD, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS OPEN-HEADED ARROW
+ { 0x21FE, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS OPEN-HEADED ARROW
+ { 0x21FF, Infix, 5, 5, Stretchy | Accent}, // LEFT RIGHT OPEN-HEADED ARROW
+ { 0x2200, Prefix, 2, 1, 0}, // FOR ALL
+ { 0x2201, Infix, 1, 2, 0}, // COMPLEMENT
+ { 0x2202, Prefix, 2, 1, 0}, // PARTIAL DIFFERENTIAL
+ { 0x2203, Prefix, 2, 1, 0}, // THERE EXISTS
+ { 0x2204, Prefix, 2, 1, 0}, // THERE DOES NOT EXIST
+ { 0x2206, Infix, 3, 3, 0}, // INCREMENT
+ { 0x2207, Prefix, 2, 1, 0}, // NABLA
+ { 0x2208, Infix, 5, 5, 0}, // ELEMENT OF
+ { 0x2209, Infix, 5, 5, 0}, // NOT AN ELEMENT OF
+ { 0x220A, Infix, 5, 5, 0}, // SMALL ELEMENT OF
+ { 0x220B, Infix, 5, 5, 0}, // CONTAINS AS MEMBER
+ { 0x220C, Infix, 5, 5, 0}, // DOES NOT CONTAIN AS MEMBER
+ { 0x220D, Infix, 5, 5, 0}, // SMALL CONTAINS AS MEMBER
+ { 0x220E, Infix, 3, 3, 0}, // END OF PROOF
+ { 0x220F, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY PRODUCT
+ { 0x2210, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY COPRODUCT
+ { 0x2211, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY SUMMATION
+ { 0x2212, Infix, 4, 4, 0}, // MINUS SIGN
+ { 0x2212, Prefix, 0, 1, 0}, // MINUS SIGN
+ { 0x2213, Infix, 4, 4, 0}, // MINUS-OR-PLUS SIGN
+ { 0x2213, Prefix, 0, 1, 0}, // MINUS-OR-PLUS SIGN
+ { 0x2214, Infix, 4, 4, 0}, // DOT PLUS
+ { 0x2215, Infix, 4, 4, Stretchy}, // DIVISION SLASH
+ { 0x2216, Infix, 4, 4, 0}, // SET MINUS
+ { 0x2217, Infix, 4, 4, 0}, // ASTERISK OPERATOR
+ { 0x2218, Infix, 4, 4, 0}, // RING OPERATOR
+ { 0x2219, Infix, 4, 4, 0}, // BULLET OPERATOR
+ { 0x221A, Prefix, 1, 1, Stretchy}, // SQUARE ROOT
+ { 0x221B, Prefix, 1, 1, 0}, // CUBE ROOT
+ { 0x221C, Prefix, 1, 1, 0}, // FOURTH ROOT
+ { 0x221D, Infix, 5, 5, 0}, // PROPORTIONAL TO
+ { 0x221F, Infix, 5, 5, 0}, // RIGHT ANGLE
+ { 0x2220, Prefix, 0, 0, 0}, // ANGLE
+ { 0x2221, Prefix, 0, 0, 0}, // MEASURED ANGLE
+ { 0x2222, Prefix, 0, 0, 0}, // SPHERICAL ANGLE
+ { 0x2223, Infix, 5, 5, 0}, // DIVIDES
+ { 0x2224, Infix, 5, 5, 0}, // DOES NOT DIVIDE
+ { 0x2225, Infix, 5, 5, 0}, // PARALLEL TO
+ { 0x2225, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // PARALLEL TO
+ { 0x2225, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // PARALLEL TO
+ { 0x2226, Infix, 5, 5, 0}, // NOT PARALLEL TO
+ { 0x2227, Infix, 4, 4, 0}, // LOGICAL AND
+ { 0x2228, Infix, 4, 4, 0}, // LOGICAL OR
+ { 0x2229, Infix, 4, 4, 0}, // INTERSECTION
+ { 0x222A, Infix, 4, 4, 0}, // UNION
+ { 0x222B, Prefix, 0, 1, Symmetric | LargeOp}, // INTEGRAL
+ { 0x222C, Prefix, 0, 1, Symmetric | LargeOp}, // DOUBLE INTEGRAL
+ { 0x222D, Prefix, 0, 1, Symmetric | LargeOp}, // TRIPLE INTEGRAL
+ { 0x222E, Prefix, 0, 1, Symmetric | LargeOp}, // CONTOUR INTEGRAL
+ { 0x222F, Prefix, 0, 1, Symmetric | LargeOp}, // SURFACE INTEGRAL
+ { 0x2230, Prefix, 0, 1, Symmetric | LargeOp}, // VOLUME INTEGRAL
+ { 0x2231, Prefix, 0, 1, Symmetric | LargeOp}, // CLOCKWISE INTEGRAL
+ { 0x2232, Prefix, 0, 1, Symmetric | LargeOp}, // CLOCKWISE CONTOUR INTEGRAL
+ { 0x2233, Prefix, 0, 1, Symmetric | LargeOp}, // ANTICLOCKWISE CONTOUR INTEGRAL
+ { 0x2234, Infix, 5, 5, 0}, // THEREFORE
+ { 0x2235, Infix, 5, 5, 0}, // BECAUSE
+ { 0x2236, Infix, 5, 5, 0}, // RATIO
+ { 0x2237, Infix, 5, 5, 0}, // PROPORTION
+ { 0x2238, Infix, 4, 4, 0}, // DOT MINUS
+ { 0x2239, Infix, 5, 5, 0}, // EXCESS
+ { 0x223A, Infix, 4, 4, 0}, // GEOMETRIC PROPORTION
+ { 0x223B, Infix, 5, 5, 0}, // HOMOTHETIC
+ { 0x223C, Infix, 5, 5, 0}, // TILDE OPERATOR
+ { 0x223D, Infix, 5, 5, 0}, // REVERSED TILDE
+ { 0x223E, Infix, 5, 5, 0}, // INVERTED LAZY S
+ { 0x223F, Infix, 3, 3, 0}, // SINE WAVE
+ { 0x2240, Infix, 4, 4, 0}, // WREATH PRODUCT
+ { 0x2241, Infix, 5, 5, 0}, // NOT TILDE
+ { 0x2242, Infix, 5, 5, 0}, // MINUS TILDE
+ { 0x2243, Infix, 5, 5, 0}, // ASYMPTOTICALLY EQUAL TO
+ { 0x2244, Infix, 5, 5, 0}, // NOT ASYMPTOTICALLY EQUAL TO
+ { 0x2245, Infix, 5, 5, 0}, // APPROXIMATELY EQUAL TO
+ { 0x2246, Infix, 5, 5, 0}, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO
+ { 0x2247, Infix, 5, 5, 0}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ { 0x2248, Infix, 5, 5, 0}, // ALMOST EQUAL TO
+ { 0x2249, Infix, 5, 5, 0}, // NOT ALMOST EQUAL TO
+ { 0x224A, Infix, 5, 5, 0}, // ALMOST EQUAL OR EQUAL TO
+ { 0x224B, Infix, 5, 5, 0}, // TRIPLE TILDE
+ { 0x224C, Infix, 5, 5, 0}, // ALL EQUAL TO
+ { 0x224D, Infix, 5, 5, 0}, // EQUIVALENT TO
+ { 0x224E, Infix, 5, 5, 0}, // GEOMETRICALLY EQUIVALENT TO
+ { 0x224F, Infix, 5, 5, 0}, // DIFFERENCE BETWEEN
+ { 0x2250, Infix, 5, 5, 0}, // APPROACHES THE LIMIT
+ { 0x2251, Infix, 5, 5, 0}, // GEOMETRICALLY EQUAL TO
+ { 0x2252, Infix, 5, 5, 0}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ { 0x2253, Infix, 5, 5, 0}, // IMAGE OF OR APPROXIMATELY EQUAL TO
+ { 0x2254, Infix, 5, 5, 0}, // COLON EQUALS
+ { 0x2255, Infix, 5, 5, 0}, // EQUALS COLON
+ { 0x2256, Infix, 5, 5, 0}, // RING IN EQUAL TO
+ { 0x2257, Infix, 5, 5, 0}, // RING EQUAL TO
+ { 0x2258, Infix, 5, 5, 0}, // CORRESPONDS TO
+ { 0x2259, Infix, 5, 5, 0}, // ESTIMATES
+ { 0x225A, Infix, 5, 5, 0}, // EQUIANGULAR TO
+ { 0x225C, Infix, 5, 5, 0}, // DELTA EQUAL TO
+ { 0x225D, Infix, 5, 5, 0}, // EQUAL TO BY DEFINITION
+ { 0x225E, Infix, 5, 5, 0}, // MEASURED BY
+ { 0x225F, Infix, 5, 5, 0}, // QUESTIONED EQUAL TO
+ { 0x2260, Infix, 5, 5, 0}, // NOT EQUAL TO
+ { 0x2261, Infix, 5, 5, 0}, // IDENTICAL TO
+ { 0x2262, Infix, 5, 5, 0}, // NOT IDENTICAL TO
+ { 0x2263, Infix, 5, 5, 0}, // STRICTLY EQUIVALENT TO
+ { 0x2264, Infix, 5, 5, 0}, // LESS-THAN OR EQUAL TO
+ { 0x2265, Infix, 5, 5, 0}, // GREATER-THAN OR EQUAL TO
+ { 0x2266, Infix, 5, 5, 0}, // LESS-THAN OVER EQUAL TO
+ { 0x2267, Infix, 5, 5, 0}, // GREATER-THAN OVER EQUAL TO
+ { 0x2268, Infix, 5, 5, 0}, // LESS-THAN BUT NOT EQUAL TO
+ { 0x2269, Infix, 5, 5, 0}, // GREATER-THAN BUT NOT EQUAL TO
+ { 0x226A, Infix, 5, 5, 0}, // MUCH LESS-THAN
+ { 0x226B, Infix, 5, 5, 0}, // MUCH GREATER-THAN
+ { 0x226C, Infix, 5, 5, 0}, // BETWEEN
+ { 0x226D, Infix, 5, 5, 0}, // NOT EQUIVALENT TO
+ { 0x226E, Infix, 5, 5, 0}, // NOT LESS-THAN
+ { 0x226F, Infix, 5, 5, 0}, // NOT GREATER-THAN
+ { 0x2270, Infix, 5, 5, 0}, // NEITHER LESS-THAN NOR EQUAL TO
+ { 0x2271, Infix, 5, 5, 0}, // NEITHER GREATER-THAN NOR EQUAL TO
+ { 0x2272, Infix, 5, 5, 0}, // LESS-THAN OR EQUIVALENT TO
+ { 0x2273, Infix, 5, 5, 0}, // GREATER-THAN OR EQUIVALENT TO
+ { 0x2274, Infix, 5, 5, 0}, // NEITHER LESS-THAN NOR EQUIVALENT TO
+ { 0x2275, Infix, 5, 5, 0}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
+ { 0x2276, Infix, 5, 5, 0}, // LESS-THAN OR GREATER-THAN
+ { 0x2277, Infix, 5, 5, 0}, // GREATER-THAN OR LESS-THAN
+ { 0x2278, Infix, 5, 5, 0}, // NEITHER LESS-THAN NOR GREATER-THAN
+ { 0x2279, Infix, 5, 5, 0}, // NEITHER GREATER-THAN NOR LESS-THAN
+ { 0x227A, Infix, 5, 5, 0}, // PRECEDES
+ { 0x227B, Infix, 5, 5, 0}, // SUCCEEDS
+ { 0x227C, Infix, 5, 5, 0}, // PRECEDES OR EQUAL TO
+ { 0x227D, Infix, 5, 5, 0}, // SUCCEEDS OR EQUAL TO
+ { 0x227E, Infix, 5, 5, 0}, // PRECEDES OR EQUIVALENT TO
+ { 0x227F, Infix, 5, 5, 0}, // SUCCEEDS OR EQUIVALENT TO
+ { 0x2280, Infix, 5, 5, 0}, // DOES NOT PRECEDE
+ { 0x2281, Infix, 5, 5, 0}, // DOES NOT SUCCEED
+ { 0x2282, Infix, 5, 5, 0}, // SUBSET OF
+ { 0x2283, Infix, 5, 5, 0}, // SUPERSET OF
+ { 0x2284, Infix, 5, 5, 0}, // NOT A SUBSET OF
+ { 0x2285, Infix, 5, 5, 0}, // NOT A SUPERSET OF
+ { 0x2286, Infix, 5, 5, 0}, // SUBSET OF OR EQUAL TO
+ { 0x2287, Infix, 5, 5, 0}, // SUPERSET OF OR EQUAL TO
+ { 0x2288, Infix, 5, 5, 0}, // NEITHER A SUBSET OF NOR EQUAL TO
+ { 0x2289, Infix, 5, 5, 0}, // NEITHER A SUPERSET OF NOR EQUAL TO
+ { 0x228A, Infix, 5, 5, 0}, // SUBSET OF WITH NOT EQUAL TO
+ { 0x228B, Infix, 5, 5, 0}, // SUPERSET OF WITH NOT EQUAL TO
+ { 0x228C, Infix, 4, 4, 0}, // MULTISET
+ { 0x228D, Infix, 4, 4, 0}, // MULTISET MULTIPLICATION
+ { 0x228E, Infix, 4, 4, 0}, // MULTISET UNION
+ { 0x228F, Infix, 5, 5, 0}, // SQUARE IMAGE OF
+ { 0x2290, Infix, 5, 5, 0}, // SQUARE ORIGINAL OF
+ { 0x2291, Infix, 5, 5, 0}, // SQUARE IMAGE OF OR EQUAL TO
+ { 0x2292, Infix, 5, 5, 0}, // SQUARE ORIGINAL OF OR EQUAL TO
+ { 0x2293, Infix, 4, 4, 0}, // SQUARE CAP
+ { 0x2294, Infix, 4, 4, 0}, // SQUARE CUP
+ { 0x2295, Infix, 4, 4, 0}, // CIRCLED PLUS
+ { 0x2296, Infix, 4, 4, 0}, // CIRCLED MINUS
+ { 0x2297, Infix, 4, 4, 0}, // CIRCLED TIMES
+ { 0x2298, Infix, 4, 4, 0}, // CIRCLED DIVISION SLASH
+ { 0x2299, Infix, 4, 4, 0}, // CIRCLED DOT OPERATOR
+ { 0x229A, Infix, 4, 4, 0}, // CIRCLED RING OPERATOR
+ { 0x229B, Infix, 4, 4, 0}, // CIRCLED ASTERISK OPERATOR
+ { 0x229C, Infix, 4, 4, 0}, // CIRCLED EQUALS
+ { 0x229D, Infix, 4, 4, 0}, // CIRCLED DASH
+ { 0x229E, Infix, 4, 4, 0}, // SQUARED PLUS
+ { 0x229F, Infix, 4, 4, 0}, // SQUARED MINUS
+ { 0x22A0, Infix, 4, 4, 0}, // SQUARED TIMES
+ { 0x22A1, Infix, 4, 4, 0}, // SQUARED DOT OPERATOR
+ { 0x22A2, Infix, 5, 5, 0}, // RIGHT TACK
+ { 0x22A3, Infix, 5, 5, 0}, // LEFT TACK
+ { 0x22A4, Infix, 5, 5, 0}, // DOWN TACK
+ { 0x22A5, Infix, 5, 5, 0}, // UP TACK
+ { 0x22A6, Infix, 5, 5, 0}, // ASSERTION
+ { 0x22A7, Infix, 5, 5, 0}, // MODELS
+ { 0x22A8, Infix, 5, 5, 0}, // TRUE
+ { 0x22A9, Infix, 5, 5, 0}, // FORCES
+ { 0x22AA, Infix, 5, 5, 0}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE
+ { 0x22AB, Infix, 5, 5, 0}, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+ { 0x22AC, Infix, 5, 5, 0}, // DOES NOT PROVE
+ { 0x22AD, Infix, 5, 5, 0}, // NOT TRUE
+ { 0x22AE, Infix, 5, 5, 0}, // DOES NOT FORCE
+ { 0x22AF, Infix, 5, 5, 0}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+ { 0x22B0, Infix, 5, 5, 0}, // PRECEDES UNDER RELATION
+ { 0x22B1, Infix, 5, 5, 0}, // SUCCEEDS UNDER RELATION
+ { 0x22B2, Infix, 5, 5, 0}, // NORMAL SUBGROUP OF
+ { 0x22B3, Infix, 5, 5, 0}, // CONTAINS AS NORMAL SUBGROUP
+ { 0x22B4, Infix, 5, 5, 0}, // NORMAL SUBGROUP OF OR EQUAL TO
+ { 0x22B5, Infix, 5, 5, 0}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ { 0x22B6, Infix, 5, 5, 0}, // ORIGINAL OF
+ { 0x22B7, Infix, 5, 5, 0}, // IMAGE OF
+ { 0x22B8, Infix, 5, 5, 0}, // MULTIMAP
+ { 0x22B9, Infix, 5, 5, 0}, // HERMITIAN CONJUGATE MATRIX
+ { 0x22BA, Infix, 4, 4, 0}, // INTERCALATE
+ { 0x22BB, Infix, 4, 4, 0}, // XOR
+ { 0x22BC, Infix, 4, 4, 0}, // NAND
+ { 0x22BD, Infix, 4, 4, 0}, // NOR
+ { 0x22BE, Infix, 3, 3, 0}, // RIGHT ANGLE WITH ARC
+ { 0x22BF, Infix, 3, 3, 0}, // RIGHT TRIANGLE
+ { 0x22C0, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY LOGICAL AND
+ { 0x22C1, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY LOGICAL OR
+ { 0x22C2, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY INTERSECTION
+ { 0x22C3, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY UNION
+ { 0x22C4, Infix, 4, 4, 0}, // DIAMOND OPERATOR
+ { 0x22C5, Infix, 4, 4, 0}, // DOT OPERATOR
+ { 0x22C6, Infix, 4, 4, 0}, // STAR OPERATOR
+ { 0x22C7, Infix, 4, 4, 0}, // DIVISION TIMES
+ { 0x22C8, Infix, 5, 5, 0}, // BOWTIE
+ { 0x22C9, Infix, 4, 4, 0}, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
+ { 0x22CA, Infix, 4, 4, 0}, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
+ { 0x22CB, Infix, 4, 4, 0}, // LEFT SEMIDIRECT PRODUCT
+ { 0x22CC, Infix, 4, 4, 0}, // RIGHT SEMIDIRECT PRODUCT
+ { 0x22CD, Infix, 5, 5, 0}, // REVERSED TILDE EQUALS
+ { 0x22CE, Infix, 4, 4, 0}, // CURLY LOGICAL OR
+ { 0x22CF, Infix, 4, 4, 0}, // CURLY LOGICAL AND
+ { 0x22D0, Infix, 5, 5, 0}, // DOUBLE SUBSET
+ { 0x22D1, Infix, 5, 5, 0}, // DOUBLE SUPERSET
+ { 0x22D2, Infix, 4, 4, 0}, // DOUBLE INTERSECTION
+ { 0x22D3, Infix, 4, 4, 0}, // DOUBLE UNION
+ { 0x22D4, Infix, 5, 5, 0}, // PITCHFORK
+ { 0x22D5, Infix, 5, 5, 0}, // EQUAL AND PARALLEL TO
+ { 0x22D6, Infix, 5, 5, 0}, // LESS-THAN WITH DOT
+ { 0x22D7, Infix, 5, 5, 0}, // GREATER-THAN WITH DOT
+ { 0x22D8, Infix, 5, 5, 0}, // VERY MUCH LESS-THAN
+ { 0x22D9, Infix, 5, 5, 0}, // VERY MUCH GREATER-THAN
+ { 0x22DA, Infix, 5, 5, 0}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ { 0x22DB, Infix, 5, 5, 0}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ { 0x22DC, Infix, 5, 5, 0}, // EQUAL TO OR LESS-THAN
+ { 0x22DD, Infix, 5, 5, 0}, // EQUAL TO OR GREATER-THAN
+ { 0x22DE, Infix, 5, 5, 0}, // EQUAL TO OR PRECEDES
+ { 0x22DF, Infix, 5, 5, 0}, // EQUAL TO OR SUCCEEDS
+ { 0x22E0, Infix, 5, 5, 0}, // DOES NOT PRECEDE OR EQUAL
+ { 0x22E1, Infix, 5, 5, 0}, // DOES NOT SUCCEED OR EQUAL
+ { 0x22E2, Infix, 5, 5, 0}, // NOT SQUARE IMAGE OF OR EQUAL TO
+ { 0x22E3, Infix, 5, 5, 0}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
+ { 0x22E4, Infix, 5, 5, 0}, // SQUARE IMAGE OF OR NOT EQUAL TO
+ { 0x22E5, Infix, 5, 5, 0}, // SQUARE ORIGINAL OF OR NOT EQUAL TO
+ { 0x22E6, Infix, 5, 5, 0}, // LESS-THAN BUT NOT EQUIVALENT TO
+ { 0x22E7, Infix, 5, 5, 0}, // GREATER-THAN BUT NOT EQUIVALENT TO
+ { 0x22E8, Infix, 5, 5, 0}, // PRECEDES BUT NOT EQUIVALENT TO
+ { 0x22E9, Infix, 5, 5, 0}, // SUCCEEDS BUT NOT EQUIVALENT TO
+ { 0x22EA, Infix, 5, 5, 0}, // NOT NORMAL SUBGROUP OF
+ { 0x22EB, Infix, 5, 5, 0}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+ { 0x22EC, Infix, 5, 5, 0}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+ { 0x22ED, Infix, 5, 5, 0}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+ { 0x22EE, Infix, 5, 5, 0}, // VERTICAL ELLIPSIS
+ { 0x22EF, Infix, 0, 0, 0}, // MIDLINE HORIZONTAL ELLIPSIS
+ { 0x22F0, Infix, 5, 5, 0}, // UP RIGHT DIAGONAL ELLIPSIS
+ { 0x22F1, Infix, 5, 5, 0}, // DOWN RIGHT DIAGONAL ELLIPSIS
+ { 0x22F2, Infix, 5, 5, 0}, // ELEMENT OF WITH LONG HORIZONTAL STROKE
+ { 0x22F3, Infix, 5, 5, 0}, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ { 0x22F4, Infix, 5, 5, 0}, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ { 0x22F5, Infix, 5, 5, 0}, // ELEMENT OF WITH DOT ABOVE
+ { 0x22F6, Infix, 5, 5, 0}, // ELEMENT OF WITH OVERBAR
+ { 0x22F7, Infix, 5, 5, 0}, // SMALL ELEMENT OF WITH OVERBAR
+ { 0x22F8, Infix, 5, 5, 0}, // ELEMENT OF WITH UNDERBAR
+ { 0x22F9, Infix, 5, 5, 0}, // ELEMENT OF WITH TWO HORIZONTAL STROKES
+ { 0x22FA, Infix, 5, 5, 0}, // CONTAINS WITH LONG HORIZONTAL STROKE
+ { 0x22FB, Infix, 5, 5, 0}, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ { 0x22FC, Infix, 5, 5, 0}, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ { 0x22FD, Infix, 5, 5, 0}, // CONTAINS WITH OVERBAR
+ { 0x22FE, Infix, 5, 5, 0}, // SMALL CONTAINS WITH OVERBAR
+ { 0x22FF, Infix, 5, 5, 0}, // Z NOTATION BAG MEMBERSHIP
+ { 0x2308, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT CEILING
+ { 0x2309, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT CEILING
+ { 0x230A, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT FLOOR
+ { 0x230B, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT FLOOR
+ { 0x23B4, Postfix, 0, 0, Accent | Stretchy}, // TOP SQUARE BRACKET
+ { 0x23B5, Postfix, 0, 0, Accent | Stretchy}, // BOTTOM SQUARE BRACKET
+ { 0x23DC, Postfix, 0, 0, Accent | Stretchy}, // TOP PARENTHESIS
+ { 0x23DD, Postfix, 0, 0, Accent | Stretchy}, // BOTTOM PARENTHESIS
+ { 0x23DE, Postfix, 0, 0, Accent | Stretchy}, // TOP CURLY BRACKET
+ { 0x23DF, Postfix, 0, 0, Accent | Stretchy}, // BOTTOM CURLY BRACKET
+ { 0x23E0, Postfix, 0, 0, Accent | Stretchy}, // TOP TORTOISE SHELL BRACKET
+ { 0x23E1, Postfix, 0, 0, Accent | Stretchy}, // BOTTOM TORTOISE SHELL BRACKET
+ { 0x25A0, Infix, 3, 3, 0}, // BLACK SQUARE
+ { 0x25A1, Infix, 3, 3, 0}, // WHITE SQUARE
+ { 0x25AA, Infix, 3, 3, 0}, // BLACK SMALL SQUARE
+ { 0x25AB, Infix, 3, 3, 0}, // WHITE SMALL SQUARE
+ { 0x25AD, Infix, 3, 3, 0}, // WHITE RECTANGLE
+ { 0x25AE, Infix, 3, 3, 0}, // BLACK VERTICAL RECTANGLE
+ { 0x25AF, Infix, 3, 3, 0}, // WHITE VERTICAL RECTANGLE
+ { 0x25B0, Infix, 3, 3, 0}, // BLACK PARALLELOGRAM
+ { 0x25B1, Infix, 3, 3, 0}, // WHITE PARALLELOGRAM
+ { 0x25B2, Infix, 4, 4, 0}, // BLACK UP-POINTING TRIANGLE
+ { 0x25B3, Infix, 4, 4, 0}, // WHITE UP-POINTING TRIANGLE
+ { 0x25B4, Infix, 4, 4, 0}, // BLACK UP-POINTING SMALL TRIANGLE
+ { 0x25B5, Infix, 4, 4, 0}, // WHITE UP-POINTING SMALL TRIANGLE
+ { 0x25B6, Infix, 4, 4, 0}, // BLACK RIGHT-POINTING TRIANGLE
+ { 0x25B7, Infix, 4, 4, 0}, // WHITE RIGHT-POINTING TRIANGLE
+ { 0x25B8, Infix, 4, 4, 0}, // BLACK RIGHT-POINTING SMALL TRIANGLE
+ { 0x25B9, Infix, 4, 4, 0}, // WHITE RIGHT-POINTING SMALL TRIANGLE
+ { 0x25BC, Infix, 4, 4, 0}, // BLACK DOWN-POINTING TRIANGLE
+ { 0x25BD, Infix, 4, 4, 0}, // WHITE DOWN-POINTING TRIANGLE
+ { 0x25BE, Infix, 4, 4, 0}, // BLACK DOWN-POINTING SMALL TRIANGLE
+ { 0x25BF, Infix, 4, 4, 0}, // WHITE DOWN-POINTING SMALL TRIANGLE
+ { 0x25C0, Infix, 4, 4, 0}, // BLACK LEFT-POINTING TRIANGLE
+ { 0x25C1, Infix, 4, 4, 0}, // WHITE LEFT-POINTING TRIANGLE
+ { 0x25C2, Infix, 4, 4, 0}, // BLACK LEFT-POINTING SMALL TRIANGLE
+ { 0x25C3, Infix, 4, 4, 0}, // WHITE LEFT-POINTING SMALL TRIANGLE
+ { 0x25C4, Infix, 4, 4, 0}, // BLACK LEFT-POINTING POINTER
+ { 0x25C5, Infix, 4, 4, 0}, // WHITE LEFT-POINTING POINTER
+ { 0x25C6, Infix, 4, 4, 0}, // BLACK DIAMOND
+ { 0x25C7, Infix, 4, 4, 0}, // WHITE DIAMOND
+ { 0x25C8, Infix, 4, 4, 0}, // WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
+ { 0x25C9, Infix, 4, 4, 0}, // FISHEYE
+ { 0x25CC, Infix, 4, 4, 0}, // DOTTED CIRCLE
+ { 0x25CD, Infix, 4, 4, 0}, // CIRCLE WITH VERTICAL FILL
+ { 0x25CE, Infix, 4, 4, 0}, // BULLSEYE
+ { 0x25CF, Infix, 4, 4, 0}, // BLACK CIRCLE
+ { 0x25D6, Infix, 4, 4, 0}, // LEFT HALF BLACK CIRCLE
+ { 0x25D7, Infix, 4, 4, 0}, // RIGHT HALF BLACK CIRCLE
+ { 0x25E6, Infix, 4, 4, 0}, // WHITE BULLET
+ { 0x266D, Postfix, 0, 2, 0}, // MUSIC FLAT SIGN
+ { 0x266E, Postfix, 0, 2, 0}, // MUSIC NATURAL SIGN
+ { 0x266F, Postfix, 0, 2, 0}, // MUSIC SHARP SIGN
+ { 0x2758, Infix, 5, 5, 0}, // LIGHT VERTICAL BAR
+ { 0x2772, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ { 0x2773, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ { 0x27E6, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ { 0x27E7, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ { 0x27E8, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL LEFT ANGLE BRACKET
+ { 0x27E9, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ { 0x27EA, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ { 0x27EB, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ { 0x27EC, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ { 0x27ED, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ { 0x27EE, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL LEFT FLATTENED PARENTHESIS
+ { 0x27EF, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+ { 0x27F0, Infix, 5, 5, Stretchy}, // UPWARDS QUADRUPLE ARROW
+ { 0x27F1, Infix, 5, 5, Stretchy}, // DOWNWARDS QUADRUPLE ARROW
+ { 0x27F5, Infix, 5, 5, Stretchy | Accent}, // LONG LEFTWARDS ARROW
+ { 0x27F6, Infix, 5, 5, Stretchy | Accent}, // LONG RIGHTWARDS ARROW
+ { 0x27F7, Infix, 5, 5, Stretchy | Accent}, // LONG LEFT RIGHT ARROW
+ { 0x27F8, Infix, 5, 5, Stretchy | Accent}, // LONG LEFTWARDS DOUBLE ARROW
+ { 0x27F9, Infix, 5, 5, Stretchy | Accent}, // LONG RIGHTWARDS DOUBLE ARROW
+ { 0x27FA, Infix, 5, 5, Stretchy | Accent}, // LONG LEFT RIGHT DOUBLE ARROW
+ { 0x27FB, Infix, 5, 5, Stretchy | Accent}, // LONG LEFTWARDS ARROW FROM BAR
+ { 0x27FC, Infix, 5, 5, Stretchy | Accent}, // LONG RIGHTWARDS ARROW FROM BAR
+ { 0x27FD, Infix, 5, 5, Stretchy | Accent}, // LONG LEFTWARDS DOUBLE ARROW FROM BAR
+ { 0x27FE, Infix, 5, 5, Stretchy | Accent}, // LONG RIGHTWARDS DOUBLE ARROW FROM BAR
+ { 0x27FF, Infix, 5, 5, Stretchy | Accent}, // LONG RIGHTWARDS SQUIGGLE ARROW
+ { 0x2900, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE
+ { 0x2901, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE
+ { 0x2902, Infix, 5, 5, Accent}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+ { 0x2903, Infix, 5, 5, Accent}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+ { 0x2904, Infix, 5, 5, Accent}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
+ { 0x2905, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW FROM BAR
+ { 0x2906, Infix, 5, 5, Accent}, // LEFTWARDS DOUBLE ARROW FROM BAR
+ { 0x2907, Infix, 5, 5, Accent}, // RIGHTWARDS DOUBLE ARROW FROM BAR
+ { 0x2908, Infix, 5, 5, 0}, // DOWNWARDS ARROW WITH HORIZONTAL STROKE
+ { 0x2909, Infix, 5, 5, 0}, // UPWARDS ARROW WITH HORIZONTAL STROKE
+ { 0x290A, Infix, 5, 5, Stretchy}, // UPWARDS TRIPLE ARROW
+ { 0x290B, Infix, 5, 5, Stretchy}, // DOWNWARDS TRIPLE ARROW
+ { 0x290C, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS DOUBLE DASH ARROW
+ { 0x290D, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS DOUBLE DASH ARROW
+ { 0x290E, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS TRIPLE DASH ARROW
+ { 0x290F, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS TRIPLE DASH ARROW
+ { 0x2910, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+ { 0x2911, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH DOTTED STEM
+ { 0x2912, Infix, 5, 5, Stretchy}, // UPWARDS ARROW TO BAR
+ { 0x2913, Infix, 5, 5, Stretchy}, // DOWNWARDS ARROW TO BAR
+ { 0x2914, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE
+ { 0x2915, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE
+ { 0x2916, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL
+ { 0x2917, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE
+ { 0x2918, Infix, 5, 5, Accent}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE
+ { 0x2919, Infix, 5, 5, Accent}, // LEFTWARDS ARROW-TAIL
+ { 0x291A, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW-TAIL
+ { 0x291B, Infix, 5, 5, Accent}, // LEFTWARDS DOUBLE ARROW-TAIL
+ { 0x291C, Infix, 5, 5, Accent}, // RIGHTWARDS DOUBLE ARROW-TAIL
+ { 0x291D, Infix, 5, 5, Accent}, // LEFTWARDS ARROW TO BLACK DIAMOND
+ { 0x291E, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW TO BLACK DIAMOND
+ { 0x291F, Infix, 5, 5, Accent}, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ { 0x2920, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ { 0x2921, Infix, 5, 5, Stretchy}, // NORTH WEST AND SOUTH EAST ARROW
+ { 0x2922, Infix, 5, 5, Stretchy}, // NORTH EAST AND SOUTH WEST ARROW
+ { 0x2923, Infix, 5, 5, 0}, // NORTH WEST ARROW WITH HOOK
+ { 0x2924, Infix, 5, 5, 0}, // NORTH EAST ARROW WITH HOOK
+ { 0x2925, Infix, 5, 5, 0}, // SOUTH EAST ARROW WITH HOOK
+ { 0x2926, Infix, 5, 5, 0}, // SOUTH WEST ARROW WITH HOOK
+ { 0x2927, Infix, 5, 5, 0}, // NORTH WEST ARROW AND NORTH EAST ARROW
+ { 0x2928, Infix, 5, 5, 0}, // NORTH EAST ARROW AND SOUTH EAST ARROW
+ { 0x2929, Infix, 5, 5, 0}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
+ { 0x292A, Infix, 5, 5, 0}, // SOUTH WEST ARROW AND NORTH WEST ARROW
+ { 0x292B, Infix, 5, 5, 0}, // RISING DIAGONAL CROSSING FALLING DIAGONAL
+ { 0x292C, Infix, 5, 5, 0}, // FALLING DIAGONAL CROSSING RISING DIAGONAL
+ { 0x292D, Infix, 5, 5, 0}, // SOUTH EAST ARROW CROSSING NORTH EAST ARROW
+ { 0x292E, Infix, 5, 5, 0}, // NORTH EAST ARROW CROSSING SOUTH EAST ARROW
+ { 0x292F, Infix, 5, 5, 0}, // FALLING DIAGONAL CROSSING NORTH EAST ARROW
+ { 0x2930, Infix, 5, 5, 0}, // RISING DIAGONAL CROSSING SOUTH EAST ARROW
+ { 0x2931, Infix, 5, 5, 0}, // NORTH EAST ARROW CROSSING NORTH WEST ARROW
+ { 0x2932, Infix, 5, 5, 0}, // NORTH WEST ARROW CROSSING NORTH EAST ARROW
+ { 0x2933, Infix, 5, 5, Accent}, // WAVE ARROW POINTING DIRECTLY RIGHT
+ { 0x2934, Infix, 5, 5, 0}, // ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
+ { 0x2935, Infix, 5, 5, 0}, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+ { 0x2936, Infix, 5, 5, 0}, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
+ { 0x2937, Infix, 5, 5, 0}, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS
+ { 0x2938, Infix, 5, 5, 0}, // RIGHT-SIDE ARC CLOCKWISE ARROW
+ { 0x2939, Infix, 5, 5, 0}, // LEFT-SIDE ARC ANTICLOCKWISE ARROW
+ { 0x293A, Infix, 5, 5, Accent}, // TOP ARC ANTICLOCKWISE ARROW
+ { 0x293B, Infix, 5, 5, Accent}, // BOTTOM ARC ANTICLOCKWISE ARROW
+ { 0x293C, Infix, 5, 5, Accent}, // TOP ARC CLOCKWISE ARROW WITH MINUS
+ { 0x293D, Infix, 5, 5, Accent}, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS
+ { 0x293E, Infix, 5, 5, 0}, // LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW
+ { 0x293F, Infix, 5, 5, 0}, // LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW
+ { 0x2940, Infix, 5, 5, 0}, // ANTICLOCKWISE CLOSED CIRCLE ARROW
+ { 0x2941, Infix, 5, 5, 0}, // CLOCKWISE CLOSED CIRCLE ARROW
+ { 0x2942, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW
+ { 0x2943, Infix, 5, 5, Accent}, // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW
+ { 0x2944, Infix, 5, 5, Accent}, // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW
+ { 0x2945, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW WITH PLUS BELOW
+ { 0x2946, Infix, 5, 5, Accent}, // LEFTWARDS ARROW WITH PLUS BELOW
+ { 0x2947, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW THROUGH X
+ { 0x2948, Infix, 5, 5, Accent}, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE
+ { 0x2949, Infix, 5, 5, 0}, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE
+ { 0x294A, Infix, 5, 5, Accent}, // LEFT BARB UP RIGHT BARB DOWN HARPOON
+ { 0x294B, Infix, 5, 5, Accent}, // LEFT BARB DOWN RIGHT BARB UP HARPOON
+ { 0x294C, Infix, 5, 5, 0}, // UP BARB RIGHT DOWN BARB LEFT HARPOON
+ { 0x294D, Infix, 5, 5, 0}, // UP BARB LEFT DOWN BARB RIGHT HARPOON
+ { 0x294E, Infix, 5, 5, Stretchy | Accent}, // LEFT BARB UP RIGHT BARB UP HARPOON
+ { 0x294F, Infix, 5, 5, Stretchy}, // UP BARB RIGHT DOWN BARB RIGHT HARPOON
+ { 0x2950, Infix, 5, 5, Stretchy | Accent}, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON
+ { 0x2951, Infix, 5, 5, Stretchy}, // UP BARB LEFT DOWN BARB LEFT HARPOON
+ { 0x2952, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON WITH BARB UP TO BAR
+ { 0x2953, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON WITH BARB UP TO BAR
+ { 0x2954, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB RIGHT TO BAR
+ { 0x2955, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR
+ { 0x2956, Infix, 5, 5, Stretchy}, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR
+ { 0x2957, Infix, 5, 5, Stretchy}, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR
+ { 0x2958, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB LEFT TO BAR
+ { 0x2959, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR
+ { 0x295A, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON WITH BARB UP FROM BAR
+ { 0x295B, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR
+ { 0x295C, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR
+ { 0x295D, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR
+ { 0x295E, Infix, 5, 5, Stretchy | Accent}, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR
+ { 0x295F, Infix, 5, 5, Stretchy | Accent}, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR
+ { 0x2960, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB LEFT FROM BAR
+ { 0x2961, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR
+ { 0x2962, Infix, 5, 5, Accent}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ { 0x2963, Infix, 5, 5, 0}, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ { 0x2964, Infix, 5, 5, Accent}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ { 0x2965, Infix, 5, 5, 0}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ { 0x2966, Infix, 5, 5, Accent}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
+ { 0x2967, Infix, 5, 5, Accent}, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ { 0x2968, Infix, 5, 5, Accent}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP
+ { 0x2969, Infix, 5, 5, Accent}, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ { 0x296A, Infix, 5, 5, Accent}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ { 0x296B, Infix, 5, 5, Accent}, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ { 0x296C, Infix, 5, 5, Accent}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ { 0x296D, Infix, 5, 5, Accent}, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ { 0x296E, Infix, 5, 5, Stretchy}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ { 0x296F, Infix, 5, 5, Stretchy}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ { 0x2970, Infix, 5, 5, Accent}, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD
+ { 0x2971, Infix, 5, 5, Accent}, // EQUALS SIGN ABOVE RIGHTWARDS ARROW
+ { 0x2972, Infix, 5, 5, Accent}, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW
+ { 0x2973, Infix, 5, 5, Accent}, // LEFTWARDS ARROW ABOVE TILDE OPERATOR
+ { 0x2974, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR
+ { 0x2975, Infix, 5, 5, Accent}, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO
+ { 0x2976, Infix, 5, 5, Accent}, // LESS-THAN ABOVE LEFTWARDS ARROW
+ { 0x2977, Infix, 5, 5, Accent}, // LEFTWARDS ARROW THROUGH LESS-THAN
+ { 0x2978, Infix, 5, 5, Accent}, // GREATER-THAN ABOVE RIGHTWARDS ARROW
+ { 0x2979, Infix, 5, 5, Accent}, // SUBSET ABOVE RIGHTWARDS ARROW
+ { 0x297A, Infix, 5, 5, Accent}, // LEFTWARDS ARROW THROUGH SUBSET
+ { 0x297B, Infix, 5, 5, Accent}, // SUPERSET ABOVE LEFTWARDS ARROW
+ { 0x297C, Infix, 5, 5, Accent}, // LEFT FISH TAIL
+ { 0x297D, Infix, 5, 5, Accent}, // RIGHT FISH TAIL
+ { 0x297E, Infix, 5, 5, 0}, // UP FISH TAIL
+ { 0x297F, Infix, 5, 5, 0}, // DOWN FISH TAIL
+ { 0x2980, Prefix, 0, 0, Fence | Stretchy}, // TRIPLE VERTICAL BAR DELIMITER
+ { 0x2980, Postfix, 0, 0, Fence | Stretchy}, // TRIPLE VERTICAL BAR DELIMITER
+ { 0x2981, Infix, 3, 3, 0}, // Z NOTATION SPOT
+ { 0x2982, Infix, 3, 3, 0}, // Z NOTATION TYPE COLON
+ { 0x2983, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT WHITE CURLY BRACKET
+ { 0x2984, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT WHITE CURLY BRACKET
+ { 0x2985, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT WHITE PARENTHESIS
+ { 0x2986, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT WHITE PARENTHESIS
+ { 0x2987, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // Z NOTATION LEFT IMAGE BRACKET
+ { 0x2988, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // Z NOTATION RIGHT IMAGE BRACKET
+ { 0x2989, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // Z NOTATION LEFT BINDING BRACKET
+ { 0x298A, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // Z NOTATION RIGHT BINDING BRACKET
+ { 0x298B, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT SQUARE BRACKET WITH UNDERBAR
+ { 0x298C, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT SQUARE BRACKET WITH UNDERBAR
+ { 0x298D, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ { 0x298E, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ { 0x298F, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ { 0x2990, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ { 0x2991, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT ANGLE BRACKET WITH DOT
+ { 0x2992, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT ANGLE BRACKET WITH DOT
+ { 0x2993, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT ARC LESS-THAN BRACKET
+ { 0x2994, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT ARC GREATER-THAN BRACKET
+ { 0x2995, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // DOUBLE LEFT ARC GREATER-THAN BRACKET
+ { 0x2996, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
+ { 0x2997, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT BLACK TORTOISE SHELL BRACKET
+ { 0x2998, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT BLACK TORTOISE SHELL BRACKET
+ { 0x2999, Infix, 3, 3, 0}, // DOTTED FENCE
+ { 0x299A, Infix, 3, 3, 0}, // VERTICAL ZIGZAG LINE
+ { 0x299B, Infix, 3, 3, 0}, // MEASURED ANGLE OPENING LEFT
+ { 0x299C, Infix, 3, 3, 0}, // RIGHT ANGLE VARIANT WITH SQUARE
+ { 0x299D, Infix, 3, 3, 0}, // MEASURED RIGHT ANGLE WITH DOT
+ { 0x299E, Infix, 3, 3, 0}, // ANGLE WITH S INSIDE
+ { 0x299F, Infix, 3, 3, 0}, // ACUTE ANGLE
+ { 0x29A0, Infix, 3, 3, 0}, // SPHERICAL ANGLE OPENING LEFT
+ { 0x29A1, Infix, 3, 3, 0}, // SPHERICAL ANGLE OPENING UP
+ { 0x29A2, Infix, 3, 3, 0}, // TURNED ANGLE
+ { 0x29A3, Infix, 3, 3, 0}, // REVERSED ANGLE
+ { 0x29A4, Infix, 3, 3, 0}, // ANGLE WITH UNDERBAR
+ { 0x29A5, Infix, 3, 3, 0}, // REVERSED ANGLE WITH UNDERBAR
+ { 0x29A6, Infix, 3, 3, 0}, // OBLIQUE ANGLE OPENING UP
+ { 0x29A7, Infix, 3, 3, 0}, // OBLIQUE ANGLE OPENING DOWN
+ { 0x29A8, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT
+ { 0x29A9, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT
+ { 0x29AA, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT
+ { 0x29AB, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT
+ { 0x29AC, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP
+ { 0x29AD, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP
+ { 0x29AE, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN
+ { 0x29AF, Infix, 3, 3, 0}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN
+ { 0x29B0, Infix, 3, 3, 0}, // REVERSED EMPTY SET
+ { 0x29B1, Infix, 3, 3, 0}, // EMPTY SET WITH OVERBAR
+ { 0x29B2, Infix, 3, 3, 0}, // EMPTY SET WITH SMALL CIRCLE ABOVE
+ { 0x29B3, Infix, 3, 3, 0}, // EMPTY SET WITH RIGHT ARROW ABOVE
+ { 0x29B4, Infix, 3, 3, 0}, // EMPTY SET WITH LEFT ARROW ABOVE
+ { 0x29B5, Infix, 3, 3, 0}, // CIRCLE WITH HORIZONTAL BAR
+ { 0x29B6, Infix, 4, 4, 0}, // CIRCLED VERTICAL BAR
+ { 0x29B7, Infix, 4, 4, 0}, // CIRCLED PARALLEL
+ { 0x29B8, Infix, 4, 4, 0}, // CIRCLED REVERSE SOLIDUS
+ { 0x29B9, Infix, 4, 4, 0}, // CIRCLED PERPENDICULAR
+ { 0x29BA, Infix, 4, 4, 0}, // CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR
+ { 0x29BB, Infix, 4, 4, 0}, // CIRCLE WITH SUPERIMPOSED X
+ { 0x29BC, Infix, 4, 4, 0}, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN
+ { 0x29BD, Infix, 4, 4, 0}, // UP ARROW THROUGH CIRCLE
+ { 0x29BE, Infix, 4, 4, 0}, // CIRCLED WHITE BULLET
+ { 0x29BF, Infix, 4, 4, 0}, // CIRCLED BULLET
+ { 0x29C0, Infix, 5, 5, 0}, // CIRCLED LESS-THAN
+ { 0x29C1, Infix, 5, 5, 0}, // CIRCLED GREATER-THAN
+ { 0x29C2, Infix, 3, 3, 0}, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT
+ { 0x29C3, Infix, 3, 3, 0}, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT
+ { 0x29C4, Infix, 4, 4, 0}, // SQUARED RISING DIAGONAL SLASH
+ { 0x29C5, Infix, 4, 4, 0}, // SQUARED FALLING DIAGONAL SLASH
+ { 0x29C6, Infix, 4, 4, 0}, // SQUARED ASTERISK
+ { 0x29C7, Infix, 4, 4, 0}, // SQUARED SMALL CIRCLE
+ { 0x29C8, Infix, 4, 4, 0}, // SQUARED SQUARE
+ { 0x29C9, Infix, 3, 3, 0}, // TWO JOINED SQUARES
+ { 0x29CA, Infix, 3, 3, 0}, // TRIANGLE WITH DOT ABOVE
+ { 0x29CB, Infix, 3, 3, 0}, // TRIANGLE WITH UNDERBAR
+ { 0x29CC, Infix, 3, 3, 0}, // S IN TRIANGLE
+ { 0x29CD, Infix, 3, 3, 0}, // TRIANGLE WITH SERIFS AT BOTTOM
+ { 0x29CE, Infix, 5, 5, 0}, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE
+ { 0x29CF, Infix, 5, 5, 0}, // LEFT TRIANGLE BESIDE VERTICAL BAR
+ { 0x29D0, Infix, 5, 5, 0}, // VERTICAL BAR BESIDE RIGHT TRIANGLE
+ { 0x29D1, Infix, 5, 5, 0}, // BOWTIE WITH LEFT HALF BLACK
+ { 0x29D2, Infix, 5, 5, 0}, // BOWTIE WITH RIGHT HALF BLACK
+ { 0x29D3, Infix, 5, 5, 0}, // BLACK BOWTIE
+ { 0x29D4, Infix, 5, 5, 0}, // TIMES WITH LEFT HALF BLACK
+ { 0x29D5, Infix, 5, 5, 0}, // TIMES WITH RIGHT HALF BLACK
+ { 0x29D6, Infix, 4, 4, 0}, // WHITE HOURGLASS
+ { 0x29D7, Infix, 4, 4, 0}, // BLACK HOURGLASS
+ { 0x29D8, Infix, 3, 3, 0}, // LEFT WIGGLY FENCE
+ { 0x29D9, Infix, 3, 3, 0}, // RIGHT WIGGLY FENCE
+ { 0x29DB, Infix, 3, 3, 0}, // RIGHT DOUBLE WIGGLY FENCE
+ { 0x29DC, Infix, 3, 3, 0}, // INCOMPLETE INFINITY
+ { 0x29DD, Infix, 3, 3, 0}, // TIE OVER INFINITY
+ { 0x29DE, Infix, 5, 5, 0}, // INFINITY NEGATED WITH VERTICAL BAR
+ { 0x29DF, Infix, 3, 3, 0}, // DOUBLE-ENDED MULTIMAP
+ { 0x29E0, Infix, 3, 3, 0}, // SQUARE WITH CONTOURED OUTLINE
+ { 0x29E1, Infix, 5, 5, 0}, // INCREASES AS
+ { 0x29E2, Infix, 4, 4, 0}, // SHUFFLE PRODUCT
+ { 0x29E3, Infix, 5, 5, 0}, // EQUALS SIGN AND SLANTED PARALLEL
+ { 0x29E4, Infix, 5, 5, 0}, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE
+ { 0x29E5, Infix, 5, 5, 0}, // IDENTICAL TO AND SLANTED PARALLEL
+ { 0x29E6, Infix, 5, 5, 0}, // GLEICH STARK
+ { 0x29E7, Infix, 3, 3, 0}, // THERMODYNAMIC
+ { 0x29E8, Infix, 3, 3, 0}, // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK
+ { 0x29E9, Infix, 3, 3, 0}, // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK
+ { 0x29EA, Infix, 3, 3, 0}, // BLACK DIAMOND WITH DOWN ARROW
+ { 0x29EB, Infix, 3, 3, 0}, // BLACK LOZENGE
+ { 0x29EC, Infix, 3, 3, 0}, // WHITE CIRCLE WITH DOWN ARROW
+ { 0x29ED, Infix, 3, 3, 0}, // BLACK CIRCLE WITH DOWN ARROW
+ { 0x29EE, Infix, 3, 3, 0}, // ERROR-BARRED WHITE SQUARE
+ { 0x29EF, Infix, 3, 3, 0}, // ERROR-BARRED BLACK SQUARE
+ { 0x29F0, Infix, 3, 3, 0}, // ERROR-BARRED WHITE DIAMOND
+ { 0x29F1, Infix, 3, 3, 0}, // ERROR-BARRED BLACK DIAMOND
+ { 0x29F2, Infix, 3, 3, 0}, // ERROR-BARRED WHITE CIRCLE
+ { 0x29F3, Infix, 3, 3, 0}, // ERROR-BARRED BLACK CIRCLE
+ { 0x29F4, Infix, 5, 5, 0}, // RULE-DELAYED
+ { 0x29F5, Infix, 4, 4, 0}, // REVERSE SOLIDUS OPERATOR
+ { 0x29F6, Infix, 4, 4, 0}, // SOLIDUS WITH OVERBAR
+ { 0x29F7, Infix, 4, 4, 0}, // REVERSE SOLIDUS WITH HORIZONTAL STROKE
+ { 0x29F8, Infix, 3, 3, 0}, // BIG SOLIDUS
+ { 0x29F9, Infix, 3, 3, 0}, // BIG REVERSE SOLIDUS
+ { 0x29FA, Infix, 3, 3, 0}, // DOUBLE PLUS
+ { 0x29FB, Infix, 3, 3, 0}, // TRIPLE PLUS
+ { 0x29FC, Prefix, 0, 0, Symmetric | Fence | Stretchy}, // LEFT-POINTING CURVED ANGLE BRACKET
+ { 0x29FD, Postfix, 0, 0, Symmetric | Fence | Stretchy}, // RIGHT-POINTING CURVED ANGLE BRACKET
+ { 0x29FE, Infix, 4, 4, 0}, // TINY
+ { 0x29FF, Infix, 4, 4, 0}, // MINY
+ { 0x2A00, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY CIRCLED DOT OPERATOR
+ { 0x2A01, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY CIRCLED PLUS OPERATOR
+ { 0x2A02, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY CIRCLED TIMES OPERATOR
+ { 0x2A03, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY UNION OPERATOR WITH DOT
+ { 0x2A04, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY UNION OPERATOR WITH PLUS
+ { 0x2A05, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY SQUARE INTERSECTION OPERATOR
+ { 0x2A06, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY SQUARE UNION OPERATOR
+ { 0x2A07, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // TWO LOGICAL AND OPERATOR
+ { 0x2A08, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // TWO LOGICAL OR OPERATOR
+ { 0x2A09, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY TIMES OPERATOR
+ { 0x2A0A, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // MODULO TWO SUM
+ { 0x2A0B, Prefix, 1, 2, Symmetric | LargeOp}, // SUMMATION WITH INTEGRAL
+ { 0x2A0C, Prefix, 0, 1, Symmetric | LargeOp}, // QUADRUPLE INTEGRAL OPERATOR
+ { 0x2A0D, Prefix, 1, 2, Symmetric | LargeOp}, // FINITE PART INTEGRAL
+ { 0x2A0E, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH DOUBLE STROKE
+ { 0x2A0F, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL AVERAGE WITH SLASH
+ { 0x2A10, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // CIRCULATION FUNCTION
+ { 0x2A11, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // ANTICLOCKWISE INTEGRATION
+ { 0x2A12, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
+ { 0x2A13, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
+ { 0x2A14, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // LINE INTEGRATION NOT INCLUDING THE POLE
+ { 0x2A15, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL AROUND A POINT OPERATOR
+ { 0x2A16, Prefix, 1, 2, Symmetric | LargeOp}, // QUATERNION INTEGRAL OPERATOR
+ { 0x2A17, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
+ { 0x2A18, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH TIMES SIGN
+ { 0x2A19, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH INTERSECTION
+ { 0x2A1A, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH UNION
+ { 0x2A1B, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH OVERBAR
+ { 0x2A1C, Prefix, 1, 2, Symmetric | LargeOp}, // INTEGRAL WITH UNDERBAR
+ { 0x2A1D, Infix, 3, 3, 0}, // JOIN
+ { 0x2A1E, Infix, 3, 3, 0}, // LARGE LEFT TRIANGLE OPERATOR
+ { 0x2A1F, Infix, 3, 3, 0}, // Z NOTATION SCHEMA COMPOSITION
+ { 0x2A20, Infix, 3, 3, 0}, // Z NOTATION SCHEMA PIPING
+ { 0x2A21, Infix, 3, 3, 0}, // Z NOTATION SCHEMA PROJECTION
+ { 0x2A22, Infix, 4, 4, 0}, // PLUS SIGN WITH SMALL CIRCLE ABOVE
+ { 0x2A23, Infix, 4, 4, 0}, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE
+ { 0x2A24, Infix, 4, 4, 0}, // PLUS SIGN WITH TILDE ABOVE
+ { 0x2A25, Infix, 4, 4, 0}, // PLUS SIGN WITH DOT BELOW
+ { 0x2A26, Infix, 4, 4, 0}, // PLUS SIGN WITH TILDE BELOW
+ { 0x2A27, Infix, 4, 4, 0}, // PLUS SIGN WITH SUBSCRIPT TWO
+ { 0x2A28, Infix, 4, 4, 0}, // PLUS SIGN WITH BLACK TRIANGLE
+ { 0x2A29, Infix, 4, 4, 0}, // MINUS SIGN WITH COMMA ABOVE
+ { 0x2A2A, Infix, 4, 4, 0}, // MINUS SIGN WITH DOT BELOW
+ { 0x2A2B, Infix, 4, 4, 0}, // MINUS SIGN WITH FALLING DOTS
+ { 0x2A2C, Infix, 4, 4, 0}, // MINUS SIGN WITH RISING DOTS
+ { 0x2A2D, Infix, 4, 4, 0}, // PLUS SIGN IN LEFT HALF CIRCLE
+ { 0x2A2E, Infix, 4, 4, 0}, // PLUS SIGN IN RIGHT HALF CIRCLE
+ { 0x2A2F, Infix, 4, 4, 0}, // VECTOR OR CROSS PRODUCT
+ { 0x2A30, Infix, 4, 4, 0}, // MULTIPLICATION SIGN WITH DOT ABOVE
+ { 0x2A31, Infix, 4, 4, 0}, // MULTIPLICATION SIGN WITH UNDERBAR
+ { 0x2A32, Infix, 4, 4, 0}, // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED
+ { 0x2A33, Infix, 4, 4, 0}, // SMASH PRODUCT
+ { 0x2A34, Infix, 4, 4, 0}, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
+ { 0x2A35, Infix, 4, 4, 0}, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
+ { 0x2A36, Infix, 4, 4, 0}, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT
+ { 0x2A37, Infix, 4, 4, 0}, // MULTIPLICATION SIGN IN DOUBLE CIRCLE
+ { 0x2A38, Infix, 4, 4, 0}, // CIRCLED DIVISION SIGN
+ { 0x2A39, Infix, 4, 4, 0}, // PLUS SIGN IN TRIANGLE
+ { 0x2A3A, Infix, 4, 4, 0}, // MINUS SIGN IN TRIANGLE
+ { 0x2A3B, Infix, 4, 4, 0}, // MULTIPLICATION SIGN IN TRIANGLE
+ { 0x2A3C, Infix, 4, 4, 0}, // INTERIOR PRODUCT
+ { 0x2A3D, Infix, 4, 4, 0}, // RIGHTHAND INTERIOR PRODUCT
+ { 0x2A3E, Infix, 4, 4, 0}, // Z NOTATION RELATIONAL COMPOSITION
+ { 0x2A3F, Infix, 4, 4, 0}, // AMALGAMATION OR COPRODUCT
+ { 0x2A40, Infix, 4, 4, 0}, // INTERSECTION WITH DOT
+ { 0x2A41, Infix, 4, 4, 0}, // UNION WITH MINUS SIGN
+ { 0x2A42, Infix, 4, 4, 0}, // UNION WITH OVERBAR
+ { 0x2A43, Infix, 4, 4, 0}, // INTERSECTION WITH OVERBAR
+ { 0x2A44, Infix, 4, 4, 0}, // INTERSECTION WITH LOGICAL AND
+ { 0x2A45, Infix, 4, 4, 0}, // UNION WITH LOGICAL OR
+ { 0x2A46, Infix, 4, 4, 0}, // UNION ABOVE INTERSECTION
+ { 0x2A47, Infix, 4, 4, 0}, // INTERSECTION ABOVE UNION
+ { 0x2A48, Infix, 4, 4, 0}, // UNION ABOVE BAR ABOVE INTERSECTION
+ { 0x2A49, Infix, 4, 4, 0}, // INTERSECTION ABOVE BAR ABOVE UNION
+ { 0x2A4A, Infix, 4, 4, 0}, // UNION BESIDE AND JOINED WITH UNION
+ { 0x2A4B, Infix, 4, 4, 0}, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION
+ { 0x2A4C, Infix, 4, 4, 0}, // CLOSED UNION WITH SERIFS
+ { 0x2A4D, Infix, 4, 4, 0}, // CLOSED INTERSECTION WITH SERIFS
+ { 0x2A4E, Infix, 4, 4, 0}, // DOUBLE SQUARE INTERSECTION
+ { 0x2A4F, Infix, 4, 4, 0}, // DOUBLE SQUARE UNION
+ { 0x2A50, Infix, 4, 4, 0}, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT
+ { 0x2A51, Infix, 4, 4, 0}, // LOGICAL AND WITH DOT ABOVE
+ { 0x2A52, Infix, 4, 4, 0}, // LOGICAL OR WITH DOT ABOVE
+ { 0x2A53, Infix, 4, 4, 0}, // DOUBLE LOGICAL AND
+ { 0x2A54, Infix, 4, 4, 0}, // DOUBLE LOGICAL OR
+ { 0x2A55, Infix, 4, 4, 0}, // TWO INTERSECTING LOGICAL AND
+ { 0x2A56, Infix, 4, 4, 0}, // TWO INTERSECTING LOGICAL OR
+ { 0x2A57, Infix, 4, 4, 0}, // SLOPING LARGE OR
+ { 0x2A58, Infix, 4, 4, 0}, // SLOPING LARGE AND
+ { 0x2A59, Infix, 5, 5, 0}, // LOGICAL OR OVERLAPPING LOGICAL AND
+ { 0x2A5A, Infix, 4, 4, 0}, // LOGICAL AND WITH MIDDLE STEM
+ { 0x2A5B, Infix, 4, 4, 0}, // LOGICAL OR WITH MIDDLE STEM
+ { 0x2A5C, Infix, 4, 4, 0}, // LOGICAL AND WITH HORIZONTAL DASH
+ { 0x2A5D, Infix, 4, 4, 0}, // LOGICAL OR WITH HORIZONTAL DASH
+ { 0x2A5E, Infix, 4, 4, 0}, // LOGICAL AND WITH DOUBLE OVERBAR
+ { 0x2A5F, Infix, 4, 4, 0}, // LOGICAL AND WITH UNDERBAR
+ { 0x2A60, Infix, 4, 4, 0}, // LOGICAL AND WITH DOUBLE UNDERBAR
+ { 0x2A61, Infix, 4, 4, 0}, // SMALL VEE WITH UNDERBAR
+ { 0x2A62, Infix, 4, 4, 0}, // LOGICAL OR WITH DOUBLE OVERBAR
+ { 0x2A63, Infix, 4, 4, 0}, // LOGICAL OR WITH DOUBLE UNDERBAR
+ { 0x2A64, Infix, 4, 4, 0}, // Z NOTATION DOMAIN ANTIRESTRICTION
+ { 0x2A65, Infix, 4, 4, 0}, // Z NOTATION RANGE ANTIRESTRICTION
+ { 0x2A66, Infix, 5, 5, 0}, // EQUALS SIGN WITH DOT BELOW
+ { 0x2A67, Infix, 5, 5, 0}, // IDENTICAL WITH DOT ABOVE
+ { 0x2A68, Infix, 5, 5, 0}, // TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE
+ { 0x2A69, Infix, 5, 5, 0}, // TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE
+ { 0x2A6A, Infix, 5, 5, 0}, // TILDE OPERATOR WITH DOT ABOVE
+ { 0x2A6B, Infix, 5, 5, 0}, // TILDE OPERATOR WITH RISING DOTS
+ { 0x2A6C, Infix, 5, 5, 0}, // SIMILAR MINUS SIMILAR
+ { 0x2A6D, Infix, 5, 5, 0}, // CONGRUENT WITH DOT ABOVE
+ { 0x2A6E, Infix, 5, 5, 0}, // EQUALS WITH ASTERISK
+ { 0x2A6F, Infix, 5, 5, 0}, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT
+ { 0x2A70, Infix, 5, 5, 0}, // APPROXIMATELY EQUAL OR EQUAL TO
+ { 0x2A71, Infix, 4, 4, 0}, // EQUALS SIGN ABOVE PLUS SIGN
+ { 0x2A72, Infix, 4, 4, 0}, // PLUS SIGN ABOVE EQUALS SIGN
+ { 0x2A73, Infix, 5, 5, 0}, // EQUALS SIGN ABOVE TILDE OPERATOR
+ { 0x2A74, Infix, 5, 5, 0}, // DOUBLE COLON EQUAL
+ { 0x2A75, Infix, 5, 5, 0}, // TWO CONSECUTIVE EQUALS SIGNS
+ { 0x2A76, Infix, 5, 5, 0}, // THREE CONSECUTIVE EQUALS SIGNS
+ { 0x2A77, Infix, 5, 5, 0}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+ { 0x2A78, Infix, 5, 5, 0}, // EQUIVALENT WITH FOUR DOTS ABOVE
+ { 0x2A79, Infix, 5, 5, 0}, // LESS-THAN WITH CIRCLE INSIDE
+ { 0x2A7A, Infix, 5, 5, 0}, // GREATER-THAN WITH CIRCLE INSIDE
+ { 0x2A7B, Infix, 5, 5, 0}, // LESS-THAN WITH QUESTION MARK ABOVE
+ { 0x2A7C, Infix, 5, 5, 0}, // GREATER-THAN WITH QUESTION MARK ABOVE
+ { 0x2A7D, Infix, 5, 5, 0}, // LESS-THAN OR SLANTED EQUAL TO
+ { 0x2A7E, Infix, 5, 5, 0}, // GREATER-THAN OR SLANTED EQUAL TO
+ { 0x2A7F, Infix, 5, 5, 0}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ { 0x2A80, Infix, 5, 5, 0}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ { 0x2A81, Infix, 5, 5, 0}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ { 0x2A82, Infix, 5, 5, 0}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ { 0x2A83, Infix, 5, 5, 0}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
+ { 0x2A84, Infix, 5, 5, 0}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
+ { 0x2A85, Infix, 5, 5, 0}, // LESS-THAN OR APPROXIMATE
+ { 0x2A86, Infix, 5, 5, 0}, // GREATER-THAN OR APPROXIMATE
+ { 0x2A87, Infix, 5, 5, 0}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+ { 0x2A88, Infix, 5, 5, 0}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+ { 0x2A89, Infix, 5, 5, 0}, // LESS-THAN AND NOT APPROXIMATE
+ { 0x2A8A, Infix, 5, 5, 0}, // GREATER-THAN AND NOT APPROXIMATE
+ { 0x2A8B, Infix, 5, 5, 0}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+ { 0x2A8C, Infix, 5, 5, 0}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+ { 0x2A8D, Infix, 5, 5, 0}, // LESS-THAN ABOVE SIMILAR OR EQUAL
+ { 0x2A8E, Infix, 5, 5, 0}, // GREATER-THAN ABOVE SIMILAR OR EQUAL
+ { 0x2A8F, Infix, 5, 5, 0}, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN
+ { 0x2A90, Infix, 5, 5, 0}, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN
+ { 0x2A91, Infix, 5, 5, 0}, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
+ { 0x2A92, Infix, 5, 5, 0}, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
+ { 0x2A93, Infix, 5, 5, 0}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
+ { 0x2A94, Infix, 5, 5, 0}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
+ { 0x2A95, Infix, 5, 5, 0}, // SLANTED EQUAL TO OR LESS-THAN
+ { 0x2A96, Infix, 5, 5, 0}, // SLANTED EQUAL TO OR GREATER-THAN
+ { 0x2A97, Infix, 5, 5, 0}, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
+ { 0x2A98, Infix, 5, 5, 0}, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
+ { 0x2A99, Infix, 5, 5, 0}, // DOUBLE-LINE EQUAL TO OR LESS-THAN
+ { 0x2A9A, Infix, 5, 5, 0}, // DOUBLE-LINE EQUAL TO OR GREATER-THAN
+ { 0x2A9B, Infix, 5, 5, 0}, // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN
+ { 0x2A9C, Infix, 5, 5, 0}, // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN
+ { 0x2A9D, Infix, 5, 5, 0}, // SIMILAR OR LESS-THAN
+ { 0x2A9E, Infix, 5, 5, 0}, // SIMILAR OR GREATER-THAN
+ { 0x2A9F, Infix, 5, 5, 0}, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN
+ { 0x2AA0, Infix, 5, 5, 0}, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN
+ { 0x2AA1, Infix, 5, 5, 0}, // DOUBLE NESTED LESS-THAN
+ { 0x2AA2, Infix, 5, 5, 0}, // DOUBLE NESTED GREATER-THAN
+ { 0x2AA3, Infix, 5, 5, 0}, // DOUBLE NESTED LESS-THAN WITH UNDERBAR
+ { 0x2AA4, Infix, 5, 5, 0}, // GREATER-THAN OVERLAPPING LESS-THAN
+ { 0x2AA5, Infix, 5, 5, 0}, // GREATER-THAN BESIDE LESS-THAN
+ { 0x2AA6, Infix, 5, 5, 0}, // LESS-THAN CLOSED BY CURVE
+ { 0x2AA7, Infix, 5, 5, 0}, // GREATER-THAN CLOSED BY CURVE
+ { 0x2AA8, Infix, 5, 5, 0}, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ { 0x2AA9, Infix, 5, 5, 0}, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ { 0x2AAA, Infix, 5, 5, 0}, // SMALLER THAN
+ { 0x2AAB, Infix, 5, 5, 0}, // LARGER THAN
+ { 0x2AAC, Infix, 5, 5, 0}, // SMALLER THAN OR EQUAL TO
+ { 0x2AAD, Infix, 5, 5, 0}, // LARGER THAN OR EQUAL TO
+ { 0x2AAE, Infix, 5, 5, 0}, // EQUALS SIGN WITH BUMPY ABOVE
+ { 0x2AAF, Infix, 5, 5, 0}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ { 0x2AB0, Infix, 5, 5, 0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ { 0x2AB1, Infix, 5, 5, 0}, // PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO
+ { 0x2AB2, Infix, 5, 5, 0}, // SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO
+ { 0x2AB3, Infix, 5, 5, 0}, // PRECEDES ABOVE EQUALS SIGN
+ { 0x2AB4, Infix, 5, 5, 0}, // SUCCEEDS ABOVE EQUALS SIGN
+ { 0x2AB5, Infix, 5, 5, 0}, // PRECEDES ABOVE NOT EQUAL TO
+ { 0x2AB6, Infix, 5, 5, 0}, // SUCCEEDS ABOVE NOT EQUAL TO
+ { 0x2AB7, Infix, 5, 5, 0}, // PRECEDES ABOVE ALMOST EQUAL TO
+ { 0x2AB8, Infix, 5, 5, 0}, // SUCCEEDS ABOVE ALMOST EQUAL TO
+ { 0x2AB9, Infix, 5, 5, 0}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
+ { 0x2ABA, Infix, 5, 5, 0}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+ { 0x2ABB, Infix, 5, 5, 0}, // DOUBLE PRECEDES
+ { 0x2ABC, Infix, 5, 5, 0}, // DOUBLE SUCCEEDS
+ { 0x2ABD, Infix, 5, 5, 0}, // SUBSET WITH DOT
+ { 0x2ABE, Infix, 5, 5, 0}, // SUPERSET WITH DOT
+ { 0x2ABF, Infix, 5, 5, 0}, // SUBSET WITH PLUS SIGN BELOW
+ { 0x2AC0, Infix, 5, 5, 0}, // SUPERSET WITH PLUS SIGN BELOW
+ { 0x2AC1, Infix, 5, 5, 0}, // SUBSET WITH MULTIPLICATION SIGN BELOW
+ { 0x2AC2, Infix, 5, 5, 0}, // SUPERSET WITH MULTIPLICATION SIGN BELOW
+ { 0x2AC3, Infix, 5, 5, 0}, // SUBSET OF OR EQUAL TO WITH DOT ABOVE
+ { 0x2AC4, Infix, 5, 5, 0}, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
+ { 0x2AC5, Infix, 5, 5, 0}, // SUBSET OF ABOVE EQUALS SIGN
+ { 0x2AC6, Infix, 5, 5, 0}, // SUPERSET OF ABOVE EQUALS SIGN
+ { 0x2AC7, Infix, 5, 5, 0}, // SUBSET OF ABOVE TILDE OPERATOR
+ { 0x2AC8, Infix, 5, 5, 0}, // SUPERSET OF ABOVE TILDE OPERATOR
+ { 0x2AC9, Infix, 5, 5, 0}, // SUBSET OF ABOVE ALMOST EQUAL TO
+ { 0x2ACA, Infix, 5, 5, 0}, // SUPERSET OF ABOVE ALMOST EQUAL TO
+ { 0x2ACB, Infix, 5, 5, 0}, // SUBSET OF ABOVE NOT EQUAL TO
+ { 0x2ACC, Infix, 5, 5, 0}, // SUPERSET OF ABOVE NOT EQUAL TO
+ { 0x2ACD, Infix, 5, 5, 0}, // SQUARE LEFT OPEN BOX OPERATOR
+ { 0x2ACE, Infix, 5, 5, 0}, // SQUARE RIGHT OPEN BOX OPERATOR
+ { 0x2ACF, Infix, 5, 5, 0}, // CLOSED SUBSET
+ { 0x2AD0, Infix, 5, 5, 0}, // CLOSED SUPERSET
+ { 0x2AD1, Infix, 5, 5, 0}, // CLOSED SUBSET OR EQUAL TO
+ { 0x2AD2, Infix, 5, 5, 0}, // CLOSED SUPERSET OR EQUAL TO
+ { 0x2AD3, Infix, 5, 5, 0}, // SUBSET ABOVE SUPERSET
+ { 0x2AD4, Infix, 5, 5, 0}, // SUPERSET ABOVE SUBSET
+ { 0x2AD5, Infix, 5, 5, 0}, // SUBSET ABOVE SUBSET
+ { 0x2AD6, Infix, 5, 5, 0}, // SUPERSET ABOVE SUPERSET
+ { 0x2AD7, Infix, 5, 5, 0}, // SUPERSET BESIDE SUBSET
+ { 0x2AD8, Infix, 5, 5, 0}, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET
+ { 0x2AD9, Infix, 5, 5, 0}, // ELEMENT OF OPENING DOWNWARDS
+ { 0x2ADA, Infix, 5, 5, 0}, // PITCHFORK WITH TEE TOP
+ { 0x2ADB, Infix, 5, 5, 0}, // TRANSVERSAL INTERSECTION
+ { 0x2ADD, Infix, 5, 5, 0}, // NONFORKING
+ { 0x2ADE, Infix, 5, 5, 0}, // SHORT LEFT TACK
+ { 0x2ADF, Infix, 5, 5, 0}, // SHORT DOWN TACK
+ { 0x2AE0, Infix, 5, 5, 0}, // SHORT UP TACK
+ { 0x2AE1, Infix, 5, 5, 0}, // PERPENDICULAR WITH S
+ { 0x2AE2, Infix, 5, 5, 0}, // VERTICAL BAR TRIPLE RIGHT TURNSTILE
+ { 0x2AE3, Infix, 5, 5, 0}, // DOUBLE VERTICAL BAR LEFT TURNSTILE
+ { 0x2AE4, Infix, 5, 5, 0}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
+ { 0x2AE5, Infix, 5, 5, 0}, // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE
+ { 0x2AE6, Infix, 5, 5, 0}, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL
+ { 0x2AE7, Infix, 5, 5, 0}, // SHORT DOWN TACK WITH OVERBAR
+ { 0x2AE8, Infix, 5, 5, 0}, // SHORT UP TACK WITH UNDERBAR
+ { 0x2AE9, Infix, 5, 5, 0}, // SHORT UP TACK ABOVE SHORT DOWN TACK
+ { 0x2AEA, Infix, 5, 5, 0}, // DOUBLE DOWN TACK
+ { 0x2AEB, Infix, 5, 5, 0}, // DOUBLE UP TACK
+ { 0x2AEC, Infix, 5, 5, 0}, // DOUBLE STROKE NOT SIGN
+ { 0x2AED, Infix, 5, 5, 0}, // REVERSED DOUBLE STROKE NOT SIGN
+ { 0x2AEE, Infix, 5, 5, 0}, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH
+ { 0x2AEF, Infix, 5, 5, 0}, // VERTICAL LINE WITH CIRCLE ABOVE
+ { 0x2AF0, Infix, 5, 5, 0}, // VERTICAL LINE WITH CIRCLE BELOW
+ { 0x2AF1, Infix, 5, 5, 0}, // DOWN TACK WITH CIRCLE BELOW
+ { 0x2AF2, Infix, 5, 5, 0}, // PARALLEL WITH HORIZONTAL STROKE
+ { 0x2AF3, Infix, 5, 5, 0}, // PARALLEL WITH TILDE OPERATOR
+ { 0x2AF4, Infix, 4, 4, 0}, // TRIPLE VERTICAL BAR BINARY RELATION
+ { 0x2AF5, Infix, 4, 4, 0}, // TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE
+ { 0x2AF6, Infix, 4, 4, 0}, // TRIPLE COLON OPERATOR
+ { 0x2AF7, Infix, 5, 5, 0}, // TRIPLE NESTED LESS-THAN
+ { 0x2AF8, Infix, 5, 5, 0}, // TRIPLE NESTED GREATER-THAN
+ { 0x2AF9, Infix, 5, 5, 0}, // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO
+ { 0x2AFA, Infix, 5, 5, 0}, // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO
+ { 0x2AFB, Infix, 4, 4, 0}, // TRIPLE SOLIDUS BINARY RELATION
+ { 0x2AFC, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // LARGE TRIPLE VERTICAL BAR OPERATOR
+ { 0x2AFD, Infix, 4, 4, 0}, // DOUBLE SOLIDUS OPERATOR
+ { 0x2AFE, Infix, 3, 3, 0}, // WHITE VERTICAL BAR
+ { 0x2AFF, Prefix, 1, 2, Symmetric | LargeOp | MovableLimits}, // N-ARY WHITE VERTICAL BAR
+ { 0x2B45, Infix, 5, 5, Stretchy}, // LEFTWARDS QUADRUPLE ARROW
+ { 0x2B46, Infix, 5, 5, Stretchy}, // RIGHTWARDS QUADRUPLE ARROW
+ { 0x1EEF0, Prefix, 0, 0, Stretchy }, // ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL
+ { 0x1EEF1, Prefix, 0, 0, Stretchy } // ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
+};
+
+// A list of operators that stretch in the horizontal direction. This has been generated from Mozilla's MathML operator dictionary.
+static inline UChar32 ExtractKeyHorizontal(const UChar32* entry) { return *entry; }
+static const UChar32 horizontalOperators[] = {
+ 0x003D, 0x005E, 0x005F, 0x007E, 0x00AF, 0x02C6, 0x02C7, 0x02C9, 0x02CD, 0x02DC, 0x02F7, 0x0302, 0x0332, 0x203E, 0x20D0, 0x20D1, 0x20D6, 0x20D7, 0x20E1, 0x2190, 0x2192, 0x2194, 0x2198, 0x2199, 0x219C, 0x219D, 0x219E, 0x21A0, 0x21A2, 0x21A3, 0x21A4, 0x21A6, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21B4, 0x21B9, 0x21BC, 0x21BD, 0x21C0, 0x21C1, 0x21C4, 0x21C6, 0x21C7, 0x21C9, 0x21CB, 0x21CC, 0x21D0, 0x21D2, 0x21D4, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21E0, 0x21E2, 0x21E4, 0x21E5, 0x21E6, 0x21E8, 0x21F0, 0x21F6, 0x21FD, 0x21FE, 0x21FF, 0x23B4, 0x23B5, 0x23DC, 0x23DD, 0x23DE, 0x23DF, 0x23E0, 0x23E1, 0x2500, 0x27F5, 0x27F6, 0x27F7, 0x27F8, 0x27F9, 0x27FA, 0x27FB, 0x27FC, 0x27FD, 0x27FE, 0x27FF, 0x290C, 0x290D, 0x290E, 0x290F, 0x2910, 0x294E, 0x2950, 0x2952, 0x2953, 0x2956, 0x2957, 0x295A, 0x295B, 0x295E, 0x295F, 0x2B45, 0x2B46, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0x1EEF0, 0x1EEF1
+};
+
+std::optional<Property> MathMLOperatorDictionary::search(UChar32 character, Form form, bool explicitForm)
+{
+ if (!character)
+ return std::nullopt;
+
+ // We try and find the default values from the operator dictionary.
+ if (auto* entry = tryBinarySearch<const Entry, Key>(dictionary, dictionarySize, Key(character, form), ExtractKey))
+ return ExtractProperty(*entry);
+
+ if (explicitForm)
+ return std::nullopt;
+
+ // If we did not find the desired operator form and if it was not set explicitely, we use the first one in the following order: Infix, Prefix, Postfix.
+ // This is to handle bad MathML markup without explicit <mrow> delimiters like "<mo>(</mo><mi>a</mi><mo>)</mo><mo>(</mo><mi>b</mi><mo>)</mo>" where innerfences should not be considered infix.
+ if (auto* entry = tryBinarySearch<const Entry, UChar32>(dictionary, dictionarySize, character, ExtractChar)) {
+ // There are at most two other entries before the one found.
+ if (entry != dictionary && (entry - 1)->character == character)
+ entry--;
+ if (entry != dictionary && (entry - 1)->character == character)
+ entry--;
+ return ExtractProperty(*entry);
+ }
+
+ return std::nullopt;
+}
+
+bool MathMLOperatorDictionary::isVertical(UChar32 textContent)
+{
+ return !tryBinarySearch<const UChar32, UChar32>(horizontalOperators, WTF_ARRAY_LENGTH(horizontalOperators), textContent, ExtractKeyHorizontal);
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLOperatorDictionary.h b/Source/WebCore/mathml/MathMLOperatorDictionary.h
new file mode 100644
index 000000000..e0316d714
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLOperatorDictionary.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Frederic Wang (fred.wang@free.fr). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include <unicode/utypes.h>
+#include <wtf/Optional.h>
+
+namespace WebCore {
+
+namespace MathMLOperatorDictionary {
+enum Form { Infix, Prefix, Postfix };
+enum Flag {
+ Accent = 0x1, // FIXME: This must be used to implement accentunder/accent on munderover (https://bugs.webkit.org/show_bug.cgi?id=124826).
+ Fence = 0x2, // This has no visual effect but allows to expose semantic information via the accessibility tree.
+ LargeOp = 0x4,
+ MovableLimits = 0x8,
+ Separator = 0x10, // This has no visual effect but allows to expose semantic information via the accessibility tree.
+ Stretchy = 0x20,
+ Symmetric = 0x40
+};
+const unsigned allFlags = Accent | Fence | LargeOp | MovableLimits | Separator | Stretchy | Symmetric;
+struct Property {
+ MathMLOperatorDictionary::Form form;
+ // Default leading and trailing spaces are "thickmathspace".
+ unsigned short leadingSpaceInMathUnit { 5 };
+ unsigned short trailingSpaceInMathUnit { 5 };
+ // Default operator properties are all set to "false".
+ unsigned short flags { 0 };
+};
+std::optional<Property> search(UChar32, Form, bool explicitForm);
+bool isVertical(UChar32);
+}
+
+}
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLOperatorElement.cpp b/Source/WebCore/mathml/MathMLOperatorElement.cpp
new file mode 100644
index 000000000..8d35be300
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLOperatorElement.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLOperatorElement.h"
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLOperator.h"
+#include <wtf/unicode/CharacterNames.h>
+
+namespace WebCore {
+
+using namespace MathMLNames;
+using namespace MathMLOperatorDictionary;
+
+MathMLOperatorElement::MathMLOperatorElement(const QualifiedName& tagName, Document& document)
+ : MathMLTokenElement(tagName, document)
+{
+}
+
+Ref<MathMLOperatorElement> MathMLOperatorElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLOperatorElement(tagName, document));
+}
+
+MathMLOperatorElement::OperatorChar MathMLOperatorElement::parseOperatorChar(const String& string)
+{
+ OperatorChar operatorChar;
+ // FIXME: This operator dictionary does not accept multiple characters (https://webkit.org/b/124828).
+ if (auto codePoint = convertToSingleCodePoint(string)) {
+ auto character = codePoint.value();
+ // The minus sign renders better than the hyphen sign used in some MathML formulas.
+ if (character == hyphenMinus)
+ character = minusSign;
+ operatorChar.character = character;
+ operatorChar.isVertical = isVertical(operatorChar.character);
+ }
+ return operatorChar;
+}
+
+const MathMLOperatorElement::OperatorChar& MathMLOperatorElement::operatorChar()
+{
+ if (!m_operatorChar)
+ m_operatorChar = parseOperatorChar(textContent());
+ return m_operatorChar.value();
+}
+
+Property MathMLOperatorElement::computeDictionaryProperty()
+{
+ Property dictionaryProperty;
+
+ // We first determine the form attribute and use the default spacing and properties.
+ const auto& value = attributeWithoutSynchronization(formAttr);
+ bool explicitForm = true;
+ if (value == "prefix")
+ dictionaryProperty.form = Prefix;
+ else if (value == "infix")
+ dictionaryProperty.form = Infix;
+ else if (value == "postfix")
+ dictionaryProperty.form = Postfix;
+ else {
+ // FIXME: We should use more advanced heuristics indicated in the specification to determine the operator form (https://bugs.webkit.org/show_bug.cgi?id=124829).
+ explicitForm = false;
+ if (!previousSibling() && nextSibling())
+ dictionaryProperty.form = Prefix;
+ else if (previousSibling() && !nextSibling())
+ dictionaryProperty.form = Postfix;
+ else
+ dictionaryProperty.form = Infix;
+ }
+
+ // We then try and find an entry in the operator dictionary to override the default values.
+ if (auto entry = search(operatorChar().character, dictionaryProperty.form, explicitForm))
+ dictionaryProperty = entry.value();
+
+ return dictionaryProperty;
+}
+
+const Property& MathMLOperatorElement::dictionaryProperty()
+{
+ if (!m_dictionaryProperty)
+ m_dictionaryProperty = computeDictionaryProperty();
+ return m_dictionaryProperty.value();
+}
+
+static const QualifiedName& propertyFlagToAttributeName(MathMLOperatorDictionary::Flag flag)
+{
+ switch (flag) {
+ case Accent:
+ return accentAttr;
+ case Fence:
+ return fenceAttr;
+ case LargeOp:
+ return largeopAttr;
+ case MovableLimits:
+ return movablelimitsAttr;
+ case Separator:
+ return separatorAttr;
+ case Stretchy:
+ return stretchyAttr;
+ case Symmetric:
+ return symmetricAttr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullQName();
+}
+
+void MathMLOperatorElement::computeOperatorFlag(MathMLOperatorDictionary::Flag flag)
+{
+ ASSERT(m_properties.dirtyFlags & flag);
+
+ std::optional<BooleanValue> property;
+ const auto& name = propertyFlagToAttributeName(flag);
+ const BooleanValue& value = cachedBooleanAttribute(name, property);
+ switch (value) {
+ case BooleanValue::True:
+ m_properties.flags |= flag;
+ break;
+ case BooleanValue::False:
+ m_properties.flags &= ~flag;
+ break;
+ case BooleanValue::Default:
+ // By default, we use the value specified in the operator dictionary.
+ if (dictionaryProperty().flags & flag)
+ m_properties.flags |= flag;
+ else
+ m_properties.flags &= ~flag;
+ break;
+ }
+}
+
+bool MathMLOperatorElement::hasProperty(MathMLOperatorDictionary::Flag flag)
+{
+ if (m_properties.dirtyFlags & flag) {
+ computeOperatorFlag(flag);
+ m_properties.dirtyFlags &= ~flag;
+ }
+ return m_properties.flags & flag;
+}
+
+MathMLElement::Length MathMLOperatorElement::defaultLeadingSpace()
+{
+ Length space;
+ space.type = LengthType::MathUnit;
+ space.value = static_cast<float>(dictionaryProperty().leadingSpaceInMathUnit);
+ return space;
+}
+
+MathMLElement::Length MathMLOperatorElement::defaultTrailingSpace()
+{
+ Length space;
+ space.type = LengthType::MathUnit;
+ space.value = static_cast<float>(dictionaryProperty().trailingSpaceInMathUnit);
+ return space;
+}
+
+const MathMLElement::Length& MathMLOperatorElement::leadingSpace()
+{
+ return cachedMathMLLength(MathMLNames::lspaceAttr, m_leadingSpace);
+}
+
+const MathMLElement::Length& MathMLOperatorElement::trailingSpace()
+{
+ return cachedMathMLLength(MathMLNames::rspaceAttr, m_trailingSpace);
+}
+
+const MathMLElement::Length& MathMLOperatorElement::minSize()
+{
+ return cachedMathMLLength(MathMLNames::minsizeAttr, m_minSize);
+}
+
+const MathMLElement::Length& MathMLOperatorElement::maxSize()
+{
+ if (m_maxSize)
+ return m_maxSize.value();
+
+ const AtomicString& value = attributeWithoutSynchronization(MathMLNames::maxsizeAttr);
+ if (value == "infinity") {
+ Length maxsize;
+ maxsize.type = LengthType::Infinity;
+ m_maxSize = maxsize;
+ } else
+ m_maxSize = parseMathMLLength(value);
+
+ return m_maxSize.value();
+}
+
+void MathMLOperatorElement::childrenChanged(const ChildChange& change)
+{
+ m_operatorChar = std::nullopt;
+ m_dictionaryProperty = std::nullopt;
+ m_properties.dirtyFlags = MathMLOperatorDictionary::allFlags;
+ MathMLTokenElement::childrenChanged(change);
+}
+
+static std::optional<MathMLOperatorDictionary::Flag> attributeNameToPropertyFlag(const QualifiedName& name)
+{
+ if (name == accentAttr)
+ return Accent;
+ if (name == fenceAttr)
+ return Fence;
+ if (name == largeopAttr)
+ return LargeOp;
+ if (name == movablelimitsAttr)
+ return MovableLimits;
+ if (name == separatorAttr)
+ return Separator;
+ if (name == stretchyAttr)
+ return Stretchy;
+ if (name == symmetricAttr)
+ return Symmetric;
+ return std::nullopt;
+}
+
+void MathMLOperatorElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == formAttr) {
+ m_dictionaryProperty = std::nullopt;
+ m_properties.dirtyFlags = MathMLOperatorDictionary::allFlags;
+ } else if (auto flag = attributeNameToPropertyFlag(name))
+ m_properties.dirtyFlags |= flag.value();
+ else if (name == lspaceAttr)
+ m_leadingSpace = std::nullopt;
+ else if (name == rspaceAttr)
+ m_trailingSpace = std::nullopt;
+ else if (name == minsizeAttr)
+ m_minSize = std::nullopt;
+ else if (name == maxsizeAttr)
+ m_maxSize = std::nullopt;
+
+ if ((name == stretchyAttr || name == lspaceAttr || name == rspaceAttr || name == movablelimitsAttr) && renderer()) {
+ downcast<RenderMathMLOperator>(*renderer()).updateFromElement();
+ return;
+ }
+
+ MathMLTokenElement::parseAttribute(name, value);
+}
+
+RenderPtr<RenderElement> MathMLOperatorElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(MathMLNames::moTag));
+ return createRenderer<RenderMathMLOperator>(*this, WTFMove(style));
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLOperatorElement.h b/Source/WebCore/mathml/MathMLOperatorElement.h
new file mode 100644
index 000000000..5defd77fe
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLOperatorElement.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLOperatorDictionary.h"
+#include "MathMLTokenElement.h"
+
+namespace WebCore {
+
+class MathMLOperatorElement final : public MathMLTokenElement {
+public:
+ static Ref<MathMLOperatorElement> create(const QualifiedName& tagName, Document&);
+ struct OperatorChar {
+ UChar32 character { 0 };
+ bool isVertical { true };
+ };
+ static OperatorChar parseOperatorChar(const String&);
+ const OperatorChar& operatorChar();
+ void setOperatorFormDirty() { m_dictionaryProperty = std::nullopt; }
+ MathMLOperatorDictionary::Form form() { return dictionaryProperty().form; }
+ bool hasProperty(MathMLOperatorDictionary::Flag);
+ Length defaultLeadingSpace();
+ Length defaultTrailingSpace();
+ const Length& leadingSpace();
+ const Length& trailingSpace();
+ const Length& minSize();
+ const Length& maxSize();
+
+private:
+ MathMLOperatorElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void childrenChanged(const ChildChange&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+
+ std::optional<OperatorChar> m_operatorChar;
+
+ std::optional<MathMLOperatorDictionary::Property> m_dictionaryProperty;
+ MathMLOperatorDictionary::Property computeDictionaryProperty();
+ const MathMLOperatorDictionary::Property& dictionaryProperty();
+
+ struct OperatorProperties {
+ unsigned short flags;
+ unsigned short dirtyFlags { MathMLOperatorDictionary::allFlags };
+ };
+ OperatorProperties m_properties;
+ void computeOperatorFlag(MathMLOperatorDictionary::Flag);
+
+ std::optional<Length> m_leadingSpace;
+ std::optional<Length> m_trailingSpace;
+ std::optional<Length> m_minSize;
+ std::optional<Length> m_maxSize;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLPaddedElement.cpp b/Source/WebCore/mathml/MathMLPaddedElement.cpp
new file mode 100644
index 000000000..b2f446d83
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLPaddedElement.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLPaddedElement.h"
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLPadded.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+inline MathMLPaddedElement::MathMLPaddedElement(const QualifiedName& tagName, Document& document)
+ : MathMLRowElement(tagName, document)
+{
+}
+
+Ref<MathMLPaddedElement> MathMLPaddedElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLPaddedElement(tagName, document));
+}
+
+const MathMLElement::Length& MathMLPaddedElement::width()
+{
+ return cachedMathMLLength(MathMLNames::widthAttr, m_width);
+}
+
+const MathMLElement::Length& MathMLPaddedElement::height()
+{
+ return cachedMathMLLength(MathMLNames::heightAttr, m_height);
+}
+
+const MathMLElement::Length& MathMLPaddedElement::depth()
+{
+ return cachedMathMLLength(MathMLNames::depthAttr, m_depth);
+}
+
+const MathMLElement::Length& MathMLPaddedElement::lspace()
+{
+ return cachedMathMLLength(MathMLNames::lspaceAttr, m_lspace);
+}
+
+const MathMLElement::Length& MathMLPaddedElement::voffset()
+{
+ return cachedMathMLLength(MathMLNames::voffsetAttr, m_voffset);
+}
+
+void MathMLPaddedElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == widthAttr)
+ m_width = std::nullopt;
+ else if (name == heightAttr)
+ m_height = std::nullopt;
+ else if (name == depthAttr)
+ m_depth = std::nullopt;
+ else if (name == lspaceAttr)
+ m_lspace = std::nullopt;
+ else if (name == voffsetAttr)
+ m_voffset = std::nullopt;
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+RenderPtr<RenderElement> MathMLPaddedElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(MathMLNames::mpaddedTag));
+ return createRenderer<RenderMathMLPadded>(*this, WTFMove(style));
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLPaddedElement.h b/Source/WebCore/mathml/MathMLPaddedElement.h
new file mode 100644
index 000000000..7ca373e45
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLPaddedElement.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLRowElement.h"
+
+namespace WebCore {
+
+class MathMLPaddedElement final : public MathMLRowElement {
+public:
+ static Ref<MathMLPaddedElement> create(const QualifiedName& tagName, Document&);
+ // FIXME: Pseudo-units are not supported yet (https://bugs.webkit.org/show_bug.cgi?id=85730).
+ const Length& width();
+ const Length& height();
+ const Length& depth();
+ const Length& lspace();
+ const Length& voffset();
+private:
+ MathMLPaddedElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+
+ std::optional<Length> m_width;
+ std::optional<Length> m_height;
+ std::optional<Length> m_depth;
+ std::optional<Length> m_lspace;
+ std::optional<Length> m_voffset;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLPresentationElement.cpp b/Source/WebCore/mathml/MathMLPresentationElement.cpp
new file mode 100644
index 000000000..e2c7d7945
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLPresentationElement.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MathMLPresentationElement.h"
+
+#if ENABLE(MATHML)
+
+#include "ElementIterator.h"
+#include "HTMLHtmlElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
+#include "MathMLMathElement.h"
+#include "MathMLNames.h"
+#include "RenderMathMLBlock.h"
+#include "RenderTableCell.h"
+#include "SVGSVGElement.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLPresentationElement::MathMLPresentationElement(const QualifiedName& tagName, Document& document)
+ : MathMLElement(tagName, document)
+{
+}
+
+Ref<MathMLPresentationElement> MathMLPresentationElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLPresentationElement(tagName, document));
+}
+
+RenderPtr<RenderElement> MathMLPresentationElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition& insertionPosition)
+{
+ if (hasTagName(mtableTag))
+ return createRenderer<RenderMathMLTable>(*this, WTFMove(style));
+
+ return MathMLElement::createElementRenderer(WTFMove(style), insertionPosition);
+}
+
+bool MathMLPresentationElement::isPhrasingContent(const Node& node)
+{
+ // Phrasing content is described in the HTML 5 specification:
+ // http://www.w3.org/TR/html5/dom.html#phrasing-content.
+
+ if (!node.isElementNode())
+ return node.isTextNode();
+
+ if (is<MathMLElement>(node)) {
+ auto& mathmlElement = downcast<MathMLElement>(node);
+ return is<MathMLMathElement>(mathmlElement);
+ }
+
+ if (is<SVGElement>(node)) {
+ auto& svgElement = downcast<SVGElement>(node);
+ return is<SVGSVGElement>(svgElement);
+ }
+
+ if (is<HTMLElement>(node)) {
+ // FIXME: add the <data> and <time> tags when they are implemented.
+ auto& htmlElement = downcast<HTMLElement>(node);
+ return htmlElement.hasTagName(HTMLNames::aTag)
+ || htmlElement.hasTagName(HTMLNames::abbrTag)
+ || (htmlElement.hasTagName(HTMLNames::areaTag) && ancestorsOfType<HTMLMapElement>(htmlElement).first())
+ || htmlElement.hasTagName(HTMLNames::audioTag)
+ || htmlElement.hasTagName(HTMLNames::bTag)
+ || htmlElement.hasTagName(HTMLNames::bdiTag)
+ || htmlElement.hasTagName(HTMLNames::bdoTag)
+ || htmlElement.hasTagName(HTMLNames::brTag)
+ || htmlElement.hasTagName(HTMLNames::buttonTag)
+ || htmlElement.hasTagName(HTMLNames::canvasTag)
+ || htmlElement.hasTagName(HTMLNames::citeTag)
+ || htmlElement.hasTagName(HTMLNames::codeTag)
+ || htmlElement.hasTagName(HTMLNames::datalistTag)
+ || htmlElement.hasTagName(HTMLNames::delTag)
+ || htmlElement.hasTagName(HTMLNames::dfnTag)
+ || htmlElement.hasTagName(HTMLNames::emTag)
+ || htmlElement.hasTagName(HTMLNames::embedTag)
+ || htmlElement.hasTagName(HTMLNames::iTag)
+ || htmlElement.hasTagName(HTMLNames::iframeTag)
+ || htmlElement.hasTagName(HTMLNames::imgTag)
+ || htmlElement.hasTagName(HTMLNames::inputTag)
+ || htmlElement.hasTagName(HTMLNames::insTag)
+ || htmlElement.hasTagName(HTMLNames::kbdTag)
+ || htmlElement.hasTagName(HTMLNames::keygenTag)
+ || htmlElement.hasTagName(HTMLNames::labelTag)
+ || htmlElement.hasTagName(HTMLNames::mapTag)
+ || htmlElement.hasTagName(HTMLNames::markTag)
+ || htmlElement.hasTagName(HTMLNames::meterTag)
+ || htmlElement.hasTagName(HTMLNames::noscriptTag)
+ || htmlElement.hasTagName(HTMLNames::objectTag)
+ || htmlElement.hasTagName(HTMLNames::outputTag)
+ || htmlElement.hasTagName(HTMLNames::progressTag)
+ || htmlElement.hasTagName(HTMLNames::qTag)
+ || htmlElement.hasTagName(HTMLNames::rubyTag)
+ || htmlElement.hasTagName(HTMLNames::sTag)
+ || htmlElement.hasTagName(HTMLNames::sampTag)
+ || htmlElement.hasTagName(HTMLNames::scriptTag)
+ || htmlElement.hasTagName(HTMLNames::selectTag)
+ || htmlElement.hasTagName(HTMLNames::smallTag)
+ || htmlElement.hasTagName(HTMLNames::spanTag)
+ || htmlElement.hasTagName(HTMLNames::strongTag)
+ || htmlElement.hasTagName(HTMLNames::subTag)
+ || htmlElement.hasTagName(HTMLNames::supTag)
+ || htmlElement.hasTagName(HTMLNames::templateTag)
+ || htmlElement.hasTagName(HTMLNames::textareaTag)
+ || htmlElement.hasTagName(HTMLNames::uTag)
+ || htmlElement.hasTagName(HTMLNames::varTag)
+ || htmlElement.hasTagName(HTMLNames::videoTag)
+ || htmlElement.hasTagName(HTMLNames::wbrTag);
+ }
+
+ return false;
+}
+
+bool MathMLPresentationElement::isFlowContent(const Node& node)
+{
+ // Flow content is described in the HTML 5 specification:
+ // http://www.w3.org/TR/html5/dom.html#flow-content
+
+ if (isPhrasingContent(node))
+ return true;
+
+ if (!is<HTMLElement>(node))
+ return false;
+
+ auto& htmlElement = downcast<HTMLElement>(node);
+ // FIXME add the <dialog> tag when it is implemented.
+ return htmlElement.hasTagName(HTMLNames::addressTag)
+ || htmlElement.hasTagName(HTMLNames::articleTag)
+ || htmlElement.hasTagName(HTMLNames::asideTag)
+ || htmlElement.hasTagName(HTMLNames::blockquoteTag)
+ || htmlElement.hasTagName(HTMLNames::detailsTag)
+ || htmlElement.hasTagName(HTMLNames::divTag)
+ || htmlElement.hasTagName(HTMLNames::dlTag)
+ || htmlElement.hasTagName(HTMLNames::fieldsetTag)
+ || htmlElement.hasTagName(HTMLNames::figureTag)
+ || htmlElement.hasTagName(HTMLNames::footerTag)
+ || htmlElement.hasTagName(HTMLNames::formTag)
+ || htmlElement.hasTagName(HTMLNames::h1Tag)
+ || htmlElement.hasTagName(HTMLNames::h2Tag)
+ || htmlElement.hasTagName(HTMLNames::h3Tag)
+ || htmlElement.hasTagName(HTMLNames::h4Tag)
+ || htmlElement.hasTagName(HTMLNames::h5Tag)
+ || htmlElement.hasTagName(HTMLNames::h6Tag)
+ || htmlElement.hasTagName(HTMLNames::headerTag)
+ || htmlElement.hasTagName(HTMLNames::hrTag)
+ || htmlElement.hasTagName(HTMLNames::mainTag)
+ || htmlElement.hasTagName(HTMLNames::navTag)
+ || htmlElement.hasTagName(HTMLNames::olTag)
+ || htmlElement.hasTagName(HTMLNames::pTag)
+ || htmlElement.hasTagName(HTMLNames::preTag)
+ || htmlElement.hasTagName(HTMLNames::sectionTag)
+ || (htmlElement.hasTagName(HTMLNames::styleTag) && htmlElement.hasAttribute("scoped"))
+ || htmlElement.hasTagName(HTMLNames::tableTag)
+ || htmlElement.hasTagName(HTMLNames::ulTag);
+}
+
+const MathMLElement::BooleanValue& MathMLPresentationElement::cachedBooleanAttribute(const QualifiedName& name, std::optional<BooleanValue>& attribute)
+{
+ if (attribute)
+ return attribute.value();
+
+ // In MathML, attribute values are case-sensitive.
+ const AtomicString& value = attributeWithoutSynchronization(name);
+ if (value == "true")
+ attribute = BooleanValue::True;
+ else if (value == "false")
+ attribute = BooleanValue::False;
+ else
+ attribute = BooleanValue::Default;
+
+ return attribute.value();
+}
+
+MathMLElement::Length MathMLPresentationElement::parseNumberAndUnit(const StringView& string)
+{
+ LengthType lengthType = LengthType::UnitLess;
+ unsigned stringLength = string.length();
+ UChar lastChar = string[stringLength - 1];
+ if (lastChar == '%') {
+ lengthType = LengthType::Percentage;
+ stringLength--;
+ } else if (stringLength >= 2) {
+ UChar penultimateChar = string[stringLength - 2];
+ if (penultimateChar == 'c' && lastChar == 'm')
+ lengthType = LengthType::Cm;
+ if (penultimateChar == 'e' && lastChar == 'm')
+ lengthType = LengthType::Em;
+ else if (penultimateChar == 'e' && lastChar == 'x')
+ lengthType = LengthType::Ex;
+ else if (penultimateChar == 'i' && lastChar == 'n')
+ lengthType = LengthType::In;
+ else if (penultimateChar == 'm' && lastChar == 'm')
+ lengthType = LengthType::Mm;
+ else if (penultimateChar == 'p' && lastChar == 'c')
+ lengthType = LengthType::Pc;
+ else if (penultimateChar == 'p' && lastChar == 't')
+ lengthType = LengthType::Pt;
+ else if (penultimateChar == 'p' && lastChar == 'x')
+ lengthType = LengthType::Px;
+
+ if (lengthType != LengthType::UnitLess)
+ stringLength -= 2;
+ }
+
+ bool ok;
+ float lengthValue = string.substring(0, stringLength).toFloat(ok);
+ if (!ok)
+ return Length();
+
+ Length length;
+ length.type = lengthType;
+ length.value = lengthValue;
+ return length;
+}
+
+MathMLElement::Length MathMLPresentationElement::parseNamedSpace(const StringView& string)
+{
+ // Named space values are case-sensitive.
+ int namedSpaceValue;
+ if (string == "veryverythinmathspace")
+ namedSpaceValue = 1;
+ else if (string == "verythinmathspace")
+ namedSpaceValue = 2;
+ else if (string == "thinmathspace")
+ namedSpaceValue = 3;
+ else if (string == "mediummathspace")
+ namedSpaceValue = 4;
+ else if (string == "thickmathspace")
+ namedSpaceValue = 5;
+ else if (string == "verythickmathspace")
+ namedSpaceValue = 6;
+ else if (string == "veryverythickmathspace")
+ namedSpaceValue = 7;
+ else if (string == "negativeveryverythinmathspace")
+ namedSpaceValue = -1;
+ else if (string == "negativeverythinmathspace")
+ namedSpaceValue = -2;
+ else if (string == "negativethinmathspace")
+ namedSpaceValue = -3;
+ else if (string == "negativemediummathspace")
+ namedSpaceValue = -4;
+ else if (string == "negativethickmathspace")
+ namedSpaceValue = -5;
+ else if (string == "negativeverythickmathspace")
+ namedSpaceValue = -6;
+ else if (string == "negativeveryverythickmathspace")
+ namedSpaceValue = -7;
+ else
+ return Length();
+
+ Length length;
+ length.type = LengthType::MathUnit;
+ length.value = namedSpaceValue;
+ return length;
+}
+
+MathMLElement::Length MathMLPresentationElement::parseMathMLLength(const String& string)
+{
+ // The regular expression from the MathML Relax NG schema is as follows:
+ //
+ // pattern = '\s*((-?[0-9]*([0-9]\.?|\.[0-9])[0-9]*(e[mx]|in|cm|mm|p[xtc]|%)?)|(negative)?((very){0,2}thi(n|ck)|medium)mathspace)\s*'
+ //
+ // We do not perform a strict verification of the syntax of whitespaces and number.
+ // Instead, we just use isHTMLSpace and toFloat to parse these parts.
+
+ // We first skip whitespace from both ends of the string.
+ StringView stringView = stripLeadingAndTrailingWhitespace(string);
+
+ if (stringView.isEmpty())
+ return Length();
+
+ // We consider the most typical case: a number followed by an optional unit.
+ UChar firstChar = stringView[0];
+ if (isASCIIDigit(firstChar) || firstChar == '-' || firstChar == '.')
+ return parseNumberAndUnit(stringView);
+
+ // Otherwise, we try and parse a named space.
+ return parseNamedSpace(stringView);
+}
+
+const MathMLElement::Length& MathMLPresentationElement::cachedMathMLLength(const QualifiedName& name, std::optional<Length>& length)
+{
+ if (length)
+ return length.value();
+ length = parseMathMLLength(attributeWithoutSynchronization(name));
+ return length.value();
+}
+
+bool MathMLPresentationElement::acceptsDisplayStyleAttribute()
+{
+ return hasTagName(mtableTag);
+}
+
+std::optional<bool> MathMLPresentationElement::specifiedDisplayStyle()
+{
+ if (!acceptsDisplayStyleAttribute())
+ return std::nullopt;
+ const MathMLElement::BooleanValue& specifiedDisplayStyle = cachedBooleanAttribute(displaystyleAttr, m_displayStyle);
+ return toOptionalBool(specifiedDisplayStyle);
+}
+
+MathMLElement::MathVariant MathMLPresentationElement::parseMathVariantAttribute(const AtomicString& attributeValue)
+{
+ // The mathvariant attribute values is case-sensitive.
+ if (attributeValue == "normal")
+ return MathVariant::Normal;
+ if (attributeValue == "bold")
+ return MathVariant::Bold;
+ if (attributeValue == "italic")
+ return MathVariant::Italic;
+ if (attributeValue == "bold-italic")
+ return MathVariant::BoldItalic;
+ if (attributeValue == "double-struck")
+ return MathVariant::DoubleStruck;
+ if (attributeValue == "bold-fraktur")
+ return MathVariant::BoldFraktur;
+ if (attributeValue == "script")
+ return MathVariant::Script;
+ if (attributeValue == "bold-script")
+ return MathVariant::BoldScript;
+ if (attributeValue == "fraktur")
+ return MathVariant::Fraktur;
+ if (attributeValue == "sans-serif")
+ return MathVariant::SansSerif;
+ if (attributeValue == "bold-sans-serif")
+ return MathVariant::BoldSansSerif;
+ if (attributeValue == "sans-serif-italic")
+ return MathVariant::SansSerifItalic;
+ if (attributeValue == "sans-serif-bold-italic")
+ return MathVariant::SansSerifBoldItalic;
+ if (attributeValue == "monospace")
+ return MathVariant::Monospace;
+ if (attributeValue == "initial")
+ return MathVariant::Initial;
+ if (attributeValue == "tailed")
+ return MathVariant::Tailed;
+ if (attributeValue == "looped")
+ return MathVariant::Looped;
+ if (attributeValue == "stretched")
+ return MathVariant::Stretched;
+ return MathVariant::None;
+}
+
+std::optional<MathMLElement::MathVariant> MathMLPresentationElement::specifiedMathVariant()
+{
+ if (!acceptsMathVariantAttribute())
+ return std::nullopt;
+ if (!m_mathVariant)
+ m_mathVariant = parseMathVariantAttribute(attributeWithoutSynchronization(mathvariantAttr));
+ return m_mathVariant.value() == MathVariant::None ? std::nullopt : m_mathVariant;
+}
+
+void MathMLPresentationElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ bool displayStyleAttribute = name == displaystyleAttr && acceptsDisplayStyleAttribute();
+ bool mathVariantAttribute = name == mathvariantAttr && acceptsMathVariantAttribute();
+ if (displayStyleAttribute)
+ m_displayStyle = std::nullopt;
+ if (mathVariantAttribute)
+ m_mathVariant = std::nullopt;
+ if ((displayStyleAttribute || mathVariantAttribute) && renderer())
+ MathMLStyle::resolveMathMLStyleTree(renderer());
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLPresentationElement.h b/Source/WebCore/mathml/MathMLPresentationElement.h
new file mode 100644
index 000000000..2370557b4
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLPresentationElement.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLElement.h"
+
+namespace WebCore {
+
+class MathMLPresentationElement : public MathMLElement {
+public:
+ static Ref<MathMLPresentationElement> create(const QualifiedName& tagName, Document&);
+
+protected:
+ MathMLPresentationElement(const QualifiedName& tagName, Document&);
+ void parseAttribute(const QualifiedName&, const AtomicString&) override;
+
+ static bool isPhrasingContent(const Node&);
+ static bool isFlowContent(const Node&);
+
+ static std::optional<bool> toOptionalBool(const BooleanValue& value) { return value == BooleanValue::Default ? std::nullopt : std::optional<bool>(value == BooleanValue::True); }
+ const BooleanValue& cachedBooleanAttribute(const QualifiedName&, std::optional<BooleanValue>&);
+
+ static Length parseMathMLLength(const String&);
+ const Length& cachedMathMLLength(const QualifiedName&, std::optional<Length>&);
+
+ virtual bool acceptsDisplayStyleAttribute();
+ std::optional<bool> specifiedDisplayStyle() override;
+
+ virtual bool acceptsMathVariantAttribute() { return false; }
+ std::optional<MathVariant> specifiedMathVariant() final;
+
+ std::optional<BooleanValue> m_displayStyle;
+ std::optional<MathVariant> m_mathVariant;
+
+private:
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
+ bool isPresentationMathML() const final { return true; }
+
+ static Length parseNumberAndUnit(const StringView&);
+ static Length parseNamedSpace(const StringView&);
+ static MathVariant parseMathVariantAttribute(const AtomicString& attributeValue);
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLRowElement.cpp b/Source/WebCore/mathml/MathMLRowElement.cpp
new file mode 100644
index 000000000..a31f71523
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLRowElement.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MathMLRowElement.h"
+
+#if ENABLE(MATHML)
+
+#include "MathMLNames.h"
+#include "MathMLOperatorElement.h"
+#include "RenderMathMLFenced.h"
+#include "RenderMathMLMenclose.h"
+#include "RenderMathMLRoot.h"
+#include "RenderMathMLRow.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLRowElement::MathMLRowElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+}
+
+Ref<MathMLRowElement> MathMLRowElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLRowElement(tagName, document));
+}
+
+void MathMLRowElement::childrenChanged(const ChildChange& change)
+{
+ for (auto child = firstChild(); child; child = child->nextSibling()) {
+ if (child->hasTagName(moTag))
+ static_cast<MathMLOperatorElement*>(child)->setOperatorFormDirty();
+ }
+
+ MathMLPresentationElement::childrenChanged(change);
+}
+
+RenderPtr<RenderElement> MathMLRowElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ if (hasTagName(msqrtTag) || hasTagName(mrootTag))
+ return createRenderer<RenderMathMLRoot>(*this, WTFMove(style));
+
+ if (hasTagName(mfencedTag))
+ return createRenderer<RenderMathMLFenced>(*this, WTFMove(style));
+
+ ASSERT(hasTagName(merrorTag) || hasTagName(mphantomTag) || hasTagName(mrowTag) || hasTagName(mstyleTag));
+ return createRenderer<RenderMathMLRow>(*this, WTFMove(style));
+}
+
+bool MathMLRowElement::acceptsDisplayStyleAttribute()
+{
+ return hasTagName(mstyleTag);
+}
+
+bool MathMLRowElement::acceptsMathVariantAttribute()
+{
+ return hasTagName(mstyleTag);
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLInlineContainerElement.h b/Source/WebCore/mathml/MathMLRowElement.h
index eb7b3d615..834b51187 100644
--- a/Source/WebCore/mathml/MathMLInlineContainerElement.h
+++ b/Source/WebCore/mathml/MathMLRowElement.h
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,28 +23,29 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLInlineContainerElement_h
-#define MathMLInlineContainerElement_h
+#pragma once
#if ENABLE(MATHML)
-#include "MathMLElement.h"
+
+#include "MathMLPresentationElement.h"
namespace WebCore {
-
-class MathMLInlineContainerElement : public MathMLElement {
-public:
- static PassRefPtr<MathMLInlineContainerElement> create(const QualifiedName& tagName, Document&);
- virtual bool isPresentationMathML() const override { return true; }
+class MathMLRowElement : public MathMLPresentationElement {
+public:
+ static Ref<MathMLRowElement> create(const QualifiedName& tagName, Document&);
protected:
- MathMLInlineContainerElement(const QualifiedName& tagName, Document&);
+ MathMLRowElement(const QualifiedName& tagName, Document&);
+ void childrenChanged(const ChildChange&) override;
+
+ bool acceptsDisplayStyleAttribute() override;
+ bool acceptsMathVariantAttribute() override;
private:
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
};
-
+
}
#endif // ENABLE(MATHML)
-#endif // MathMLInlineContainerElement_h
diff --git a/Source/WebCore/mathml/MathMLScriptsElement.cpp b/Source/WebCore/mathml/MathMLScriptsElement.cpp
new file mode 100644
index 000000000..393edc112
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLScriptsElement.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLScriptsElement.h"
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLScripts.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLScriptsElement::MathMLScriptsElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+}
+
+Ref<MathMLScriptsElement> MathMLScriptsElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLScriptsElement(tagName, document));
+}
+
+const MathMLElement::Length& MathMLScriptsElement::subscriptShift()
+{
+ return cachedMathMLLength(subscriptshiftAttr, m_subscriptShift);
+}
+
+const MathMLElement::Length& MathMLScriptsElement::superscriptShift()
+{
+ return cachedMathMLLength(superscriptshiftAttr, m_superscriptShift);
+}
+
+void MathMLScriptsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == subscriptshiftAttr)
+ m_subscriptShift = std::nullopt;
+ else if (name == superscriptshiftAttr)
+ m_superscriptShift = std::nullopt;
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+RenderPtr<RenderElement> MathMLScriptsElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(msubTag) || hasTagName(msupTag) || hasTagName(msubsupTag) || hasTagName(mmultiscriptsTag));
+ return createRenderer<RenderMathMLScripts>(*this, WTFMove(style));
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLScriptsElement.h b/Source/WebCore/mathml/MathMLScriptsElement.h
new file mode 100644
index 000000000..b4a6089f0
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLScriptsElement.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLPresentationElement.h"
+
+namespace WebCore {
+
+class MathMLScriptsElement : public MathMLPresentationElement {
+public:
+ static Ref<MathMLScriptsElement> create(const QualifiedName& tagName, Document&);
+ const Length& subscriptShift();
+ const Length& superscriptShift();
+
+protected:
+ MathMLScriptsElement(const QualifiedName& tagName, Document&);
+
+private:
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
+ void parseAttribute(const QualifiedName&, const AtomicString&) override;
+
+ std::optional<Length> m_subscriptShift;
+ std::optional<Length> m_superscriptShift;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLSelectElement.cpp b/Source/WebCore/mathml/MathMLSelectElement.cpp
index a127bfd85..bab957a09 100644
--- a/Source/WebCore/mathml/MathMLSelectElement.cpp
+++ b/Source/WebCore/mathml/MathMLSelectElement.cpp
@@ -29,27 +29,55 @@
#if ENABLE(MATHML)
#include "Event.h"
+#include "EventNames.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
#include "MathMLNames.h"
#include "RenderMathMLRow.h"
+#include "RenderTreeUpdater.h"
+#include "SVGElement.h"
namespace WebCore {
using namespace MathMLNames;
MathMLSelectElement::MathMLSelectElement(const QualifiedName& tagName, Document& document)
- : MathMLInlineContainerElement(tagName, document)
+ : MathMLRowElement(tagName, document)
, m_selectedChild(nullptr)
{
}
-PassRefPtr<MathMLSelectElement> MathMLSelectElement::create(const QualifiedName& tagName, Document& document)
+Ref<MathMLSelectElement> MathMLSelectElement::create(const QualifiedName& tagName, Document& document)
{
- return adoptRef(new MathMLSelectElement(tagName, document));
+ return adoptRef(*new MathMLSelectElement(tagName, document));
}
-RenderPtr<RenderElement> MathMLSelectElement::createElementRenderer(PassRef<RenderStyle> style)
+RenderPtr<RenderElement> MathMLSelectElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
{
- return createRenderer<RenderMathMLRow>(*this, std::move(style));
+ return createRenderer<RenderMathMLRow>(*this, WTFMove(style));
+}
+
+// We recognize the following values for the encoding attribute of the <semantics> element:
+//
+// - "MathML-Presentation", which is mentioned in the MathML 3 recommendation.
+// - "SVG1.1" which is mentioned in the W3C note.
+// http://www.w3.org/Math/Documents/Notes/graphics.xml
+// - Other MIME Content-Types for MathML, SVG and HTML.
+//
+// We exclude "application/mathml+xml" which is ambiguous about whether it is Presentation or Content MathML. Authors must use a more explicit encoding value.
+bool MathMLSelectElement::isMathMLEncoding(const AtomicString& value)
+{
+ return value == "application/mathml-presentation+xml" || value == "MathML-Presentation";
+}
+
+bool MathMLSelectElement::isSVGEncoding(const AtomicString& value)
+{
+ return value == "image/svg+xml" || value == "SVG1.1";
+}
+
+bool MathMLSelectElement::isHTMLEncoding(const AtomicString& value)
+{
+ return value == "application/xhtml+xml" || value == "text/html";
}
bool MathMLSelectElement::childShouldCreateRenderer(const Node& child) const
@@ -60,36 +88,36 @@ bool MathMLSelectElement::childShouldCreateRenderer(const Node& child) const
void MathMLSelectElement::finishParsingChildren()
{
updateSelectedChild();
- MathMLInlineContainerElement::finishParsingChildren();
+ MathMLRowElement::finishParsingChildren();
}
void MathMLSelectElement::childrenChanged(const ChildChange& change)
{
updateSelectedChild();
- MathMLInlineContainerElement::childrenChanged(change);
+ MathMLRowElement::childrenChanged(change);
}
void MathMLSelectElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
{
- if (hasLocalName(mactionTag) && (name == MathMLNames::actiontypeAttr || name == MathMLNames::selectionAttr))
+ if (hasTagName(mactionTag) && (name == MathMLNames::actiontypeAttr || name == MathMLNames::selectionAttr))
updateSelectedChild();
- MathMLInlineContainerElement::attributeChanged(name, oldValue, newValue, reason);
+ MathMLRowElement::attributeChanged(name, oldValue, newValue, reason);
}
int MathMLSelectElement::getSelectedActionChildAndIndex(Element*& selectedChild)
{
- ASSERT(hasLocalName(mactionTag));
+ ASSERT(hasTagName(mactionTag));
// We "round up or down to the closest allowable value" of the selection attribute, as suggested by the MathML specification.
selectedChild = firstElementChild();
if (!selectedChild)
return 1;
- int selection = fastGetAttribute(MathMLNames::selectionAttr).toInt();
+ int selection = attributeWithoutSynchronization(MathMLNames::selectionAttr).toInt();
int i;
for (i = 1; i < selection; i++) {
- Element* nextChild = selectedChild->nextElementSibling();
+ auto* nextChild = selectedChild->nextElementSibling();
if (!nextChild)
break;
selectedChild = nextChild;
@@ -100,14 +128,14 @@ int MathMLSelectElement::getSelectedActionChildAndIndex(Element*& selectedChild)
Element* MathMLSelectElement::getSelectedActionChild()
{
- ASSERT(hasLocalName(mactionTag));
+ ASSERT(hasTagName(mactionTag));
- Element* child = firstElementChild();
+ auto* child = firstElementChild();
if (!child)
return child;
// The value of the actiontype attribute is case-sensitive.
- const AtomicString& actiontype = fastGetAttribute(MathMLNames::actiontypeAttr);
+ auto& actiontype = attributeWithoutSynchronization(MathMLNames::actiontypeAttr);
if (actiontype == "statusline")
// FIXME: implement user interaction for the "statusline" action type (http://wkbug/124922).
{ }
@@ -124,47 +152,40 @@ Element* MathMLSelectElement::getSelectedActionChild()
Element* MathMLSelectElement::getSelectedSemanticsChild()
{
- ASSERT(hasLocalName(semanticsTag));
+ ASSERT(hasTagName(semanticsTag));
- Element* child = firstElementChild();
+ auto* child = firstElementChild();
if (!child)
- return child;
+ return nullptr;
- if (!child->isMathMLElement() || !toMathMLElement(child)->isPresentationMathML()) {
+ if (!is<MathMLElement>(*child) || !downcast<MathMLElement>(*child).isPresentationMathML()) {
// The first child is not a presentation MathML element. Hence we move to the second child and start searching an annotation child that could be displayed.
child = child->nextElementSibling();
- } else if (!toMathMLElement(child)->isSemanticAnnotation()) {
+ } else if (!downcast<MathMLElement>(*child).isSemanticAnnotation()) {
// The first child is a presentation MathML but not an annotation, so we can just display it.
return child;
}
// Otherwise, the first child is an <annotation> or <annotation-xml> element. This is invalid, but some people use this syntax so we take care of this case too and start the search from this first child.
for ( ; child; child = child->nextElementSibling()) {
- if (!child->isMathMLElement())
+ if (!is<MathMLElement>(*child))
continue;
- if (child->hasLocalName(MathMLNames::annotationTag)) {
+ if (child->hasTagName(MathMLNames::annotationTag)) {
// If the <annotation> element has an src attribute then it is a reference to arbitrary binary data and it is not clear whether we can display it. Hence we just ignore the annotation.
- if (child->hasAttribute(MathMLNames::srcAttr))
+ if (child->hasAttributeWithoutSynchronization(MathMLNames::srcAttr))
continue;
// Otherwise, we assume it is a text annotation that can always be displayed and we stop here.
return child;
}
- if (child->hasLocalName(MathMLNames::annotation_xmlTag)) {
+ if (child->hasTagName(MathMLNames::annotation_xmlTag)) {
// If the <annotation-xml> element has an src attribute then it is a reference to arbitrary binary data and it is not clear whether we can display it. Hence we just ignore the annotation.
- if (child->hasAttribute(MathMLNames::srcAttr))
+ if (child->hasAttributeWithoutSynchronization(MathMLNames::srcAttr))
continue;
- // If the <annotation-xml> element has an encoding attribute describing presentation MathML, SVG or HTML we assume the content can be displayed and we stop here. We recognize the following encoding values:
- //
- // - "MathML-Presentation", which is mentioned in the MathML 3 recommendation.
- // - "SVG1.1" which is mentioned in the W3C note.
- // http://www.w3.org/Math/Documents/Notes/graphics.xml
- // - Other MIME Content-Types for SVG and HTML.
- //
- // We exclude "application/mathml+xml" which is ambiguous about whether it is Presentation or Content MathML. Authors must use a more explicit encoding value.
- const AtomicString& value = child->fastGetAttribute(MathMLNames::encodingAttr);
- if (value == "application/mathml-presentation+xml" || value == "MathML-Presentation" || value == "image/svg+xml" || value == "SVG1.1" || value == "application/xhtml+xml" || value == "text/html")
+ // If the <annotation-xml> element has an encoding attribute describing presentation MathML, SVG or HTML we assume the content can be displayed and we stop here.
+ auto& value = child->attributeWithoutSynchronization(MathMLNames::encodingAttr);
+ if (isMathMLEncoding(value) || isSVGEncoding(value) || isHTMLEncoding(value))
return child;
}
}
@@ -175,34 +196,34 @@ Element* MathMLSelectElement::getSelectedSemanticsChild()
void MathMLSelectElement::updateSelectedChild()
{
- Element* newSelectedChild = hasLocalName(mactionTag) ? getSelectedActionChild() : getSelectedSemanticsChild();
+ auto* newSelectedChild = hasTagName(mactionTag) ? getSelectedActionChild() : getSelectedSemanticsChild();
if (m_selectedChild == newSelectedChild)
return;
if (m_selectedChild && m_selectedChild->renderer())
- Style::detachRenderTree(*m_selectedChild);
+ RenderTreeUpdater::tearDownRenderers(*m_selectedChild);
m_selectedChild = newSelectedChild;
- setNeedsStyleRecalc();
+ invalidateStyleForSubtree();
}
-void MathMLSelectElement::defaultEventHandler(Event* event)
+void MathMLSelectElement::defaultEventHandler(Event& event)
{
- if (event->type() == eventNames().clickEvent) {
- if (fastGetAttribute(MathMLNames::actiontypeAttr) == "toggle") {
+ if (event.type() == eventNames().clickEvent) {
+ if (attributeWithoutSynchronization(MathMLNames::actiontypeAttr) == "toggle") {
toggle();
- event->setDefaultHandled();
+ event.setDefaultHandled();
return;
}
}
- MathMLInlineContainerElement::defaultEventHandler(event);
+ MathMLRowElement::defaultEventHandler(event);
}
bool MathMLSelectElement::willRespondToMouseClickEvents()
{
- return fastGetAttribute(MathMLNames::actiontypeAttr) == "toggle";
+ return attributeWithoutSynchronization(MathMLNames::actiontypeAttr) == "toggle" || MathMLRowElement::willRespondToMouseClickEvents();
}
void MathMLSelectElement::toggle()
@@ -216,7 +237,7 @@ void MathMLSelectElement::toggle()
// We update the attribute value of the selection attribute.
// This will also call MathMLSelectElement::attributeChanged to update the selected child.
- setAttribute(MathMLNames::selectionAttr, AtomicString::number(newSelectedChildIndex));
+ setAttributeWithoutSynchronization(MathMLNames::selectionAttr, AtomicString::number(newSelectedChildIndex));
}
}
diff --git a/Source/WebCore/mathml/MathMLSelectElement.h b/Source/WebCore/mathml/MathMLSelectElement.h
index 6230da437..1043dd5ef 100644
--- a/Source/WebCore/mathml/MathMLSelectElement.h
+++ b/Source/WebCore/mathml/MathMLSelectElement.h
@@ -23,40 +23,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLSelectElement_h
-#define MathMLSelectElement_h
+#pragma once
#if ENABLE(MATHML)
-#include "MathMLInlineContainerElement.h"
+
+#include "MathMLRowElement.h"
namespace WebCore {
-class MathMLSelectElement final : public MathMLInlineContainerElement {
+class MathMLSelectElement final : public MathMLRowElement {
public:
- static PassRefPtr<MathMLSelectElement> create(const QualifiedName& tagName, Document&);
+ static Ref<MathMLSelectElement> create(const QualifiedName& tagName, Document&);
+ static bool isMathMLEncoding(const AtomicString& value);
+ static bool isSVGEncoding(const AtomicString& value);
+ static bool isHTMLEncoding(const AtomicString& value);
private:
MathMLSelectElement(const QualifiedName& tagName, Document&);
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
- virtual bool childShouldCreateRenderer(const Node&) const override;
+ bool childShouldCreateRenderer(const Node&) const final;
- virtual void finishParsingChildren() override;
- virtual void childrenChanged(const ChildChange&) override;
- virtual void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason = ModifiedDirectly) override;
- virtual void defaultEventHandler(Event*) override;
- virtual bool willRespondToMouseClickEvents() override;
+ void finishParsingChildren() final;
+ void childrenChanged(const ChildChange&) final;
+ void attributeChanged(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason = ModifiedDirectly) final;
+ void defaultEventHandler(Event&) final;
+ bool willRespondToMouseClickEvents() final;
void toggle();
int getSelectedActionChildAndIndex(Element*& selectedChild);
Element* getSelectedActionChild();
Element* getSelectedSemanticsChild();
- void updateSelectedChild() override;
+ void updateSelectedChild() final;
RefPtr<Element> m_selectedChild;
};
}
#endif // ENABLE(MATHML)
-#endif // MathMLSelectElement_h
diff --git a/Source/WebCore/mathml/MathMLTextElement.cpp b/Source/WebCore/mathml/MathMLSpaceElement.cpp
index 4f17b6c10..96e9b9074 100644
--- a/Source/WebCore/mathml/MathMLTextElement.cpp
+++ b/Source/WebCore/mathml/MathMLSpaceElement.cpp
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -22,60 +21,61 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
*/
#include "config.h"
+#include "MathMLSpaceElement.h"
#if ENABLE(MATHML)
-#include "MathMLTextElement.h"
-
-#include "MathMLNames.h"
-#include "RenderMathMLOperator.h"
#include "RenderMathMLSpace.h"
namespace WebCore {
-
+
using namespace MathMLNames;
-inline MathMLTextElement::MathMLTextElement(const QualifiedName& tagName, Document& document)
- : MathMLElement(tagName, document)
+MathMLSpaceElement::MathMLSpaceElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+}
+
+Ref<MathMLSpaceElement> MathMLSpaceElement::create(const QualifiedName& tagName, Document& document)
{
- setHasCustomStyleResolveCallbacks();
+ return adoptRef(*new MathMLSpaceElement(tagName, document));
}
-PassRefPtr<MathMLTextElement> MathMLTextElement::create(const QualifiedName& tagName, Document& document)
+const MathMLElement::Length& MathMLSpaceElement::width()
{
- return adoptRef(new MathMLTextElement(tagName, document));
+ return cachedMathMLLength(MathMLNames::widthAttr, m_width);
}
-void MathMLTextElement::didAttachRenderers()
+const MathMLElement::Length& MathMLSpaceElement::height()
{
- MathMLElement::didAttachRenderers();
- if (renderer())
- renderer()->updateFromElement();
+ return cachedMathMLLength(MathMLNames::heightAttr, m_height);
}
-void MathMLTextElement::childrenChanged(const ChildChange& change)
+const MathMLElement::Length& MathMLSpaceElement::depth()
{
- MathMLElement::childrenChanged(change);
- if (renderer())
- renderer()->updateFromElement();
+ return cachedMathMLLength(MathMLNames::depthAttr, m_depth);
}
-RenderPtr<RenderElement> MathMLTextElement::createElementRenderer(PassRef<RenderStyle> style)
+void MathMLSpaceElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- if (hasLocalName(MathMLNames::moTag))
- return createRenderer<RenderMathMLOperator>(*this, std::move(style));
- if (hasLocalName(MathMLNames::mspaceTag))
- return createRenderer<RenderMathMLSpace>(*this, std::move(style));
+ if (name == widthAttr)
+ m_width = std::nullopt;
+ else if (name == heightAttr)
+ m_height = std::nullopt;
+ else if (name == depthAttr)
+ m_depth = std::nullopt;
- return MathMLElement::createElementRenderer(std::move(style));
+ MathMLPresentationElement::parseAttribute(name, value);
}
-bool MathMLTextElement::childShouldCreateRenderer(const Node& child) const
+RenderPtr<RenderElement> MathMLSpaceElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
{
- return child.isTextNode();
+ ASSERT(hasTagName(MathMLNames::mspaceTag));
+ return createRenderer<RenderMathMLSpace>(*this, WTFMove(style));
}
}
diff --git a/Source/WebCore/mathml/MathMLSpaceElement.h b/Source/WebCore/mathml/MathMLSpaceElement.h
new file mode 100644
index 000000000..3f16f7851
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLSpaceElement.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLPresentationElement.h"
+
+namespace WebCore {
+
+class MathMLSpaceElement final : public MathMLPresentationElement {
+public:
+ static Ref<MathMLSpaceElement> create(const QualifiedName& tagName, Document&);
+ const Length& width();
+ const Length& height();
+ const Length& depth();
+private:
+ MathMLSpaceElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+
+ bool acceptsDisplayStyleAttribute() final { return false; }
+
+ std::optional<Length> m_width;
+ std::optional<Length> m_height;
+ std::optional<Length> m_depth;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLTokenElement.cpp b/Source/WebCore/mathml/MathMLTokenElement.cpp
new file mode 100644
index 000000000..ce1cca6a8
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLTokenElement.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MathMLTokenElement.h"
+
+#if ENABLE(MATHML)
+
+#include "MathMLNames.h"
+#include "RenderMathMLToken.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLTokenElement::MathMLTokenElement(const QualifiedName& tagName, Document& document)
+ : MathMLPresentationElement(tagName, document)
+{
+ setHasCustomStyleResolveCallbacks();
+}
+
+Ref<MathMLTokenElement> MathMLTokenElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLTokenElement(tagName, document));
+}
+
+void MathMLTokenElement::didAttachRenderers()
+{
+ MathMLPresentationElement::didAttachRenderers();
+ auto* mathmlRenderer = renderer();
+ if (is<RenderMathMLToken>(mathmlRenderer))
+ downcast<RenderMathMLToken>(*mathmlRenderer).updateTokenContent();
+}
+
+void MathMLTokenElement::childrenChanged(const ChildChange& change)
+{
+ MathMLPresentationElement::childrenChanged(change);
+ auto* mathmlRenderer = renderer();
+ if (is<RenderMathMLToken>(mathmlRenderer))
+ downcast<RenderMathMLToken>(*mathmlRenderer).updateTokenContent();
+}
+
+RenderPtr<RenderElement> MathMLTokenElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(MathMLNames::miTag) || hasTagName(MathMLNames::mnTag) || hasTagName(MathMLNames::msTag) || hasTagName(MathMLNames::mtextTag));
+
+ return createRenderer<RenderMathMLToken>(*this, WTFMove(style));
+}
+
+bool MathMLTokenElement::childShouldCreateRenderer(const Node& child) const
+{
+ // The HTML specification defines <mi>, <mo>, <mn>, <ms> and <mtext> as insertion points.
+ return isPhrasingContent(child) && StyledElement::childShouldCreateRenderer(child);
+}
+
+std::optional<UChar32> MathMLTokenElement::convertToSingleCodePoint(StringView string)
+{
+ auto codePoints = stripLeadingAndTrailingWhitespace(string).codePoints();
+ auto iterator = codePoints.begin();
+ if (iterator == codePoints.end())
+ return std::nullopt;
+ std::optional<UChar32> character = *iterator;
+ ++iterator;
+ return iterator == codePoints.end() ? character : std::nullopt;
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLTextElement.h b/Source/WebCore/mathml/MathMLTokenElement.h
index 4135155d6..bed40f3cf 100644
--- a/Source/WebCore/mathml/MathMLTextElement.h
+++ b/Source/WebCore/mathml/MathMLTokenElement.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2009 Alex Milowski (alex@milowski.com). All rights reserved.
* Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2016 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,31 +25,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MathMLTextElement_h
-#define MathMLTextElement_h
+#pragma once
#if ENABLE(MATHML)
-#include "MathMLElement.h"
+
+#include "MathMLPresentationElement.h"
namespace WebCore {
-
-class MathMLTextElement : public MathMLElement {
+
+class MathMLTokenElement : public MathMLPresentationElement {
public:
- static PassRefPtr<MathMLTextElement> create(const QualifiedName& tagName, Document&);
- virtual void didAttachRenderers() override;
+ static Ref<MathMLTokenElement> create(const QualifiedName& tagName, Document&);
- virtual bool isPresentationMathML() const override { return true; }
+ static std::optional<UChar32> convertToSingleCodePoint(StringView);
+
+protected:
+ MathMLTokenElement(const QualifiedName& tagName, Document&);
+ void childrenChanged(const ChildChange&) override;
private:
- MathMLTextElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
+ bool childShouldCreateRenderer(const Node&) const final;
- virtual RenderPtr<RenderElement> createElementRenderer(PassRef<RenderStyle>) override;
- virtual bool childShouldCreateRenderer(const Node&) const override;
+ void didAttachRenderers() final;
- virtual void childrenChanged(const ChildChange&) override;
+ bool isMathMLToken() const final { return true; }
+ bool acceptsMathVariantAttribute() final { return true; }
+ bool acceptsDisplayStyleAttribute() final { return false; }
};
-
+
}
#endif // ENABLE(MATHML)
-#endif // MathMLTextElement_h
diff --git a/Source/WebCore/mathml/MathMLUnderOverElement.cpp b/Source/WebCore/mathml/MathMLUnderOverElement.cpp
new file mode 100644
index 000000000..1413aad61
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLUnderOverElement.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "MathMLUnderOverElement.h"
+
+#if ENABLE(MATHML)
+
+#include "RenderMathMLUnderOver.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+inline MathMLUnderOverElement::MathMLUnderOverElement(const QualifiedName& tagName, Document& document)
+ : MathMLScriptsElement(tagName, document)
+{
+}
+
+Ref<MathMLUnderOverElement> MathMLUnderOverElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLUnderOverElement(tagName, document));
+}
+
+const MathMLElement::BooleanValue& MathMLUnderOverElement::accent()
+{
+ return cachedBooleanAttribute(accentAttr, m_accent);
+}
+
+const MathMLElement::BooleanValue& MathMLUnderOverElement::accentUnder()
+{
+ return cachedBooleanAttribute(accentunderAttr, m_accentUnder);
+}
+
+void MathMLUnderOverElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
+{
+ if (name == accentAttr)
+ m_accent = std::nullopt;
+ else if (name == accentunderAttr)
+ m_accentUnder = std::nullopt;
+
+ MathMLElement::parseAttribute(name, value);
+}
+
+RenderPtr<RenderElement> MathMLUnderOverElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
+{
+ ASSERT(hasTagName(munderTag) || hasTagName(moverTag) || hasTagName(munderoverTag));
+ return createRenderer<RenderMathMLUnderOver>(*this, WTFMove(style));
+}
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLUnderOverElement.h b/Source/WebCore/mathml/MathMLUnderOverElement.h
new file mode 100644
index 000000000..07f4d96f8
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLUnderOverElement.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MATHML)
+
+#include "MathMLScriptsElement.h"
+
+namespace WebCore {
+
+class MathMLUnderOverElement final : public MathMLScriptsElement {
+public:
+ static Ref<MathMLUnderOverElement> create(const QualifiedName& tagName, Document&);
+ const BooleanValue& accent();
+ const BooleanValue& accentUnder();
+
+private:
+ MathMLUnderOverElement(const QualifiedName& tagName, Document&);
+ RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
+ void parseAttribute(const QualifiedName&, const AtomicString&) final;
+
+ std::optional<BooleanValue> m_accent;
+ std::optional<BooleanValue> m_accentUnder;
+};
+
+}
+
+#endif // ENABLE(MATHML)
diff --git a/Source/WebCore/mathml/MathMLUnknownElement.h b/Source/WebCore/mathml/MathMLUnknownElement.h
new file mode 100644
index 000000000..13fa9bb8c
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLUnknownElement.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 Igalia S.L. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "MathMLElement.h"
+
+namespace WebCore {
+
+class MathMLUnknownElement final : public MathMLElement {
+public:
+ static Ref<MathMLUnknownElement> create(const QualifiedName& tagName, Document& document)
+ {
+ return adoptRef(*new MathMLUnknownElement(tagName, document));
+ }
+
+private:
+ MathMLUnknownElement(const QualifiedName& tagName, Document& document)
+ : MathMLElement(tagName, document)
+ {
+ }
+
+ bool rendererIsNeeded(const RenderStyle&) final { return false; }
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/mathml/mathattrs.in b/Source/WebCore/mathml/mathattrs.in
index abfdbb5bb..51186c70d 100644
--- a/Source/WebCore/mathml/mathattrs.in
+++ b/Source/WebCore/mathml/mathattrs.in
@@ -3,6 +3,8 @@ namespaceURI="http://www.w3.org/1998/Math/MathML"
guardFactoryWith="ENABLE(MATHML)"
attrsNullNamespace
+accent
+accentunder
actiontype
alttext
background
@@ -13,25 +15,39 @@ definitionURL
denomalign
depth
dir
+display
+displaystyle
encoding
+fence
fontfamily
fontsize
fontstyle
fontweight
+form
height
+href
+largeop
linethickness
+lspace
mathbackground
mathcolor
mathsize
mathvariant
+maxsize
+minsize
+movablelimits
notation
numalign
open
rowspan
+rspace
+separator
selection
separators
src
stretchy
+symmetric
subscriptshift
superscriptshift
+voffset
width
diff --git a/Source/WebCore/mathml/mathtags.in b/Source/WebCore/mathml/mathtags.in
index 7cce6d72e..8d0f76cd4 100644
--- a/Source/WebCore/mathml/mathtags.in
+++ b/Source/WebCore/mathml/mathtags.in
@@ -1,50 +1,50 @@
namespace="MathML"
namespaceURI="http://www.w3.org/1998/Math/MathML"
guardFactoryWith="ENABLE(MATHML)"
-fallbackInterfaceName="MathMLElement"
+fallbackInterfaceName="MathMLUnknownElement"
-annotation interfaceName=MathMLTextElement
-annotation-xml interfaceName=MathMLInlineContainerElement
+annotation interfaceName=MathMLAnnotationElement
+annotation-xml interfaceName=MathMLAnnotationElement
maction interfaceName=MathMLSelectElement
math
-mfrac interfaceName=MathMLInlineContainerElement
-mfenced interfaceName=MathMLInlineContainerElement
-msubsup interfaceName=MathMLInlineContainerElement
-merror interfaceName=MathMLInlineContainerElement
-mphantom interfaceName=MathMLInlineContainerElement
-mrow interfaceName=MathMLInlineContainerElement
-mstyle interfaceName=MathMLInlineContainerElement
-mover interfaceName=MathMLInlineContainerElement
-munder interfaceName=MathMLInlineContainerElement
-munderover interfaceName=MathMLInlineContainerElement
-msqrt interfaceName=MathMLInlineContainerElement
-mroot interfaceName=MathMLInlineContainerElement
-mi interfaceName=MathMLTextElement
-mn interfaceName=MathMLTextElement
-mo interfaceName=MathMLTextElement
-mtext interfaceName=MathMLTextElement
-mspace interfaceName=MathMLTextElement
-msub interfaceName=MathMLInlineContainerElement
-msup interfaceName=MathMLInlineContainerElement
-mtable interfaceName=MathMLInlineContainerElement
-mtr interfaceName=MathMLElement
-mtd interfaceName=MathMLElement
-mmultiscripts interfaceName=MathMLInlineContainerElement
-mprescripts interfaceName=MathMLInlineContainerElement
+mfrac interfaceName=MathMLFractionElement
+mfenced interfaceName=MathMLRowElement
+msubsup interfaceName=MathMLScriptsElement
+merror interfaceName=MathMLRowElement
+mpadded interfaceName=MathMLPaddedElement
+mphantom interfaceName=MathMLRowElement
+mrow interfaceName=MathMLRowElement
+mstyle interfaceName=MathMLRowElement
+mover interfaceName=MathMLUnderOverElement
+munder interfaceName=MathMLUnderOverElement
+munderover interfaceName=MathMLUnderOverElement
+msqrt interfaceName=MathMLRowElement
+mroot interfaceName=MathMLRowElement
+mi interfaceName=MathMLTokenElement
+mn interfaceName=MathMLTokenElement
+mo interfaceName=MathMLOperatorElement
+mtext interfaceName=MathMLTokenElement
+ms interfaceName=MathMLTokenElement
+mspace interfaceName=MathMLSpaceElement
+msub interfaceName=MathMLScriptsElement
+msup interfaceName=MathMLScriptsElement
+mtable interfaceName=MathMLPresentationElement
+mtr interfaceName=MathMLPresentationElement
+mtd interfaceName=MathMLPresentationElement
+mmultiscripts interfaceName=MathMLScriptsElement
+mprescripts interfaceName=MathMLPresentationElement
menclose interfaceName=MathMLMencloseElement
-none interfaceName=MathMLInlineContainerElement
+none interfaceName=MathMLPresentationElement
semantics interfaceName=MathMLSelectElement
-maligngroup interfaceName=MathMLElement
-malignmark interfaceName=MathMLElement
-mglyph interfaceName=MathMLElement
-mlabeledtr interfaceName=MathMLElement
-mlongdiv interfaceName=MathMLElement
-mpadded interfaceName=MathMLElement
-ms interfaceName=MathMLElement
-mscarries interfaceName=MathMLElement
-mscarry interfaceName=MathMLElement
-msgroup interfaceName=MathMLElement
-msline interfaceName=MathMLElement
-msrow interfaceName=MathMLElement
-mstack interfaceName=MathMLElement
+maligngroup interfaceName=MathMLPresentationElement
+malignmark interfaceName=MathMLPresentationElement
+mglyph interfaceName=MathMLPresentationElement
+mlabeledtr interfaceName=MathMLPresentationElement
+mlongdiv interfaceName=MathMLPresentationElement
+mscarries interfaceName=MathMLPresentationElement
+mscarry interfaceName=MathMLPresentationElement
+msgroup interfaceName=MathMLPresentationElement
+msline interfaceName=MathMLPresentationElement
+msrow interfaceName=MathMLPresentationElement
+mstack interfaceName=MathMLPresentationElement