Minor refactoring in RenderMathMLOperator
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLMenclose.cpp
1 /*
2  * Copyright (C) 2014 Gurpreet Kaur (k.gurpreet@samsung.com). 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 "RenderMathMLMenclose.h"
30
31 #include "GraphicsContext.h"
32 #include "MathMLMencloseElement.h"
33 #include "PaintInfo.h"
34 #include "RenderMathMLSquareRoot.h"
35 #include <wtf/MathExtras.h>
36
37 namespace WebCore {
38
39 using namespace MathMLNames;
40
41 RenderMathMLMenclose::RenderMathMLMenclose(Element& element, std::unique_ptr<RenderStyle> style)
42     : RenderMathMLRow(element, WTFMove(style))
43 {
44 }
45
46 void RenderMathMLMenclose::addChild(RenderObject* newChild, RenderObject* beforeChild)
47 {
48     MathMLMencloseElement* menclose = downcast<MathMLMencloseElement>(element());
49     // Allow an anonymous RenderMathMLSquareRoot to handle drawing the radical
50     // notation, rather than duplicating the code needed to paint a root.
51     if (!firstChild() && menclose->isRadical())        
52         RenderMathMLBlock::addChild(RenderMathMLSquareRoot::createAnonymousWithParentRenderer(*this).leakPtr());
53     
54     if (newChild) {
55         if (firstChild() && menclose->isRadical())
56             downcast<RenderElement>(*firstChild()).addChild(newChild, beforeChild && beforeChild->parent() == firstChild() ? beforeChild : nullptr);
57         else
58             RenderMathMLBlock::addChild(newChild, beforeChild);
59     }
60 }
61
62 void RenderMathMLMenclose::computePreferredLogicalWidths()
63 {
64     ASSERT(preferredLogicalWidthsDirty());
65
66     RenderMathMLBlock::computePreferredLogicalWidths();
67     const int paddingTop = 6;
68
69     MathMLMencloseElement* menclose = downcast<MathMLMencloseElement>(element());
70     const Vector<String>& notationValues = menclose->notationValues();
71     size_t notationalValueSize = notationValues.size();
72     for (size_t i = 0; i < notationalValueSize; i++) {
73         if (notationValues[i] == "circle") {
74             m_minPreferredLogicalWidth = minPreferredLogicalWidth() * sqrtOfTwoFloat;
75             m_maxPreferredLogicalWidth = maxPreferredLogicalWidth() * sqrtOfTwoFloat;
76         }
77     }
78
79     if (menclose->isDefaultLongDiv()) {
80         style().setPaddingTop(Length(paddingTop, Fixed));
81         style().setPaddingLeft(Length(menclose->longDivLeftPadding().toInt(), Fixed));
82     }
83     setPreferredLogicalWidthsDirty(false);
84 }
85
86 void RenderMathMLMenclose::updateLogicalHeight()
87 {
88     MathMLMencloseElement* menclose = downcast<MathMLMencloseElement>(element());
89     const Vector<String>& notationValues = menclose->notationValues();
90     size_t notationalValueSize = notationValues.size();
91     for (size_t i = 0; i < notationalValueSize; i++)
92         if (notationValues[i] == "circle")
93             setLogicalHeight(logicalHeight() * sqrtOfTwoFloat);
94 }
95
96 void RenderMathMLMenclose::paint(PaintInfo& info, const LayoutPoint& paintOffset)
97 {
98     RenderMathMLBlock::paint(info, paintOffset);
99
100     if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE)
101         return;
102     
103     MathMLMencloseElement* menclose = downcast<MathMLMencloseElement>(element());
104     const Vector<String>& notationValues = menclose->notationValues();
105     size_t notationalValueSize = notationValues.size();
106     bool isDefaultLongDiv = menclose->isDefaultLongDiv();
107     if ((notationalValueSize && checkNotationalValuesValidity(notationValues)) || isDefaultLongDiv) {
108         IntRect rect = absoluteBoundingBoxRect();
109         int left = rect.x();
110         int top = rect.y();
111         int boxWidth = rect.width();
112         int boxHeight = rect.height();
113         int halfboxWidth = rect.width() / 2;
114         int halfboxHeight = rect.height() / 2;
115
116         GraphicsContextStateSaver stateSaver(info.context());
117         info.context().setStrokeThickness(1);
118         info.context().setStrokeStyle(SolidStroke);
119         info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
120         // TODO add support for notation value updiagonalarrow https://bugs.webkit.org/show_bug.cgi?id=127466
121         for (size_t i = 0; i < notationalValueSize; i++) {
122             if (notationValues[i] == "updiagonalstrike")
123                 info.context().drawLine(IntPoint(left, top + boxHeight), IntPoint(left + boxWidth, top));
124             else if (notationValues[i] == "downdiagonalstrike")
125                 info.context().drawLine(IntPoint(left, top), IntPoint(left + boxWidth, top + boxHeight));
126             else if (notationValues[i] == "verticalstrike")
127                 info.context().drawLine(IntPoint(left + halfboxWidth, top), IntPoint(left + halfboxWidth, top + boxHeight));
128             else if (notationValues[i] == "horizontalstrike")
129                 info.context().drawLine(IntPoint(left, top + halfboxHeight), IntPoint(left + boxWidth, top + halfboxHeight));
130             else if (notationValues[i] == "circle") {
131                 info.context().setFillColor(Color::transparent);
132                 info.context().drawEllipse(rect);
133             } else if (notationValues[i] == "longdiv")
134                 isDefaultLongDiv = true;
135         }
136         if (isDefaultLongDiv) {
137             Path root;
138             int midxPoint = 0;
139             root.moveTo(FloatPoint(left, top));
140             int childLeft = firstChild() ? firstChild()->absoluteBoundingBoxRect().x() : 0;
141             if (childLeft)
142                 midxPoint= childLeft - left;
143             else
144                 midxPoint = style().paddingLeft().value();
145             root.addBezierCurveTo(FloatPoint(left, top), FloatPoint(left + midxPoint, top + halfboxHeight), FloatPoint(left, top + boxHeight));
146             info.context().strokePath(root);
147             if (isDefaultLongDiv)
148                 info.context().drawLine(IntPoint(left, top), IntPoint(left + boxWidth + midxPoint, top));
149         }
150     }
151 }
152
153 bool RenderMathMLMenclose::checkNotationalValuesValidity(const Vector<String>& attr) const
154 {
155     size_t attrSize = attr.size();
156     for (size_t i = 0; i < attrSize; i++) {
157         if (attr[i] == "updiagonalstrike" || attr[i] == "downdiagonalstrike" || attr[i] == "horizontalstrike" || attr[i] == "verticalstrike"
158             || attr[i] == "circle" || attr[i] == "longdiv")
159             return true;
160     }
161     return false;
162 }
163
164 }
165 #endif // ENABLE(MATHML)