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#ifndef BasicShapes_h
31#define BasicShapes_h
32
33#include "core/rendering/style/RenderStyleConstants.h"
34#include "platform/Length.h"
35#include "platform/LengthSize.h"
36#include "platform/graphics/GraphicsTypes.h"
37#include "wtf/RefCounted.h"
38#include "wtf/RefPtr.h"
39#include "wtf/Vector.h"
40
41namespace blink {
42
43class FloatRect;
44class FloatSize;
45class Path;
46
47class BasicShape : public RefCounted<BasicShape> {
48public:
49    virtual ~BasicShape() { }
50
51    enum Type {
52        BasicShapeEllipseType,
53        BasicShapePolygonType,
54        BasicShapeCircleType,
55        BasicShapeInsetType
56    };
57
58    bool canBlend(const BasicShape*) const;
59    bool isSameType(const BasicShape& other) const { return type() == other.type(); }
60
61    virtual void path(Path&, const FloatRect&) = 0;
62    virtual WindRule windRule() const { return RULE_NONZERO; }
63    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const = 0;
64    virtual bool operator==(const BasicShape&) const = 0;
65
66    virtual Type type() const = 0;
67
68protected:
69    BasicShape()
70    {
71    }
72
73};
74
75#define DEFINE_BASICSHAPE_TYPE_CASTS(thisType) \
76    DEFINE_TYPE_CASTS(thisType, BasicShape, value, value->type() == BasicShape::thisType##Type, value.type() == BasicShape::thisType##Type)
77
78class BasicShapeCenterCoordinate {
79public:
80    enum Direction {
81        TopLeft,
82        BottomRight
83    };
84
85    BasicShapeCenterCoordinate(Direction direction = TopLeft, const Length& length = Length(0, Fixed))
86        : m_direction(direction)
87        , m_length(length)
88        , m_computedLength(direction == TopLeft ? length : length.subtractFromOneHundredPercent())
89    {
90    }
91
92    BasicShapeCenterCoordinate(const BasicShapeCenterCoordinate& other)
93        : m_direction(other.direction())
94        , m_length(other.length())
95        , m_computedLength(other.m_computedLength)
96    {
97    }
98
99    bool operator==(const BasicShapeCenterCoordinate& other) const { return m_direction == other.m_direction && m_length == other.m_length && m_computedLength == other.m_computedLength; }
100
101    Direction direction() const { return m_direction; }
102    const Length& length() const { return m_length; }
103    const Length& computedLength() const { return m_computedLength; }
104
105    BasicShapeCenterCoordinate blend(const BasicShapeCenterCoordinate& other, double progress) const
106    {
107        return BasicShapeCenterCoordinate(TopLeft, m_computedLength.blend(other.m_computedLength, progress, ValueRangeAll));
108    }
109
110private:
111    Direction m_direction;
112    Length m_length;
113    Length m_computedLength;
114};
115
116class BasicShapeRadius {
117public:
118    enum Type {
119        Value,
120        ClosestSide,
121        FarthestSide
122    };
123    BasicShapeRadius() : m_type(ClosestSide) { }
124    explicit BasicShapeRadius(const Length& v) : m_value(v), m_type(Value) { }
125    explicit BasicShapeRadius(Type t) : m_type(t) { }
126    BasicShapeRadius(const BasicShapeRadius& other) : m_value(other.value()), m_type(other.type()) { }
127    bool operator==(const BasicShapeRadius& other) const { return m_type == other.m_type && m_value == other.m_value; }
128
129    const Length& value() const { return m_value; }
130    Type type() const { return m_type; }
131
132    bool canBlend(const BasicShapeRadius& other) const
133    {
134        // FIXME determine how to interpolate between keywords. See issue 330248.
135        return m_type == Value && other.type() == Value;
136    }
137
138    BasicShapeRadius blend(const BasicShapeRadius& other, double progress) const
139    {
140        if (m_type != Value || other.type() != Value)
141            return BasicShapeRadius(other);
142
143        return BasicShapeRadius(m_value.blend(other.value(), progress, ValueRangeNonNegative));
144    }
145
146private:
147    Length m_value;
148    Type m_type;
149
150};
151
152class BasicShapeCircle FINAL : public BasicShape {
153public:
154    static PassRefPtr<BasicShapeCircle> create() { return adoptRef(new BasicShapeCircle); }
155
156    const BasicShapeCenterCoordinate& centerX() const { return m_centerX; }
157    const BasicShapeCenterCoordinate& centerY() const { return m_centerY; }
158    const BasicShapeRadius& radius() const { return m_radius; }
159
160    float floatValueForRadiusInBox(FloatSize) const;
161    void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = centerX; }
162    void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = centerY; }
163    void setRadius(BasicShapeRadius radius) { m_radius = radius; }
164
165    virtual void path(Path&, const FloatRect&) OVERRIDE;
166    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
167    virtual bool operator==(const BasicShape&) const OVERRIDE;
168
169    virtual Type type() const OVERRIDE { return BasicShapeCircleType; }
170private:
171    BasicShapeCircle() { }
172
173    BasicShapeCenterCoordinate m_centerX;
174    BasicShapeCenterCoordinate m_centerY;
175    BasicShapeRadius m_radius;
176};
177
178DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeCircle);
179
180class BasicShapeEllipse FINAL : public BasicShape {
181public:
182    static PassRefPtr<BasicShapeEllipse> create() { return adoptRef(new BasicShapeEllipse); }
183
184    const BasicShapeCenterCoordinate& centerX() const { return m_centerX; }
185    const BasicShapeCenterCoordinate& centerY() const { return m_centerY; }
186    const BasicShapeRadius& radiusX() const { return m_radiusX; }
187    const BasicShapeRadius& radiusY() const { return m_radiusY; }
188    float floatValueForRadiusInBox(const BasicShapeRadius&, float center, float boxWidthOrHeight) const;
189
190    void setCenterX(BasicShapeCenterCoordinate centerX) { m_centerX = centerX; }
191    void setCenterY(BasicShapeCenterCoordinate centerY) { m_centerY = centerY; }
192    void setRadiusX(BasicShapeRadius radiusX) { m_radiusX = radiusX; }
193    void setRadiusY(BasicShapeRadius radiusY) { m_radiusY = radiusY; }
194
195    virtual void path(Path&, const FloatRect&) OVERRIDE;
196    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
197    virtual bool operator==(const BasicShape&) const OVERRIDE;
198
199    virtual Type type() const OVERRIDE { return BasicShapeEllipseType; }
200private:
201    BasicShapeEllipse() { }
202
203    BasicShapeCenterCoordinate m_centerX;
204    BasicShapeCenterCoordinate m_centerY;
205    BasicShapeRadius m_radiusX;
206    BasicShapeRadius m_radiusY;
207};
208
209DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeEllipse);
210
211class BasicShapePolygon FINAL : public BasicShape {
212public:
213    static PassRefPtr<BasicShapePolygon> create() { return adoptRef(new BasicShapePolygon); }
214
215    const Vector<Length>& values() const { return m_values; }
216    Length getXAt(unsigned i) const { return m_values.at(2 * i); }
217    Length getYAt(unsigned i) const { return m_values.at(2 * i + 1); }
218
219    void setWindRule(WindRule windRule) { m_windRule = windRule; }
220    void appendPoint(const Length& x, const Length& y) { m_values.append(x); m_values.append(y); }
221
222    virtual void path(Path&, const FloatRect&) OVERRIDE;
223    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
224    virtual bool operator==(const BasicShape&) const OVERRIDE;
225
226    virtual WindRule windRule() const OVERRIDE { return m_windRule; }
227
228    virtual Type type() const OVERRIDE { return BasicShapePolygonType; }
229private:
230    BasicShapePolygon()
231        : m_windRule(RULE_NONZERO)
232    { }
233
234    WindRule m_windRule;
235    Vector<Length> m_values;
236};
237
238DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapePolygon);
239
240class BasicShapeInset : public BasicShape {
241public:
242    static PassRefPtr<BasicShapeInset> create() { return adoptRef(new BasicShapeInset); }
243
244    const Length& top() const { return m_top; }
245    const Length& right() const { return m_right; }
246    const Length& bottom() const { return m_bottom; }
247    const Length& left() const { return m_left; }
248
249    const LengthSize& topLeftRadius() const { return m_topLeftRadius; }
250    const LengthSize& topRightRadius() const { return m_topRightRadius; }
251    const LengthSize& bottomRightRadius() const { return m_bottomRightRadius; }
252    const LengthSize& bottomLeftRadius() const { return m_bottomLeftRadius; }
253
254    void setTop(const Length& top) { m_top = top; }
255    void setRight(const Length& right) { m_right = right; }
256    void setBottom(const Length& bottom) { m_bottom = bottom; }
257    void setLeft(const Length& left) { m_left = left; }
258
259    void setTopLeftRadius(const LengthSize& radius) { m_topLeftRadius = radius; }
260    void setTopRightRadius(const LengthSize& radius) { m_topRightRadius = radius; }
261    void setBottomRightRadius(const LengthSize& radius) { m_bottomRightRadius = radius; }
262    void setBottomLeftRadius(const LengthSize& radius) { m_bottomLeftRadius = radius; }
263
264    virtual void path(Path&, const FloatRect&) OVERRIDE;
265    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
266    virtual bool operator==(const BasicShape&) const OVERRIDE;
267
268    virtual Type type() const OVERRIDE { return BasicShapeInsetType; }
269private:
270    BasicShapeInset() { }
271
272    Length m_right;
273    Length m_top;
274    Length m_bottom;
275    Length m_left;
276
277    LengthSize m_topLeftRadius;
278    LengthSize m_topRightRadius;
279    LengthSize m_bottomRightRadius;
280    LengthSize m_bottomLeftRadius;
281};
282
283DEFINE_BASICSHAPE_TYPE_CASTS(BasicShapeInset);
284
285}
286#endif
287