#include "config.h"
#if ENABLE(MATHML)
#include "MathMLElement.h"
#include "ElementIterator.h"
#include "HTMLElement.h"
#include "HTMLMapElement.h"
#include "HTMLNames.h"
#include "MathMLNames.h"
#include "MathMLSelectElement.h"
#include "RenderTableCell.h"
#include "SVGElement.h"
#include "SVGNames.h"
namespace WebCore {
using namespace MathMLNames;
MathMLElement::MathMLElement(const QualifiedName& tagName, Document& document)
: StyledElement(tagName, document, CreateMathMLElement)
{
}
Ref<MathMLElement> MathMLElement::create(const QualifiedName& tagName, Document& document)
{
return adoptRef(*new MathMLElement(tagName, document));
}
bool MathMLElement::isPresentationMathML() const
{
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);
}
bool MathMLElement::isPhrasingContent(const Node& node) const
{
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)) {
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 MathMLElement::isFlowContent(const Node& node) const
{
if (isPhrasingContent(node))
return true;
if (!is<HTMLElement>(node))
return false;
auto& htmlElement = downcast<HTMLElement>(node);
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);
}
int MathMLElement::colSpan() const
{
if (!hasTagName(mtdTag))
return 1;
const AtomicString& colSpanValue = fastGetAttribute(columnspanAttr);
return std::max(1, colSpanValue.toInt());
}
int MathMLElement::rowSpan() const
{
if (!hasTagName(mtdTag))
return 1;
const AtomicString& rowSpanValue = fastGetAttribute(rowspanAttr);
return std::max(1, rowSpanValue.toInt());
}
void MathMLElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
if (name == rowspanAttr) {
if (is<RenderTableCell>(renderer()) && hasTagName(mtdTag))
downcast<RenderTableCell>(*renderer()).colSpanOrRowSpanChanged();
} else if (name == columnspanAttr) {
if (is<RenderTableCell>(renderer()) && hasTagName(mtdTag))
downcast<RenderTableCell>(renderer())->colSpanOrRowSpanChanged();
} else
StyledElement::parseAttribute(name, value);
}
bool MathMLElement::isPresentationAttribute(const QualifiedName& name) const
{
if (name == backgroundAttr || name == colorAttr || name == dirAttr || name == fontfamilyAttr || name == fontsizeAttr || name == fontstyleAttr || name == fontweightAttr || name == mathbackgroundAttr || name == mathcolorAttr || name == mathsizeAttr)
return true;
return StyledElement::isPresentationAttribute(name);
}
void MathMLElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
{
if (name == mathbackgroundAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundColor, value);
else if (name == mathsizeAttr) {
if (value != "normal" && value != "small" && value != "big")
addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, value);
} else if (name == mathcolorAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyColor, value);
else if (name == fontsizeAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyFontSize, value);
else if (name == backgroundAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyBackgroundColor, value);
else if (name == colorAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyColor, value);
else if (name == fontstyleAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyFontStyle, value);
else if (name == fontweightAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyFontWeight, value);
else if (name == fontfamilyAttr)
addPropertyToPresentationAttributeStyle(style, CSSPropertyFontFamily, value);
else if (name == dirAttr) {
if (hasTagName(mathTag) || hasTagName(mrowTag) || hasTagName(mstyleTag) || isMathMLToken())
addPropertyToPresentationAttributeStyle(style, CSSPropertyDirection, value);
} else {
ASSERT(!isPresentationAttribute(name));
StyledElement::collectStyleForPresentationAttribute(name, value
, style);
}
}
bool MathMLElement::childShouldCreateRenderer(const Node& child) const
{
if (hasTagName(annotation_xmlTag)) {
const AtomicString& value = fastGetAttribute(MathMLNames::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;
}
return is<MathMLElement>(child);
}
void MathMLElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason reason)
{
if (isSemanticAnnotation() && (name == MathMLNames::srcAttr || name == MathMLNames::encodingAttr)) {
Element* parent = parentElement();
if (is<MathMLElement>(parent) && parent->hasTagName(semanticsTag))
downcast<MathMLElement>(*parent).updateSelectedChild();
}
StyledElement::attributeChanged(name, oldValue, newValue, reason);
}
}
#endif // ENABLE(MATHML)