Implement an internal style property for displaystyle.
[WebKit-https.git] / Source / WebCore / rendering / mathml / MathMLStyle.cpp
1 /*
2  * Copyright (C) 2016 Igalia S.L. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if ENABLE(MATHML)
29 #include "MathMLStyle.h"
30
31 #include "MathMLElement.h"
32 #include "MathMLNames.h"
33 #include "RenderMathMLBlock.h"
34 #include "RenderMathMLFraction.h"
35 #include "RenderMathMLMath.h"
36 #include "RenderMathMLRoot.h"
37 #include "RenderMathMLScripts.h"
38 #include "RenderMathMLToken.h"
39 #include "RenderMathMLUnderOver.h"
40
41 namespace WebCore {
42
43 using namespace MathMLNames;
44
45 Ref<MathMLStyle> MathMLStyle::create()
46 {
47     return adoptRef(*new MathMLStyle());
48 }
49
50 void MathMLStyle::setDisplayStyle(RenderObject* renderer)
51 {
52     if (!renderer)
53         return;
54
55     // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this?
56     if (is<RenderMathMLTable>(renderer))
57         m_displayStyle = downcast<RenderMathMLTable>(renderer)->mathMLStyle()->displayStyle();
58     else if (is<RenderMathMLBlock>(renderer))
59         m_displayStyle = downcast<RenderMathMLBlock>(renderer)->mathMLStyle()->displayStyle();
60 }
61
62 void MathMLStyle::resolveMathMLStyleTree(RenderObject* renderer)
63 {
64     for (auto* child = renderer; child; child = child->nextInPreOrder(renderer)) {
65         // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this?
66         if (is<RenderMathMLTable>(child))
67             downcast<RenderMathMLTable>(child)->mathMLStyle()->resolveMathMLStyle(child);
68         else if (is<RenderMathMLBlock>(child))
69             downcast<RenderMathMLBlock>(child)->mathMLStyle()->resolveMathMLStyle(child);
70     }
71 }
72
73 RenderObject* MathMLStyle::getMathMLParentNode(RenderObject* renderer)
74 {
75     auto* parentRenderer = renderer->parent();
76
77     while (parentRenderer && !(is<RenderMathMLTable>(parentRenderer) || is<RenderMathMLBlock>(parentRenderer)))
78         parentRenderer = parentRenderer->parent();
79
80     return parentRenderer;
81 }
82
83 void MathMLStyle::updateStyleIfNeeded(RenderObject* renderer, bool oldDisplayStyle)
84 {
85     if (oldDisplayStyle != m_displayStyle) {
86         if (is<RenderMathMLToken>(renderer))
87             downcast<RenderMathMLToken>(renderer)->updateTokenContent();
88         else if (is<RenderMathMLRoot>(renderer))
89             downcast<RenderMathMLRoot>(renderer)->updateStyle();
90     }
91 }
92
93 void MathMLStyle::resolveMathMLStyle(RenderObject* renderer)
94 {
95     ASSERT(renderer);
96
97     bool oldDisplayStyle = m_displayStyle;
98
99     // For anonymous renderers, we just inherit the style from our parent.
100     if (renderer->isAnonymous()) {
101         setDisplayStyle(getMathMLParentNode(renderer));
102         updateStyleIfNeeded(renderer, oldDisplayStyle);
103         return;
104     }
105
106     if (is<RenderMathMLMath>(renderer))
107         m_displayStyle = downcast<RenderElement>(renderer)->element()->fastGetAttribute(displayAttr) == "block"; // The default displaystyle of the <math> element depends on its display attribute.
108     else if (is<RenderMathMLTable>(renderer))
109         m_displayStyle = false; // The default displaystyle of <mtable> is false.
110     else if (auto* parentRenderer = getMathMLParentNode(renderer)) {
111         setDisplayStyle(parentRenderer); // The default displaystyle is inherited from our parent.
112         if (is<RenderMathMLFraction>(parentRenderer))
113             m_displayStyle = false; // <mfrac> sets displaystyle to false within its numerator and denominator.
114         else if ((is<RenderMathMLRoot>(parentRenderer) && !parentRenderer->isRenderMathMLSquareRoot()) || is<RenderMathMLScripts>(parentRenderer) || is<RenderMathMLUnderOver>(parentRenderer)) {
115             // <mroot>, <msub>, <msup>, <msubsup>, <mmultiscripts>, <munder>, <mover> and <munderover> elements set displaystyle to false within their scripts.
116             auto* base = downcast<RenderBox>(parentRenderer)->firstChildBox();
117             if (renderer != base)
118                 m_displayStyle = false;
119         }
120     }
121
122     // The displaystyle attribute on the <math>, <mtable> or <mstyle> elements override the default behavior.
123     const auto* element = downcast<RenderElement>(renderer)->element();
124     const QualifiedName& tagName = element->tagQName();
125     if (tagName == mathTag || tagName == mtableTag || tagName == mstyleTag) {
126         // We only modify the value of displaystyle if there is an explicit and valid attribute.
127         const AtomicString& attributeValue = element->fastGetAttribute(displaystyleAttr);
128         if (attributeValue == "true")
129             m_displayStyle = true;
130         else if (attributeValue == "false")
131             m_displayStyle = false;
132     }
133
134     updateStyleIfNeeded(renderer, oldDisplayStyle);
135 }
136
137 }
138
139 #endif // ENABLE(MATHML)