summaryrefslogtreecommitdiff
path: root/Source/WebCore/mathml/MathMLSelectElement.cpp
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/mathml/MathMLSelectElement.cpp
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
downloadqtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/mathml/MathMLSelectElement.cpp')
-rw-r--r--Source/WebCore/mathml/MathMLSelectElement.cpp245
1 files changed, 245 insertions, 0 deletions
diff --git a/Source/WebCore/mathml/MathMLSelectElement.cpp b/Source/WebCore/mathml/MathMLSelectElement.cpp
new file mode 100644
index 000000000..1226a36d4
--- /dev/null
+++ b/Source/WebCore/mathml/MathMLSelectElement.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 The MathJax Consortium. 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 "MathMLSelectElement.h"
+
+#if ENABLE(MATHML)
+
+#include "Event.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "MathMLNames.h"
+#include "RenderMathMLRow.h"
+#include "SVGElement.h"
+#include "SVGNames.h"
+#include "StyleTreeResolver.h"
+
+namespace WebCore {
+
+using namespace MathMLNames;
+
+MathMLSelectElement::MathMLSelectElement(const QualifiedName& tagName, Document& document)
+ : MathMLInlineContainerElement(tagName, document)
+ , m_selectedChild(nullptr)
+{
+}
+
+Ref<MathMLSelectElement> MathMLSelectElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new MathMLSelectElement(tagName, document));
+}
+
+RenderPtr<RenderElement> MathMLSelectElement::createElementRenderer(Ref<RenderStyle>&& style, const RenderTreePosition&)
+{
+ 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
+{
+ return MathMLElement::childShouldCreateRenderer(child) && m_selectedChild == &child;
+}
+
+void MathMLSelectElement::finishParsingChildren()
+{
+ updateSelectedChild();
+ MathMLInlineContainerElement::finishParsingChildren();
+}
+
+void MathMLSelectElement::childrenChanged(const ChildChange& change)
+{
+ updateSelectedChild();
+ MathMLInlineContainerElement::childrenChanged(change);
+}
+
+void MathMLSelectElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
+{
+ if (hasTagName(mactionTag) && (name == MathMLNames::actiontypeAttr || name == MathMLNames::selectionAttr))
+ updateSelectedChild();
+
+ MathMLInlineContainerElement::attributeChanged(name, oldValue, newValue, reason);
+}
+
+int MathMLSelectElement::getSelectedActionChildAndIndex(Element*& selectedChild)
+{
+ 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 i;
+ for (i = 1; i < selection; i++) {
+ Element* nextChild = selectedChild->nextElementSibling();
+ if (!nextChild)
+ break;
+ selectedChild = nextChild;
+ }
+
+ return i;
+}
+
+Element* MathMLSelectElement::getSelectedActionChild()
+{
+ ASSERT(hasTagName(mactionTag));
+
+ Element* child = firstElementChild();
+ if (!child)
+ return child;
+
+ // The value of the actiontype attribute is case-sensitive.
+ const AtomicString& actiontype = fastGetAttribute(MathMLNames::actiontypeAttr);
+ if (actiontype == "statusline")
+ // FIXME: implement user interaction for the "statusline" action type (http://wkbug/124922).
+ { }
+ else if (actiontype == "tooltip")
+ // FIXME: implement user interaction for the "tooltip" action type (http://wkbug/124921).
+ { }
+ else {
+ // For the "toggle" action type or any unknown action type, we rely on the value of the selection attribute to determine the visible child.
+ getSelectedActionChildAndIndex(child);
+ }
+
+ return child;
+}
+
+Element* MathMLSelectElement::getSelectedSemanticsChild()
+{
+ ASSERT(hasTagName(semanticsTag));
+
+ Element* child = firstElementChild();
+ if (!child)
+ return nullptr;
+
+ 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 (!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 (!is<MathMLElement>(*child))
+ continue;
+
+ 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))
+ continue;
+ // Otherwise, we assume it is a text annotation that can always be displayed and we stop here.
+ return child;
+ }
+
+ 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))
+ 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.
+ const AtomicString& value = child->fastGetAttribute(MathMLNames::encodingAttr);
+ if (isMathMLEncoding(value) || isSVGEncoding(value) || isHTMLEncoding(value))
+ return child;
+ }
+ }
+
+ // We fallback to the first child.
+ return firstElementChild();
+}
+
+void MathMLSelectElement::updateSelectedChild()
+{
+ Element* newSelectedChild = hasTagName(mactionTag) ? getSelectedActionChild() : getSelectedSemanticsChild();
+
+ if (m_selectedChild == newSelectedChild)
+ return;
+
+ if (m_selectedChild && m_selectedChild->renderer())
+ Style::detachRenderTree(*m_selectedChild);
+
+ m_selectedChild = newSelectedChild;
+ setNeedsStyleRecalc();
+}
+
+void MathMLSelectElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ if (fastGetAttribute(MathMLNames::actiontypeAttr) == "toggle") {
+ toggle();
+ event->setDefaultHandled();
+ return;
+ }
+ }
+
+ MathMLInlineContainerElement::defaultEventHandler(event);
+}
+
+bool MathMLSelectElement::willRespondToMouseClickEvents()
+{
+ return fastGetAttribute(MathMLNames::actiontypeAttr) == "toggle";
+}
+
+void MathMLSelectElement::toggle()
+{
+ // Select the successor of the currently selected child
+ // or the first child if the currently selected child is the last.
+ Element* selectedChild;
+ int newSelectedChildIndex = getSelectedActionChildAndIndex(selectedChild) + 1;
+ if (!selectedChild || !selectedChild->nextElementSibling())
+ newSelectedChildIndex = 1;
+
+ // 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));
+}
+
+}
+
+#endif // ENABLE(MATHML)