diff options
Diffstat (limited to 'Source/WebCore/mathml')
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 |