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#include "MathMLStyle.h"
28
29#if ENABLE(MATHML)
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
41namespace WebCore {
42
43using namespace MathMLNames;
44
45Ref<MathMLStyle> MathMLStyle::create()
46{
47 return adoptRef(*new MathMLStyle());
48}
49
50const MathMLStyle* MathMLStyle::getMathMLStyle(RenderObject* renderer)
51{
52 // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this?
53 if (is<RenderMathMLTable>(renderer))
54 return &downcast<RenderMathMLTable>(*renderer).mathMLStyle();
55 if (is<RenderMathMLBlock>(renderer))
56 return &downcast<RenderMathMLBlock>(*renderer).mathMLStyle();
57 return nullptr;
58}
59
60void MathMLStyle::resolveMathMLStyleTree(RenderObject* renderer)
61{
62 for (auto* child = renderer; child; child = child->nextInPreOrder(renderer)) {
63 // FIXME: Should we make RenderMathMLTable derive from RenderMathMLBlock in order to simplify this?
64 if (is<RenderMathMLTable>(child))
65 downcast<RenderMathMLTable>(*child).mathMLStyle().resolveMathMLStyle(child);
66 else if (is<RenderMathMLBlock>(child))
67 downcast<RenderMathMLBlock>(*child).mathMLStyle().resolveMathMLStyle(child);
68 }
69}
70
71RenderObject* MathMLStyle::getMathMLParentNode(RenderObject* renderer)
72{
73 auto* parentRenderer = renderer->parent();
74
75 while (parentRenderer && !(is<RenderMathMLTable>(parentRenderer) || is<RenderMathMLBlock>(parentRenderer)))
76 parentRenderer = parentRenderer->parent();
77
78 return parentRenderer;
79}
80
81void MathMLStyle::updateStyleIfNeeded(RenderObject* renderer, bool oldDisplayStyle, MathMLElement::MathVariant oldMathVariant)
82{
83 // RenderMathMLFencedOperator does not support mathvariant or displaystyle transforms.
84 // See https://bugs.webkit.org/show_bug.cgi?id=160509#c1.
85 bool isNonAnonymousTokenElement = is<RenderMathMLToken>(renderer) && !renderer->isAnonymous();
86
87 if (oldDisplayStyle != m_displayStyle) {
88 renderer->setNeedsLayoutAndPrefWidthsRecalc();
89 if (isNonAnonymousTokenElement)
90 downcast<RenderMathMLToken>(renderer)->updateTokenContent();
91 else if (is<RenderMathMLFraction>(renderer))
92 downcast<RenderMathMLFraction>(renderer)->updateFromElement();
93 }
94 if (oldMathVariant != m_mathVariant) {
95 if (isNonAnonymousTokenElement)
96 downcast<RenderMathMLToken>(renderer)->updateTokenContent();
97 }
98}
99
100void MathMLStyle::resolveMathMLStyle(RenderObject* renderer)
101{
102 ASSERT(renderer);
103
104 bool oldDisplayStyle = m_displayStyle;
105 MathMLElement::MathVariant oldMathVariant = m_mathVariant;
106 auto* parentRenderer = getMathMLParentNode(renderer);
107 const MathMLStyle* parentStyle = getMathMLStyle(parentRenderer);
108
109 // By default, we just inherit the style from our parent.
110 m_displayStyle = false;
111 m_mathVariant = MathMLElement::MathVariant::None;
112 if (parentStyle) {
113 setDisplayStyle(parentStyle->displayStyle());
114 setMathVariant(parentStyle->mathVariant());
115 }
116
117 // Early return for anonymous renderers.
118 if (renderer->isAnonymous()) {
119 updateStyleIfNeeded(renderer, oldDisplayStyle, oldMathVariant);
120 return;
121 }
122
123 if (is<RenderMathMLMath>(renderer) || is<RenderMathMLTable>(renderer))
124 m_displayStyle = false; // The default displaystyle of <math> and <mtable> is false.
125 else if (parentRenderer) {
126 if (is<RenderMathMLFraction>(parentRenderer))
127 m_displayStyle = false; // <mfrac> sets displaystyle to false within its numerator and denominator.
128 else if ((is<RenderMathMLRoot>(parentRenderer) && !parentRenderer->isRenderMathMLSquareRoot()) || is<RenderMathMLScripts>(parentRenderer) || is<RenderMathMLUnderOver>(parentRenderer)) {
129 // <mroot>, <msub>, <msup>, <msubsup>, <mmultiscripts>, <munder>, <mover> and <munderover> elements set displaystyle to false within their scripts.
130 auto* base = downcast<RenderBox>(parentRenderer)->firstChildBox();
131 if (renderer != base)
132 m_displayStyle = false;
133 }
134 }
135
136 // The displaystyle and mathvariant attributes override the default behavior.
137 auto* element = downcast<RenderElement>(renderer)->element();
138 if (is<MathMLElement>(element)) {
139 Optional<bool> displayStyle = downcast<MathMLElement>(element)->specifiedDisplayStyle();
140 if (displayStyle)
141 m_displayStyle = displayStyle.value();
142 Optional<MathMLElement::MathVariant> mathVariant = downcast<MathMLElement>(element)->specifiedMathVariant();
143 if (mathVariant)
144 m_mathVariant = mathVariant.value();
145 }
146 updateStyleIfNeeded(renderer, oldDisplayStyle, oldMathVariant);
147}
148
149}
150
151#endif // ENABLE(MATHML)
152