summaryrefslogtreecommitdiff
path: root/Source/WebCore/mathml/MathMLOperatorElement.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/mathml/MathMLOperatorElement.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/mathml/MathMLOperatorElement.cpp')
-rw-r--r--Source/WebCore/mathml/MathMLOperatorElement.cpp271
1 files changed, 271 insertions, 0 deletions
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)