diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/mathml/MathMLOperatorElement.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/mathml/MathMLOperatorElement.cpp')
-rw-r--r-- | Source/WebCore/mathml/MathMLOperatorElement.cpp | 271 |
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) |