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/css/BasicShapeFunctions.h"
32
33#include "core/css/CSSBasicShapes.h"
34#include "core/css/CSSPrimitiveValueMappings.h"
35#include "core/css/CSSValuePool.h"
36#include "core/css/resolver/StyleResolverState.h"
37#include "core/rendering/style/BasicShapes.h"
38#include "core/rendering/style/RenderStyle.h"
39
40namespace WebCore {
41
42PassRefPtr<CSSValue> valueForBasicShape(const RenderStyle& style, const BasicShape* basicShape)
43{
44    CSSValuePool& pool = cssValuePool();
45
46    RefPtr<CSSBasicShape> basicShapeValue;
47    switch (basicShape->type()) {
48    case BasicShape::BasicShapeRectangleType: {
49        const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
50        RefPtr<CSSBasicShapeRectangle> rectangleValue = CSSBasicShapeRectangle::create();
51
52        rectangleValue->setX(pool.createValue(rectangle->x(), style));
53        rectangleValue->setY(pool.createValue(rectangle->y(), style));
54        rectangleValue->setWidth(pool.createValue(rectangle->width(), style));
55        rectangleValue->setHeight(pool.createValue(rectangle->height(), style));
56        rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX(), style));
57        rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY(), style));
58
59        basicShapeValue = rectangleValue.release();
60        break;
61    }
62    case BasicShape::BasicShapeCircleType: {
63        const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
64        RefPtr<CSSBasicShapeCircle> circleValue = CSSBasicShapeCircle::create();
65
66        circleValue->setCenterX(pool.createValue(circle->centerX(), style));
67        circleValue->setCenterY(pool.createValue(circle->centerY(), style));
68        circleValue->setRadius(pool.createValue(circle->radius(), style));
69
70        basicShapeValue = circleValue.release();
71        break;
72    }
73    case BasicShape::BasicShapeEllipseType: {
74        const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
75        RefPtr<CSSBasicShapeEllipse> ellipseValue = CSSBasicShapeEllipse::create();
76
77        ellipseValue->setCenterX(pool.createValue(ellipse->centerX(), style));
78        ellipseValue->setCenterY(pool.createValue(ellipse->centerY(), style));
79        ellipseValue->setRadiusX(pool.createValue(ellipse->radiusX(), style));
80        ellipseValue->setRadiusY(pool.createValue(ellipse->radiusY(), style));
81
82        basicShapeValue = ellipseValue.release();
83        break;
84    }
85    case BasicShape::BasicShapePolygonType: {
86        const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
87        RefPtr<CSSBasicShapePolygon> polygonValue = CSSBasicShapePolygon::create();
88
89        polygonValue->setWindRule(polygon->windRule());
90        const Vector<Length>& values = polygon->values();
91        for (unsigned i = 0; i < values.size(); i += 2)
92            polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style));
93
94        basicShapeValue = polygonValue.release();
95        break;
96    }
97    case BasicShape::BasicShapeInsetRectangleType: {
98        const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape);
99        RefPtr<CSSBasicShapeInsetRectangle> rectangleValue = CSSBasicShapeInsetRectangle::create();
100
101        rectangleValue->setTop(cssValuePool().createValue(rectangle->top()));
102        rectangleValue->setRight(cssValuePool().createValue(rectangle->right()));
103        rectangleValue->setBottom(cssValuePool().createValue(rectangle->bottom()));
104        rectangleValue->setLeft(cssValuePool().createValue(rectangle->left()));
105        rectangleValue->setRadiusX(cssValuePool().createValue(rectangle->cornerRadiusX()));
106        rectangleValue->setRadiusY(cssValuePool().createValue(rectangle->cornerRadiusY()));
107
108        basicShapeValue = rectangleValue.release();
109        break;
110    }
111    default:
112        break;
113    }
114    return pool.createValue(basicShapeValue.release());
115}
116
117static Length convertToLength(const StyleResolverState& state, CSSPrimitiveValue* value)
118{
119    return value->convertToLength<FixedConversion | PercentConversion>(state.cssToLengthConversionData());
120}
121
122PassRefPtr<BasicShape> basicShapeForValue(const StyleResolverState& state, const CSSBasicShape* basicShapeValue)
123{
124    RefPtr<BasicShape> basicShape;
125
126    switch (basicShapeValue->type()) {
127    case CSSBasicShape::CSSBasicShapeRectangleType: {
128        const CSSBasicShapeRectangle* rectValue = static_cast<const CSSBasicShapeRectangle *>(basicShapeValue);
129        RefPtr<BasicShapeRectangle> rect = BasicShapeRectangle::create();
130
131        rect->setX(convertToLength(state, rectValue->x()));
132        rect->setY(convertToLength(state, rectValue->y()));
133        rect->setWidth(convertToLength(state, rectValue->width()));
134        rect->setHeight(convertToLength(state, rectValue->height()));
135        if (rectValue->radiusX()) {
136            Length radiusX = convertToLength(state, rectValue->radiusX());
137            rect->setCornerRadiusX(radiusX);
138            if (rectValue->radiusY())
139                rect->setCornerRadiusY(convertToLength(state, rectValue->radiusY()));
140            else
141                rect->setCornerRadiusY(radiusX);
142        } else {
143            rect->setCornerRadiusX(Length(0, Fixed));
144            rect->setCornerRadiusY(Length(0, Fixed));
145        }
146        basicShape = rect.release();
147        break;
148    }
149    case CSSBasicShape::CSSBasicShapeCircleType: {
150        const CSSBasicShapeCircle* circleValue = static_cast<const CSSBasicShapeCircle *>(basicShapeValue);
151        RefPtr<BasicShapeCircle> circle = BasicShapeCircle::create();
152
153        circle->setCenterX(convertToLength(state, circleValue->centerX()));
154        circle->setCenterY(convertToLength(state, circleValue->centerY()));
155        circle->setRadius(convertToLength(state, circleValue->radius()));
156
157        basicShape = circle.release();
158        break;
159    }
160    case CSSBasicShape::CSSBasicShapeEllipseType: {
161        const CSSBasicShapeEllipse* ellipseValue = static_cast<const CSSBasicShapeEllipse *>(basicShapeValue);
162        RefPtr<BasicShapeEllipse> ellipse = BasicShapeEllipse::create();
163
164        ellipse->setCenterX(convertToLength(state, ellipseValue->centerX()));
165        ellipse->setCenterY(convertToLength(state, ellipseValue->centerY()));
166        ellipse->setRadiusX(convertToLength(state, ellipseValue->radiusX()));
167        ellipse->setRadiusY(convertToLength(state, ellipseValue->radiusY()));
168
169        basicShape = ellipse.release();
170        break;
171    }
172    case CSSBasicShape::CSSBasicShapePolygonType: {
173        const CSSBasicShapePolygon* polygonValue = static_cast<const CSSBasicShapePolygon *>(basicShapeValue);
174        RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create();
175
176        polygon->setWindRule(polygonValue->windRule());
177        const Vector<RefPtr<CSSPrimitiveValue> >& values = polygonValue->values();
178        for (unsigned i = 0; i < values.size(); i += 2)
179            polygon->appendPoint(convertToLength(state, values.at(i).get()), convertToLength(state, values.at(i + 1).get()));
180
181        basicShape = polygon.release();
182        break;
183    }
184    case CSSBasicShape::CSSBasicShapeInsetRectangleType: {
185        const CSSBasicShapeInsetRectangle* rectValue = static_cast<const CSSBasicShapeInsetRectangle *>(basicShapeValue);
186        RefPtr<BasicShapeInsetRectangle> rect = BasicShapeInsetRectangle::create();
187
188        rect->setTop(convertToLength(state, rectValue->top()));
189        rect->setRight(convertToLength(state, rectValue->right()));
190        rect->setBottom(convertToLength(state, rectValue->bottom()));
191        rect->setLeft(convertToLength(state, rectValue->left()));
192        if (rectValue->radiusX()) {
193            Length radiusX = convertToLength(state, rectValue->radiusX());
194            rect->setCornerRadiusX(radiusX);
195            if (rectValue->radiusY())
196                rect->setCornerRadiusY(convertToLength(state, rectValue->radiusY()));
197            else
198                rect->setCornerRadiusY(radiusX);
199        } else {
200            rect->setCornerRadiusX(Length(0, Fixed));
201            rect->setCornerRadiusY(Length(0, Fixed));
202        }
203        basicShape = rect.release();
204        break;
205    }
206    default:
207        break;
208    }
209    return basicShape.release();
210}
211}
212