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