Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / style / BasicShapes.cpp
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. 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  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "config.h"
31
32 #include "BasicShapes.h"
33
34 #include "BasicShapeFunctions.h"
35 #include "CalculationValue.h"
36 #include "FloatRect.h"
37 #include "FloatRoundedRect.h"
38 #include "LengthFunctions.h"
39 #include "Path.h"
40 #include "RenderBox.h"
41 #include "SVGPathByteStream.h"
42 #include "SVGPathUtilities.h"
43
44 namespace WebCore {
45
46 void BasicShapeCenterCoordinate::updateComputedLength()
47 {
48     if (m_direction == TopLeft) {
49         m_computedLength = m_length.isUndefined() ? Length(0, Fixed) : m_length;
50         return;
51     }
52     if (m_length.isUndefined()) {
53         m_computedLength = Length(100, Percent);
54         return;
55     }
56
57     auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
58     auto rhs = std::make_unique<CalcExpressionLength>(m_length);
59     auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
60     m_computedLength = Length(CalculationValue::create(WTFMove(op), CalculationRangeAll));
61 }
62
63 bool BasicShapeCircle::operator==(const BasicShape& other) const
64 {
65     if (type() != other.type())
66         return false;
67
68     auto& otherCircle = downcast<BasicShapeCircle>(other);
69     return m_centerX == otherCircle.m_centerX
70         && m_centerY == otherCircle.m_centerY
71         && m_radius == otherCircle.m_radius;
72 }
73
74 float BasicShapeCircle::floatValueForRadiusInBox(float boxWidth, float boxHeight) const
75 {
76     if (m_radius.type() == BasicShapeRadius::Value)
77         return floatValueForLength(m_radius.value(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2));
78
79     float centerX = floatValueForCenterCoordinate(m_centerX, boxWidth);
80     float centerY = floatValueForCenterCoordinate(m_centerY, boxHeight);
81
82     float widthDelta = std::abs(boxWidth - centerX);
83     float heightDelta = std::abs(boxHeight - centerY);
84     if (m_radius.type() == BasicShapeRadius::ClosestSide)
85         return std::min(std::min(std::abs(centerX), widthDelta), std::min(std::abs(centerY), heightDelta));
86
87     // If radius.type() == BasicShapeRadius::FarthestSide.
88     return std::max(std::max(std::abs(centerX), widthDelta), std::max(std::abs(centerY), heightDelta));
89 }
90
91 void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
92 {
93     ASSERT(path.isEmpty());
94
95     float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
96     float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
97     float radius = floatValueForRadiusInBox(boundingBox.width(), boundingBox.height());
98     path.addEllipse(FloatRect(
99         centerX - radius + boundingBox.x(),
100         centerY - radius + boundingBox.y(),
101         radius * 2,
102         radius * 2
103     ));
104 }
105
106 bool BasicShapeCircle::canBlend(const BasicShape& other) const
107 {
108     if (type() != other.type())
109         return false;
110
111     return radius().canBlend(downcast<BasicShapeCircle>(other).radius());
112 }
113
114 Ref<BasicShape> BasicShapeCircle::blend(const BasicShape& other, double progress) const
115 {
116     ASSERT(type() == other.type());
117     auto& otherCircle = downcast<BasicShapeCircle>(other);
118     auto result =  BasicShapeCircle::create();
119
120     result->setCenterX(m_centerX.blend(otherCircle.centerX(), progress));
121     result->setCenterY(m_centerY.blend(otherCircle.centerY(), progress));
122     result->setRadius(m_radius.blend(otherCircle.radius(), progress));
123     return WTFMove(result);
124 }
125
126 bool BasicShapeEllipse::operator==(const BasicShape& other) const
127 {
128     if (type() != other.type())
129         return false;
130
131     auto& otherEllipse = downcast<BasicShapeEllipse>(other);
132     return m_centerX == otherEllipse.m_centerX
133         && m_centerY == otherEllipse.m_centerY
134         && m_radiusX == otherEllipse.m_radiusX
135         && m_radiusY == otherEllipse.m_radiusY;
136 }
137
138 float BasicShapeEllipse::floatValueForRadiusInBox(const BasicShapeRadius& radius, float center, float boxWidthOrHeight) const
139 {
140     if (radius.type() == BasicShapeRadius::Value)
141         return floatValueForLength(radius.value(), std::abs(boxWidthOrHeight));
142
143     float widthOrHeightDelta = std::abs(boxWidthOrHeight - center);
144     if (radius.type() == BasicShapeRadius::ClosestSide)
145         return std::min(std::abs(center), widthOrHeightDelta);
146
147     ASSERT(radius.type() == BasicShapeRadius::FarthestSide);
148     return std::max(std::abs(center), widthOrHeightDelta);
149 }
150
151 void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
152 {
153     ASSERT(path.isEmpty());
154
155     float centerX = floatValueForCenterCoordinate(m_centerX, boundingBox.width());
156     float centerY = floatValueForCenterCoordinate(m_centerY, boundingBox.height());
157     float radiusX = floatValueForRadiusInBox(m_radiusX, centerX, boundingBox.width());
158     float radiusY = floatValueForRadiusInBox(m_radiusY, centerY, boundingBox.height());
159     path.addEllipse(FloatRect(
160         centerX - radiusX + boundingBox.x(),
161         centerY - radiusY + boundingBox.y(),
162         radiusX * 2,
163         radiusY * 2));
164 }
165
166 bool BasicShapeEllipse::canBlend(const BasicShape& other) const
167 {
168     if (type() != other.type())
169         return false;
170
171     auto& otherEllipse = downcast<BasicShapeEllipse>(other);
172     return radiusX().canBlend(otherEllipse.radiusX()) && radiusY().canBlend(otherEllipse.radiusY());
173 }
174
175 Ref<BasicShape> BasicShapeEllipse::blend(const BasicShape& other, double progress) const
176 {
177     ASSERT(type() == other.type());
178     auto& otherEllipse = downcast<BasicShapeEllipse>(other);
179     auto result = BasicShapeEllipse::create();
180
181     if (m_radiusX.type() != BasicShapeRadius::Value || otherEllipse.radiusX().type() != BasicShapeRadius::Value
182         || m_radiusY.type() != BasicShapeRadius::Value || otherEllipse.radiusY().type() != BasicShapeRadius::Value) {
183         result->setCenterX(otherEllipse.centerX());
184         result->setCenterY(otherEllipse.centerY());
185         result->setRadiusX(otherEllipse.radiusX());
186         result->setRadiusY(otherEllipse.radiusY());
187         return WTFMove(result);
188     }
189
190     result->setCenterX(m_centerX.blend(otherEllipse.centerX(), progress));
191     result->setCenterY(m_centerY.blend(otherEllipse.centerY(), progress));
192     result->setRadiusX(m_radiusX.blend(otherEllipse.radiusX(), progress));
193     result->setRadiusY(m_radiusY.blend(otherEllipse.radiusY(), progress));
194     return WTFMove(result);
195 }
196
197 bool BasicShapePolygon::operator==(const BasicShape& other) const
198 {
199     if (type() != other.type())
200         return false;
201
202     auto& otherPolygon = downcast<BasicShapePolygon>(other);
203     return m_windRule == otherPolygon.m_windRule
204         && m_values == otherPolygon.m_values;
205 }
206
207 void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox)
208 {
209     ASSERT(path.isEmpty());
210     ASSERT(!(m_values.size() % 2));
211     size_t length = m_values.size();
212     
213     if (!length)
214         return;
215
216     path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(),
217         floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.y()));
218     for (size_t i = 2; i < length; i = i + 2) {
219         path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(),
220             floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boundingBox.y()));
221     }
222     path.closeSubpath();
223 }
224
225 bool BasicShapePolygon::canBlend(const BasicShape& other) const
226 {
227     if (type() != other.type())
228         return false;
229
230     auto& otherPolygon = downcast<BasicShapePolygon>(other);
231     return values().size() == otherPolygon.values().size() && windRule() == otherPolygon.windRule();
232 }
233
234 Ref<BasicShape> BasicShapePolygon::blend(const BasicShape& other, double progress) const
235 {
236     ASSERT(type() == other.type());
237
238     auto& otherPolygon = downcast<BasicShapePolygon>(other);
239     ASSERT(m_values.size() == otherPolygon.values().size());
240     ASSERT(!(m_values.size() % 2));
241
242     size_t length = m_values.size();
243     auto result = BasicShapePolygon::create();
244     if (!length)
245         return WTFMove(result);
246
247     result->setWindRule(otherPolygon.windRule());
248
249     for (size_t i = 0; i < length; i = i + 2) {
250         result->appendPoint(m_values.at(i).blend(otherPolygon.values().at(i), progress),
251             m_values.at(i + 1).blend(otherPolygon.values().at(i + 1), progress));
252     }
253
254     return WTFMove(result);
255 }
256
257 BasicShapePath::BasicShapePath(std::unique_ptr<SVGPathByteStream>&& byteStream)
258     : m_byteStream(WTFMove(byteStream))
259 {
260 }
261
262 void BasicShapePath::path(Path& path, const FloatRect& boundingBox)
263 {
264     ASSERT(path.isEmpty());
265     buildPathFromByteStream(*m_byteStream, path);
266     path.translate(toFloatSize(boundingBox.location()));
267 }
268
269 bool BasicShapePath::operator==(const BasicShape& other) const
270 {
271     if (type() != other.type())
272         return false;
273
274     auto& otherPath = downcast<BasicShapePath>(other);
275     return m_windRule == otherPath.m_windRule && *m_byteStream == *otherPath.m_byteStream;
276 }
277
278 bool BasicShapePath::canBlend(const BasicShape& other) const
279 {
280     if (type() != other.type())
281         return false;
282
283     auto& otherPath = downcast<BasicShapePath>(other);
284     return windRule() == otherPath.windRule() && canBlendSVGPathByteStreams(*m_byteStream, *otherPath.pathData());
285 }
286
287 Ref<BasicShape> BasicShapePath::blend(const BasicShape& from, double progress) const
288 {
289     ASSERT(type() == from.type());
290
291     auto& fromPath = downcast<BasicShapePath>(from);
292
293     auto resultingPathBytes = std::make_unique<SVGPathByteStream>();
294     buildAnimatedSVGPathByteStream(*fromPath.m_byteStream, *m_byteStream, *resultingPathBytes, progress);
295
296     auto result = BasicShapePath::create(WTFMove(resultingPathBytes));
297     result->setWindRule(windRule());
298     return WTFMove(result);
299 }
300
301 bool BasicShapeInset::operator==(const BasicShape& other) const
302 {
303     if (type() != other.type())
304         return false;
305
306     auto& otherInset = downcast<BasicShapeInset>(other);
307     return m_right == otherInset.m_right
308         && m_top == otherInset.m_top
309         && m_bottom == otherInset.m_bottom
310         && m_left == otherInset.m_left
311         && m_topLeftRadius == otherInset.m_topLeftRadius
312         && m_topRightRadius == otherInset.m_topRightRadius
313         && m_bottomRightRadius == otherInset.m_bottomRightRadius
314         && m_bottomLeftRadius == otherInset.m_bottomLeftRadius;
315 }
316
317 static FloatSize floatSizeForLengthSize(const LengthSize& lengthSize, const FloatRect& boundingBox)
318 {
319     return FloatSize(floatValueForLength(lengthSize.width(), boundingBox.width()),
320         floatValueForLength(lengthSize.height(), boundingBox.height()));
321 }
322
323 void BasicShapeInset::path(Path& path, const FloatRect& boundingBox)
324 {
325     ASSERT(path.isEmpty());
326     float left = floatValueForLength(m_left, boundingBox.width());
327     float top = floatValueForLength(m_top, boundingBox.height());
328     auto rect = FloatRect(left + boundingBox.x(), top + boundingBox.y(),
329         std::max<float>(boundingBox.width() - left - floatValueForLength(m_right, boundingBox.width()), 0),
330         std::max<float>(boundingBox.height() - top - floatValueForLength(m_bottom, boundingBox.height()), 0));
331     auto radii = FloatRoundedRect::Radii(floatSizeForLengthSize(m_topLeftRadius, boundingBox),
332         floatSizeForLengthSize(m_topRightRadius, boundingBox),
333         floatSizeForLengthSize(m_bottomLeftRadius, boundingBox),
334         floatSizeForLengthSize(m_bottomRightRadius, boundingBox));
335     radii.scale(calcBorderRadiiConstraintScaleFor(rect, radii));
336     path.addRoundedRect(FloatRoundedRect(rect, radii));
337 }
338
339 bool BasicShapeInset::canBlend(const BasicShape& other) const
340 {
341     return type() == other.type();
342 }
343
344 Ref<BasicShape> BasicShapeInset::blend(const BasicShape& other, double progress) const
345 {
346     ASSERT(type() == other.type());
347
348     auto& otherInset = downcast<BasicShapeInset>(other);
349     auto result =  BasicShapeInset::create();
350     result->setTop(m_top.blend(otherInset.top(), progress));
351     result->setRight(m_right.blend(otherInset.right(), progress));
352     result->setBottom(m_bottom.blend(otherInset.bottom(), progress));
353     result->setLeft(m_left.blend(otherInset.left(), progress));
354
355     result->setTopLeftRadius(m_topLeftRadius.blend(otherInset.topLeftRadius(), progress));
356     result->setTopRightRadius(m_topRightRadius.blend(otherInset.topRightRadius(), progress));
357     result->setBottomRightRadius(m_bottomRightRadius.blend(otherInset.bottomRightRadius(), progress));
358     result->setBottomLeftRadius(m_bottomLeftRadius.blend(otherInset.bottomLeftRadius(), progress));
359
360     return WTFMove(result);
361 }
362 }