Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLRadicalOperator.cpp
1 /*
2  * Copyright (C) 2014 Frédéric Wang (fred.wang@free.fr). 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 "RenderMathMLRadicalOperator.h"
30
31 namespace WebCore {
32
33 using namespace MathMLNames;
34
35 static const UChar gRadicalCharacter = 0x221A;
36
37 // This class relies on the RenderMathMLOperator class to draw a radical symbol.
38 // This does not work well when an OpenType MATH font is not available.
39 // In that case, we fallback to the old implementation of RenderMathMLRoot.cpp with graphic primitives.
40
41 // Normal width of the front of the radical sign, before the base & overbar (em)
42 const float gFrontWidthEms = 0.75f;
43 // Horizontal position of the bottom point of the radical (* frontWidth)
44 const float gRadicalBottomPointXFront = 0.5f;
45 // Lower the radical sign's bottom point (px)
46 const int gRadicalBottomPointLower = 3;
47 // Horizontal position of the top left point of the radical "dip" (* frontWidth)
48 const float gRadicalDipLeftPointXFront = 0.8f;
49 // Vertical position of the top left point of a sqrt radical "dip" (* baseHeight)
50 const float gSqrtRadicalDipLeftPointYPos = 0.5f;
51 // Vertical shift of the left end point of the radical (em)
52 const float gRadicalLeftEndYShiftEms = 0.05f;
53
54 // Radical line thickness (em)
55 const float gRadicalLineThicknessEms = 0.02f;
56 // Radical thick line thickness (em)
57 const float gRadicalThickLineThicknessEms = 0.1f;
58
59 RenderMathMLRadicalOperator::RenderMathMLRadicalOperator(Document& document, Ref<RenderStyle>&& style)
60     : RenderMathMLOperator(document, WTFMove(style), String(&gRadicalCharacter, 1), MathMLOperatorDictionary::Prefix)
61 {
62 }
63
64 void RenderMathMLRadicalOperator::stretchTo(LayoutUnit heightAboveBaseline, LayoutUnit depthBelowBaseline)
65 {
66     if (!style().fontCascade().primaryFont().mathData()) {
67         // If we do not have an OpenType MATH font, we always make the radical depth a bit larger than the target.
68         depthBelowBaseline += gRadicalBottomPointLower;
69     }
70
71     RenderMathMLOperator::stretchTo(heightAboveBaseline, depthBelowBaseline);
72 }
73
74 void RenderMathMLRadicalOperator::setOperatorProperties()
75 {
76     RenderMathMLOperator::setOperatorProperties();
77     // We remove spacing around the radical symbol.
78     setLeadingSpace(0);
79     setTrailingSpace(0);
80 }
81
82 void RenderMathMLRadicalOperator::computePreferredLogicalWidths()
83 {
84     ASSERT(preferredLogicalWidthsDirty());
85
86     if (style().fontCascade().primaryFont().mathData()) {
87         RenderMathMLOperator::computePreferredLogicalWidths();
88         return;
89     }
90
91     // If we do not have an OpenType MATH font, the front width is just given by the gFrontWidthEms constant.
92     int frontWidth = lroundf(gFrontWidthEms * style().fontSize());
93     m_minPreferredLogicalWidth = frontWidth;
94     m_maxPreferredLogicalWidth = frontWidth;
95 }
96
97 void RenderMathMLRadicalOperator::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
98 {
99     if (style().fontCascade().primaryFont().mathData()) {
100         RenderMathMLOperator::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
101         return;
102     }
103
104     // If we do not have an OpenType MATH font, the logical height is always the stretch size.
105     logicalHeight = stretchSize();
106     RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
107 }
108
109 void RenderMathMLRadicalOperator::paint(PaintInfo& info, const LayoutPoint& paintOffset)
110 {
111     if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE)
112         return;
113
114     if (style().fontCascade().primaryFont().mathData()) {
115         RenderMathMLOperator::paint(info, paintOffset);
116         return;
117     }
118
119     // If we do not have an OpenType MATH font, we paint the radical sign with graphic primitives.
120     IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + contentBoxRect().location());
121     int frontWidth = lroundf(gFrontWidthEms * style().fontSize());
122     int startX = adjustedPaintOffset.x() + frontWidth;
123     int baseHeight = stretchSize() - gRadicalBottomPointLower;
124
125     float radicalDipLeftPointYPos = gSqrtRadicalDipLeftPointYPos * baseHeight;
126
127     FloatPoint overbarLeftPoint(startX, adjustedPaintOffset.y());
128     FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower);
129     FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + radicalDipLeftPointYPos);
130     FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style().fontSize());
131
132     GraphicsContextStateSaver stateSaver(info.context());
133
134     info.context().setStrokeThickness(gRadicalLineThicknessEms * style().fontSize());
135     info.context().setStrokeStyle(SolidStroke);
136     info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
137     info.context().setLineJoin(MiterJoin);
138     info.context().setMiterLimit(style().fontSize());
139
140     Path root;
141
142     root.moveTo(FloatPoint(overbarLeftPoint.x(), adjustedPaintOffset.y()));
143     // draw from top left corner to bottom point of radical
144     root.addLineTo(bottomPoint);
145     // draw from bottom point to top of left part of radical base "dip"
146     root.addLineTo(dipLeftPoint);
147     // draw to end
148     root.addLineTo(leftEnd);
149
150     info.context().strokePath(root);
151
152     GraphicsContextStateSaver maskStateSaver(info.context());
153
154     // Build a mask to draw the thick part of the root.
155     Path maskPath;
156
157     maskPath.moveTo(overbarLeftPoint);
158     maskPath.addLineTo(bottomPoint);
159     maskPath.addLineTo(dipLeftPoint);
160     maskPath.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y()));
161
162     info.context().clipPath(maskPath);
163
164     // Draw the thick part of the root.
165     info.context().setStrokeThickness(gRadicalThickLineThicknessEms * style().fontSize());
166     info.context().setLineCap(SquareCap);
167
168     Path line;
169     line.moveTo(bottomPoint);
170     line.addLineTo(dipLeftPoint);
171
172     info.context().strokePath(line);
173 }
174
175 }
176
177 #endif