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 | #pragma once |
31 | |
32 | #include "Length.h" |
33 | #include "LengthSize.h" |
34 | #include "WindRule.h" |
35 | #include <wtf/RefCounted.h> |
36 | #include <wtf/RefPtr.h> |
37 | #include <wtf/TypeCasts.h> |
38 | #include <wtf/Vector.h> |
39 | |
40 | namespace WebCore { |
41 | |
42 | class FloatRect; |
43 | class Path; |
44 | class RenderBox; |
45 | class SVGPathByteStream; |
46 | |
47 | class BasicShape : public RefCounted<BasicShape> { |
48 | public: |
49 | virtual ~BasicShape() = default; |
50 | |
51 | enum Type { |
52 | BasicShapePolygonType, |
53 | BasicShapePathType, |
54 | BasicShapeCircleType, |
55 | BasicShapeEllipseType, |
56 | BasicShapeInsetType |
57 | }; |
58 | |
59 | virtual Type type() const = 0; |
60 | |
61 | virtual const Path& path(const FloatRect&) = 0; |
62 | virtual WindRule windRule() const { return WindRule::NonZero; } |
63 | |
64 | virtual bool canBlend(const BasicShape&) const = 0; |
65 | virtual Ref<BasicShape> blend(const BasicShape& from, double) const = 0; |
66 | |
67 | virtual bool operator==(const BasicShape&) const = 0; |
68 | }; |
69 | |
70 | class BasicShapeCenterCoordinate { |
71 | public: |
72 | enum Direction { |
73 | TopLeft, |
74 | BottomRight |
75 | }; |
76 | |
77 | BasicShapeCenterCoordinate() |
78 | : m_direction(TopLeft) |
79 | , m_length(Undefined) |
80 | { |
81 | updateComputedLength(); |
82 | } |
83 | |
84 | BasicShapeCenterCoordinate(Direction direction, Length length) |
85 | : m_direction(direction) |
86 | , m_length(length) |
87 | { |
88 | updateComputedLength(); |
89 | } |
90 | |
91 | Direction direction() const { return m_direction; } |
92 | const Length& length() const { return m_length; } |
93 | const Length& computedLength() const { return m_computedLength; } |
94 | |
95 | BasicShapeCenterCoordinate blend(const BasicShapeCenterCoordinate& from, double progress) const |
96 | { |
97 | return BasicShapeCenterCoordinate(TopLeft, WebCore::blend(from.m_computedLength, m_computedLength, progress)); |
98 | } |
99 | |
100 | bool operator==(const BasicShapeCenterCoordinate& other) const |
101 | { |
102 | return m_direction == other.m_direction |
103 | && m_length == other.m_length |
104 | && m_computedLength == other.m_computedLength; |
105 | } |
106 | |
107 | private: |
108 | void updateComputedLength(); |
109 | |
110 | Direction m_direction; |
111 | Length m_length; |
112 | Length m_computedLength; |
113 | }; |
114 | |
115 | class BasicShapeRadius { |
116 | public: |
117 | enum Type { |
118 | Value, |
119 | ClosestSide, |
120 | FarthestSide |
121 | }; |
122 | BasicShapeRadius() |
123 | : m_value(Undefined), |
124 | m_type(ClosestSide) |
125 | { } |
126 | |
127 | explicit BasicShapeRadius(Length v) |
128 | : m_value(v) |
129 | , m_type(Value) |
130 | { } |
131 | explicit BasicShapeRadius(Type t) |
132 | : m_value(Undefined) |
133 | , m_type(t) |
134 | { } |
135 | |
136 | const Length& value() const { return m_value; } |
137 | Type type() const { return m_type; } |
138 | |
139 | bool canBlend(const BasicShapeRadius& other) const |
140 | { |
141 | // FIXME determine how to interpolate between keywords. See bug 125108. |
142 | return m_type == Value && other.type() == Value; |
143 | } |
144 | |
145 | BasicShapeRadius blend(const BasicShapeRadius& from, double progress) const |
146 | { |
147 | if (m_type != Value || from.type() != Value) |
148 | return BasicShapeRadius(from); |
149 | |
150 | return BasicShapeRadius(WebCore::blend(from.value(), value(), progress)); |
151 | } |
152 | |
153 | bool operator==(const BasicShapeRadius& other) const |
154 | { |
155 | return m_value == other.m_value && m_type == other.m_type; |
156 | } |
157 | |
158 | private: |
159 | Length m_value; |
160 | Type m_type; |
161 | |
162 | }; |
163 | |
164 | class BasicShapeCircle final : public BasicShape { |
165 | public: |
166 | static Ref<BasicShapeCircle> create() { return adoptRef(*new BasicShapeCircle); } |
167 | |
168 | const BasicShapeCenterCoordinate& centerX() const { return m_centerX; } |
169 | const BasicShapeCenterCoordinate& centerY() const { return m_centerY; } |
170 | const BasicShapeRadius& radius() const { return m_radius; } |
171 | float floatValueForRadiusInBox(float boxWidth, float boxHeight) const; |
172 | |
173 | void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = WTFMove(centerX); } |
174 | void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = WTFMove(centerY); } |
175 | void setRadius(BasicShapeRadius radius) { m_radius = WTFMove(radius); } |
176 | |
177 | private: |
178 | BasicShapeCircle() = default; |
179 | |
180 | Type type() const override { return BasicShapeCircleType; } |
181 | |
182 | const Path& path(const FloatRect&) override; |
183 | |
184 | bool canBlend(const BasicShape&) const override; |
185 | Ref<BasicShape> blend(const BasicShape& from, double) const override; |
186 | |
187 | bool operator==(const BasicShape&) const override; |
188 | |
189 | BasicShapeCenterCoordinate m_centerX; |
190 | BasicShapeCenterCoordinate m_centerY; |
191 | BasicShapeRadius m_radius; |
192 | }; |
193 | |
194 | class BasicShapeEllipse final : public BasicShape { |
195 | public: |
196 | static Ref<BasicShapeEllipse> create() { return adoptRef(*new BasicShapeEllipse); } |
197 | |
198 | const BasicShapeCenterCoordinate& centerX() const { return m_centerX; } |
199 | const BasicShapeCenterCoordinate& centerY() const { return m_centerY; } |
200 | const BasicShapeRadius& radiusX() const { return m_radiusX; } |
201 | const BasicShapeRadius& radiusY() const { return m_radiusY; } |
202 | float floatValueForRadiusInBox(const BasicShapeRadius&, float center, float boxWidthOrHeight) const; |
203 | |
204 | void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = WTFMove(centerX); } |
205 | void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = WTFMove(centerY); } |
206 | void setRadiusX(BasicShapeRadius radiusX) { m_radiusX = WTFMove(radiusX); } |
207 | void setRadiusY(BasicShapeRadius radiusY) { m_radiusY = WTFMove(radiusY); } |
208 | |
209 | private: |
210 | BasicShapeEllipse() = default; |
211 | |
212 | Type type() const override { return BasicShapeEllipseType; } |
213 | |
214 | const Path& path(const FloatRect&) override; |
215 | |
216 | bool canBlend(const BasicShape&) const override; |
217 | Ref<BasicShape> blend(const BasicShape& from, double) const override; |
218 | |
219 | bool operator==(const BasicShape&) const override; |
220 | |
221 | BasicShapeCenterCoordinate m_centerX; |
222 | BasicShapeCenterCoordinate m_centerY; |
223 | BasicShapeRadius m_radiusX; |
224 | BasicShapeRadius m_radiusY; |
225 | }; |
226 | |
227 | class BasicShapePolygon final : public BasicShape { |
228 | public: |
229 | static Ref<BasicShapePolygon> create() { return adoptRef(*new BasicShapePolygon); } |
230 | |
231 | const Vector<Length>& values() const { return m_values; } |
232 | const Length& getXAt(unsigned i) const { return m_values[2 * i]; } |
233 | const Length& getYAt(unsigned i) const { return m_values[2 * i + 1]; } |
234 | |
235 | void setWindRule(WindRule windRule) { m_windRule = windRule; } |
236 | void appendPoint(Length x, Length y) { m_values.append(WTFMove(x)); m_values.append(WTFMove(y)); } |
237 | |
238 | WindRule windRule() const override { return m_windRule; } |
239 | |
240 | private: |
241 | BasicShapePolygon() = default; |
242 | |
243 | Type type() const override { return BasicShapePolygonType; } |
244 | |
245 | const Path& path(const FloatRect&) override; |
246 | |
247 | bool canBlend(const BasicShape&) const override; |
248 | Ref<BasicShape> blend(const BasicShape& from, double) const override; |
249 | |
250 | bool operator==(const BasicShape&) const override; |
251 | |
252 | WindRule m_windRule { WindRule::NonZero }; |
253 | Vector<Length> m_values; |
254 | }; |
255 | |
256 | class BasicShapePath final : public BasicShape { |
257 | public: |
258 | static Ref<BasicShapePath> create(std::unique_ptr<SVGPathByteStream>&& byteStream) |
259 | { |
260 | return adoptRef(*new BasicShapePath(WTFMove(byteStream))); |
261 | } |
262 | |
263 | void setWindRule(WindRule windRule) { m_windRule = windRule; } |
264 | WindRule windRule() const override { return m_windRule; } |
265 | |
266 | const SVGPathByteStream* pathData() const { return m_byteStream.get(); } |
267 | |
268 | private: |
269 | BasicShapePath(std::unique_ptr<SVGPathByteStream>&&); |
270 | |
271 | Type type() const override { return BasicShapePathType; } |
272 | |
273 | const Path& path(const FloatRect&) override; |
274 | |
275 | bool canBlend(const BasicShape&) const override; |
276 | Ref<BasicShape> blend(const BasicShape& from, double) const override; |
277 | |
278 | bool operator==(const BasicShape&) const override; |
279 | |
280 | std::unique_ptr<SVGPathByteStream> m_byteStream; |
281 | WindRule m_windRule { WindRule::NonZero }; |
282 | }; |
283 | |
284 | class BasicShapeInset final : public BasicShape { |
285 | public: |
286 | static Ref<BasicShapeInset> create() { return adoptRef(*new BasicShapeInset); } |
287 | |
288 | const Length& top() const { return m_top; } |
289 | const Length& right() const { return m_right; } |
290 | const Length& bottom() const { return m_bottom; } |
291 | const Length& left() const { return m_left; } |
292 | |
293 | const LengthSize& topLeftRadius() const { return m_topLeftRadius; } |
294 | const LengthSize& topRightRadius() const { return m_topRightRadius; } |
295 | const LengthSize& bottomRightRadius() const { return m_bottomRightRadius; } |
296 | const LengthSize& bottomLeftRadius() const { return m_bottomLeftRadius; } |
297 | |
298 | void setTop(Length top) { m_top = WTFMove(top); } |
299 | void setRight(Length right) { m_right = WTFMove(right); } |
300 | void setBottom(Length bottom) { m_bottom = WTFMove(bottom); } |
301 | void setLeft(Length left) { m_left = WTFMove(left); } |
302 | |
303 | void setTopLeftRadius(LengthSize radius) { m_topLeftRadius = WTFMove(radius); } |
304 | void setTopRightRadius(LengthSize radius) { m_topRightRadius = WTFMove(radius); } |
305 | void setBottomRightRadius(LengthSize radius) { m_bottomRightRadius = WTFMove(radius); } |
306 | void setBottomLeftRadius(LengthSize radius) { m_bottomLeftRadius = WTFMove(radius); } |
307 | |
308 | private: |
309 | BasicShapeInset() = default; |
310 | |
311 | Type type() const override { return BasicShapeInsetType; } |
312 | |
313 | const Path& path(const FloatRect&) override; |
314 | |
315 | bool canBlend(const BasicShape&) const override; |
316 | Ref<BasicShape> blend(const BasicShape& from, double) const override; |
317 | |
318 | bool operator==(const BasicShape&) const override; |
319 | |
320 | Length m_right; |
321 | Length m_top; |
322 | Length m_bottom; |
323 | Length m_left; |
324 | |
325 | LengthSize m_topLeftRadius; |
326 | LengthSize m_topRightRadius; |
327 | LengthSize m_bottomRightRadius; |
328 | LengthSize m_bottomLeftRadius; |
329 | }; |
330 | |
331 | } // namespace WebCore |
332 | |
333 | #define SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(ToValueTypeName, predicate) \ |
334 | SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ |
335 | static bool isType(const WebCore::BasicShape& basicShape) { return basicShape.type() == WebCore::predicate; } \ |
336 | SPECIALIZE_TYPE_TRAITS_END() |
337 | |
338 | SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeCircle, BasicShape::BasicShapeCircleType) |
339 | SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeEllipse, BasicShape::BasicShapeEllipseType) |
340 | SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePolygon, BasicShape::BasicShapePolygonType) |
341 | SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePath, BasicShape::BasicShapePathType) |
342 | SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeInset, BasicShape::BasicShapeInsetType) |
343 | |