OLD | NEW |
| (Empty) |
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 #include "core/layout/style/BasicShapes.h" | |
32 | |
33 #include "core/css/BasicShapeFunctions.h" | |
34 #include "core/layout/style/ComputedStyle.h" | |
35 #include "platform/CalculationValue.h" | |
36 #include "platform/LengthFunctions.h" | |
37 #include "platform/geometry/FloatRect.h" | |
38 #include "platform/graphics/Path.h" | |
39 | |
40 namespace blink { | |
41 | |
42 bool BasicShape::canBlend(const BasicShape* other) const | |
43 { | |
44 // FIXME: Support animations between different shapes in the future. | |
45 if (!other || !isSameType(*other)) | |
46 return false; | |
47 | |
48 // Just polygons with same number of vertices can be animated. | |
49 if (type() == BasicShape::BasicShapePolygonType | |
50 && (toBasicShapePolygon(this)->values().size() != toBasicShapePolygon(ot
her)->values().size() | |
51 || toBasicShapePolygon(this)->windRule() != toBasicShapePolygon(other)->
windRule())) | |
52 return false; | |
53 | |
54 // Circles with keywords for radii or center coordinates cannot be animated. | |
55 if (type() == BasicShape::BasicShapeCircleType) { | |
56 if (!toBasicShapeCircle(this)->radius().canBlend(toBasicShapeCircle(othe
r)->radius())) | |
57 return false; | |
58 } | |
59 | |
60 // Ellipses with keywords for radii or center coordinates cannot be animated
. | |
61 if (type() != BasicShape::BasicShapeEllipseType) | |
62 return true; | |
63 | |
64 return (toBasicShapeEllipse(this)->radiusX().canBlend(toBasicShapeEllipse(ot
her)->radiusX()) | |
65 && toBasicShapeEllipse(this)->radiusY().canBlend(toBasicShapeEllipse(oth
er)->radiusY())); | |
66 } | |
67 | |
68 bool BasicShapeCircle::operator==(const BasicShape& o) const | |
69 { | |
70 if (!isSameType(o)) | |
71 return false; | |
72 const BasicShapeCircle& other = toBasicShapeCircle(o); | |
73 return m_centerX == other.m_centerX && m_centerY == other.m_centerY && m_rad
ius == other.m_radius; | |
74 } | |
75 | |
76 float BasicShapeCircle::floatValueForRadiusInBox(FloatSize boxSize) const | |
77 { | |
78 if (m_radius.type() == BasicShapeRadius::Value) | |
79 return floatValueForLength(m_radius.value(), hypotf(boxSize.width(), box
Size.height()) / sqrtf(2)); | |
80 | |
81 FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boxS
ize); | |
82 | |
83 float widthDelta = std::abs(boxSize.width() - center.x()); | |
84 float heightDelta = std::abs(boxSize.height() - center.y()); | |
85 if (m_radius.type() == BasicShapeRadius::ClosestSide) | |
86 return std::min(std::min(std::abs(center.x()), widthDelta), std::min(std
::abs(center.y()), heightDelta)); | |
87 | |
88 // If radius.type() == BasicShapeRadius::FarthestSide. | |
89 return std::max(std::max(center.x(), widthDelta), std::max(center.y(), heigh
tDelta)); | |
90 } | |
91 | |
92 void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) | |
93 { | |
94 ASSERT(path.isEmpty()); | |
95 FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boun
dingBox.size()); | |
96 float radius = floatValueForRadiusInBox(boundingBox.size()); | |
97 path.addEllipse(FloatRect( | |
98 center.x() - radius + boundingBox.x(), | |
99 center.y() - radius + boundingBox.y(), | |
100 radius * 2, | |
101 radius * 2 | |
102 )); | |
103 } | |
104 | |
105 PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double p
rogress) const | |
106 { | |
107 ASSERT(type() == other->type()); | |
108 const BasicShapeCircle* o = toBasicShapeCircle(other); | |
109 RefPtr<BasicShapeCircle> result = BasicShapeCircle::create(); | |
110 | |
111 result->setCenterX(m_centerX.blend(o->centerX(), progress)); | |
112 result->setCenterY(m_centerY.blend(o->centerY(), progress)); | |
113 result->setRadius(m_radius.blend(o->radius(), progress)); | |
114 return result.release(); | |
115 } | |
116 | |
117 bool BasicShapeEllipse::operator==(const BasicShape& o) const | |
118 { | |
119 if (!isSameType(o)) | |
120 return false; | |
121 const BasicShapeEllipse& other = toBasicShapeEllipse(o); | |
122 return m_centerX == other.m_centerX && m_centerY == other.m_centerY && m_rad
iusX == other.m_radiusX && m_radiusY == other.m_radiusY; | |
123 } | |
124 | |
125 float BasicShapeEllipse::floatValueForRadiusInBox(const BasicShapeRadius& radius
, float center, float boxWidthOrHeight) const | |
126 { | |
127 if (radius.type() == BasicShapeRadius::Value) | |
128 return floatValueForLength(radius.value(), boxWidthOrHeight); | |
129 | |
130 float widthOrHeightDelta = std::abs(boxWidthOrHeight - center); | |
131 if (radius.type() == BasicShapeRadius::ClosestSide) | |
132 return std::min(std::abs(center), widthOrHeightDelta); | |
133 | |
134 ASSERT(radius.type() == BasicShapeRadius::FarthestSide); | |
135 return std::max(center, widthOrHeightDelta); | |
136 } | |
137 | |
138 void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) | |
139 { | |
140 ASSERT(path.isEmpty()); | |
141 FloatPoint center = floatPointForCenterCoordinate(m_centerX, m_centerY, boun
dingBox.size()); | |
142 float radiusX = floatValueForRadiusInBox(m_radiusX, center.x(), boundingBox.
width()); | |
143 float radiusY = floatValueForRadiusInBox(m_radiusY, center.y(), boundingBox.
height()); | |
144 path.addEllipse(FloatRect( | |
145 center.x() - radiusX + boundingBox.x(), | |
146 center.y() - radiusY + boundingBox.y(), | |
147 radiusX * 2, | |
148 radiusY * 2 | |
149 )); | |
150 } | |
151 | |
152 PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double
progress) const | |
153 { | |
154 ASSERT(type() == other->type()); | |
155 const BasicShapeEllipse* o = toBasicShapeEllipse(other); | |
156 RefPtr<BasicShapeEllipse> result = BasicShapeEllipse::create(); | |
157 | |
158 if (m_radiusX.type() != BasicShapeRadius::Value || o->radiusX().type() != Ba
sicShapeRadius::Value | |
159 || m_radiusY.type() != BasicShapeRadius::Value || o->radiusY().type() !=
BasicShapeRadius::Value) { | |
160 result->setCenterX(o->centerX()); | |
161 result->setCenterY(o->centerY()); | |
162 result->setRadiusX(o->radiusX()); | |
163 result->setRadiusY(o->radiusY()); | |
164 return result; | |
165 } | |
166 | |
167 result->setCenterX(m_centerX.blend(o->centerX(), progress)); | |
168 result->setCenterY(m_centerY.blend(o->centerY(), progress)); | |
169 result->setRadiusX(m_radiusX.blend(o->radiusX(), progress)); | |
170 result->setRadiusY(m_radiusY.blend(o->radiusY(), progress)); | |
171 return result.release(); | |
172 } | |
173 | |
174 void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) | |
175 { | |
176 ASSERT(path.isEmpty()); | |
177 ASSERT(!(m_values.size() % 2)); | |
178 size_t length = m_values.size(); | |
179 | |
180 if (!length) | |
181 return; | |
182 | |
183 path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width
()) + boundingBox.x(), | |
184 floatValueForLength(m_values.at(1), boundingBox.height()) + boundingBox.
y())); | |
185 for (size_t i = 2; i < length; i = i + 2) { | |
186 path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBo
x.width()) + boundingBox.x(), | |
187 floatValueForLength(m_values.at(i + 1), boundingBox.height()) + boun
dingBox.y())); | |
188 } | |
189 path.closeSubpath(); | |
190 } | |
191 | |
192 PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double
progress) const | |
193 { | |
194 ASSERT(other && isSameType(*other)); | |
195 | |
196 const BasicShapePolygon* o = toBasicShapePolygon(other); | |
197 ASSERT(m_values.size() == o->values().size()); | |
198 ASSERT(!(m_values.size() % 2)); | |
199 | |
200 size_t length = m_values.size(); | |
201 RefPtr<BasicShapePolygon> result = BasicShapePolygon::create(); | |
202 if (!length) | |
203 return result.release(); | |
204 | |
205 result->setWindRule(o->windRule()); | |
206 | |
207 for (size_t i = 0; i < length; i = i + 2) { | |
208 result->appendPoint(m_values.at(i).blend(o->values().at(i), progress, Va
lueRangeAll), | |
209 m_values.at(i + 1).blend(o->values().at(i + 1), progress, ValueRange
All)); | |
210 } | |
211 | |
212 return result.release(); | |
213 } | |
214 | |
215 bool BasicShapePolygon::operator==(const BasicShape& o) const | |
216 { | |
217 if (!isSameType(o)) | |
218 return false; | |
219 const BasicShapePolygon& other = toBasicShapePolygon(o); | |
220 return m_windRule == other.m_windRule && m_values == other.m_values; | |
221 } | |
222 | |
223 static FloatSize floatSizeForLengthSize(const LengthSize& lengthSize, const Floa
tRect& boundingBox) | |
224 { | |
225 return FloatSize(floatValueForLength(lengthSize.width(), boundingBox.width()
), | |
226 floatValueForLength(lengthSize.height(), boundingBox.height())); | |
227 } | |
228 | |
229 void BasicShapeInset::path(Path& path, const FloatRect& boundingBox) | |
230 { | |
231 ASSERT(path.isEmpty()); | |
232 float left = floatValueForLength(m_left, boundingBox.width()); | |
233 float top = floatValueForLength(m_top, boundingBox.height()); | |
234 FloatRect rect(left + boundingBox.x(), top + boundingBox.y(), | |
235 std::max<float>(boundingBox.width() - left - floatValueForLength(m_right
, boundingBox.width()), 0), | |
236 std::max<float>(boundingBox.height() - top - floatValueForLength(m_botto
m, boundingBox.height()), 0)); | |
237 auto radii = FloatRoundedRect::Radii(floatSizeForLengthSize(m_topLeftRadius,
boundingBox), | |
238 floatSizeForLengthSize(m_topRightRadius, boundingBox), | |
239 floatSizeForLengthSize(m_bottomLeftRadius, boundingBox), | |
240 floatSizeForLengthSize(m_bottomRightRadius, boundingBox)); | |
241 | |
242 FloatRoundedRect finalRect(rect, radii); | |
243 finalRect.constrainRadii(); | |
244 path.addRoundedRect(finalRect); | |
245 } | |
246 | |
247 static inline LengthSize blendLengthSize(const LengthSize& to, const LengthSize&
from, double progress) | |
248 { | |
249 return LengthSize(to.width().blend(from.width(), progress, ValueRangeAll), | |
250 to.height().blend(from.height(), progress, ValueRangeAll)); | |
251 } | |
252 | |
253 PassRefPtr<BasicShape> BasicShapeInset::blend(const BasicShape* other, double pr
ogress) const | |
254 { | |
255 ASSERT(other && isSameType(*other)); | |
256 | |
257 const BasicShapeInset& otherInset = toBasicShapeInset(*other); | |
258 RefPtr<BasicShapeInset> result = BasicShapeInset::create(); | |
259 result->setTop(m_top.blend(otherInset.top(), progress, ValueRangeAll)); | |
260 result->setRight(m_right.blend(otherInset.right(), progress, ValueRangeAll))
; | |
261 result->setBottom(m_bottom.blend(otherInset.bottom(), progress, ValueRangeAl
l)); | |
262 result->setLeft(m_left.blend(otherInset.left(), progress, ValueRangeAll)); | |
263 | |
264 result->setTopLeftRadius(blendLengthSize(m_topLeftRadius, otherInset.topLeft
Radius(), progress)); | |
265 result->setTopRightRadius(blendLengthSize(m_topRightRadius, otherInset.topRi
ghtRadius(), progress)); | |
266 result->setBottomRightRadius(blendLengthSize(m_bottomRightRadius, otherInset
.bottomRightRadius(), progress)); | |
267 result->setBottomLeftRadius(blendLengthSize(m_bottomLeftRadius, otherInset.b
ottomLeftRadius(), progress)); | |
268 | |
269 return result.release(); | |
270 } | |
271 | |
272 bool BasicShapeInset::operator==(const BasicShape& o) const | |
273 { | |
274 if (!isSameType(o)) | |
275 return false; | |
276 const BasicShapeInset& other = toBasicShapeInset(o); | |
277 return m_right == other.m_right | |
278 && m_top == other.m_top | |
279 && m_bottom == other.m_bottom | |
280 && m_left == other.m_left | |
281 && m_topLeftRadius == other.m_topLeftRadius | |
282 && m_topRightRadius == other.m_topRightRadius | |
283 && m_bottomRightRadius == other.m_bottomRightRadius | |
284 && m_bottomLeftRadius == other.m_bottomLeftRadius; | |
285 } | |
286 | |
287 } | |
OLD | NEW |