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
40namespace WebCore {
41
42class FloatRect;
43class Path;
44class RenderBox;
45class SVGPathByteStream;
46
47class BasicShape : public RefCounted<BasicShape> {
48public:
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
70class BasicShapeCenterCoordinate {
71public:
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
107private:
108 void updateComputedLength();
109
110 Direction m_direction;
111 Length m_length;
112 Length m_computedLength;
113};
114
115class BasicShapeRadius {
116public:
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
158private:
159 Length m_value;
160 Type m_type;
161
162};
163
164class BasicShapeCircle final : public BasicShape {
165public:
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
177private:
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
194class BasicShapeEllipse final : public BasicShape {
195public:
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
209private:
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
227class BasicShapePolygon final : public BasicShape {
228public:
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
240private:
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
256class BasicShapePath final : public BasicShape {
257public:
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
268private:
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
284class BasicShapeInset final : public BasicShape {
285public:
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
308private:
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) \
334SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \
335 static bool isType(const WebCore::BasicShape& basicShape) { return basicShape.type() == WebCore::predicate; } \
336SPECIALIZE_TYPE_TRAITS_END()
337
338SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeCircle, BasicShape::BasicShapeCircleType)
339SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeEllipse, BasicShape::BasicShapeEllipseType)
340SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePolygon, BasicShape::BasicShapePolygonType)
341SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapePath, BasicShape::BasicShapePathType)
342SPECIALIZE_TYPE_TRAITS_BASIC_SHAPE(BasicShapeInset, BasicShape::BasicShapeInsetType)
343