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 | |
41 | namespace WebCore { |
42 | |
43 | using namespace MathMLNames; |
44 | |
45 | Ref<MathMLStyle> MathMLStyle::create() |
46 | { |
47 | return adoptRef(*new MathMLStyle()); |
48 | } |
49 | |
50 | const 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 | |
60 | void 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 | |
71 | RenderObject* 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 | |
81 | void 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 | |
100 | void 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 | |