[CSS Shapes] complex calc args for inset round vanish
[WebKit-https.git] / Source / WebCore / css / BasicShapeFunctions.cpp
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 "Pair.h"
38 #include "RenderStyle.h"
39
40 namespace WebCore {
41
42 static PassRefPtr<CSSPrimitiveValue> valueForCenterCoordinate(CSSValuePool& pool, const RenderStyle* style, const BasicShapeCenterCoordinate& center, EBoxOrient orientation)
43 {
44     if (center.direction() == BasicShapeCenterCoordinate::TopLeft)
45         return pool.createValue(center.length(), style);
46
47     CSSValueID keyword = orientation == HORIZONTAL ? CSSValueRight : CSSValueBottom;
48
49     return pool.createValue(Pair::create(pool.createIdentifierValue(keyword), pool.createValue(center.length(), style)));
50 }
51
52 static PassRefPtr<CSSPrimitiveValue> basicShapeRadiusToCSSValue(const RenderStyle* style, CSSValuePool& pool, const BasicShapeRadius& radius)
53 {
54     switch (radius.type()) {
55     case BasicShapeRadius::Value:
56         return pool.createValue(radius.value(), style);
57     case BasicShapeRadius::ClosestSide:
58         return pool.createIdentifierValue(CSSValueClosestSide);
59     case BasicShapeRadius::FarthestSide:
60         return pool.createIdentifierValue(CSSValueFarthestSide);
61     }
62
63     ASSERT_NOT_REACHED();
64     return 0;
65 }
66
67 PassRefPtr<CSSValue> valueForBasicShape(const RenderStyle* style, const BasicShape* basicShape)
68 {
69     CSSValuePool& pool = cssValuePool();
70
71     RefPtr<CSSBasicShape> basicShapeValue;
72     switch (basicShape->type()) {
73     case BasicShape::BasicShapeCircleType: {
74         const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
75         RefPtr<CSSBasicShapeCircle> circleValue = CSSBasicShapeCircle::create();
76
77         circleValue->setCenterX(valueForCenterCoordinate(pool, style, circle->centerX(), HORIZONTAL));
78         circleValue->setCenterY(valueForCenterCoordinate(pool, style, circle->centerY(), VERTICAL));
79         circleValue->setRadius(basicShapeRadiusToCSSValue(style, pool, circle->radius()));
80         basicShapeValue = circleValue.release();
81         break;
82     }
83     case BasicShape::BasicShapeEllipseType: {
84         const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
85         RefPtr<CSSBasicShapeEllipse> ellipseValue = CSSBasicShapeEllipse::create();
86
87         ellipseValue->setCenterX(valueForCenterCoordinate(pool, style, ellipse->centerX(), HORIZONTAL));
88         ellipseValue->setCenterY(valueForCenterCoordinate(pool, style, ellipse->centerY(), VERTICAL));
89         ellipseValue->setRadiusX(basicShapeRadiusToCSSValue(style, pool, ellipse->radiusX()));
90         ellipseValue->setRadiusY(basicShapeRadiusToCSSValue(style, pool, ellipse->radiusY()));
91         basicShapeValue = ellipseValue.release();
92         break;
93     }
94     case BasicShape::BasicShapePolygonType: {
95         const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape);
96         RefPtr<CSSBasicShapePolygon> polygonValue = CSSBasicShapePolygon::create();
97
98         polygonValue->setWindRule(polygon->windRule());
99         const Vector<Length>& values = polygon->values();
100         for (unsigned i = 0; i < values.size(); i += 2)
101             polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style));
102
103         basicShapeValue = polygonValue.release();
104         break;
105     }
106     case BasicShape::BasicShapeInsetType: {
107         const BasicShapeInset* inset = static_cast<const BasicShapeInset*>(basicShape);
108         RefPtr<CSSBasicShapeInset> insetValue = CSSBasicShapeInset::create();
109
110         insetValue->setTop(pool.createValue(inset->top(), style));
111         insetValue->setRight(pool.createValue(inset->right(), style));
112         insetValue->setBottom(pool.createValue(inset->bottom(), style));
113         insetValue->setLeft(pool.createValue(inset->left(), style));
114
115         insetValue->setTopLeftRadius(pool.createValue(inset->topLeftRadius(), style));
116         insetValue->setTopRightRadius(pool.createValue(inset->topRightRadius(), style));
117         insetValue->setBottomRightRadius(pool.createValue(inset->bottomRightRadius(), style));
118         insetValue->setBottomLeftRadius(pool.createValue(inset->bottomLeftRadius(), style));
119
120         basicShapeValue = insetValue.release();
121         break;
122     }
123     default:
124         break;
125     }
126
127     return pool.createValue(basicShapeValue.release());
128 }
129
130 static Length convertToLength(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value)
131 {
132     return value->convertToLength<FixedIntegerConversion | FixedFloatConversion | PercentConversion | CalculatedConversion | ViewportPercentageConversion>(style, rootStyle, style->effectiveZoom());
133 }
134
135 static LengthSize convertToLengthSize(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value)
136 {
137     if (!value)
138         return LengthSize(Length(0, Fixed), Length(0, Fixed));
139
140     Pair* pair = value->getPairValue();
141     return LengthSize(convertToLength(style, rootStyle, pair->first()), convertToLength(style, rootStyle, pair->second()));
142 }
143
144 static BasicShapeCenterCoordinate convertToCenterCoordinate(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value)
145 {
146     BasicShapeCenterCoordinate::Direction direction;
147     Length offset = Length(0, Fixed);
148
149     CSSValueID keyword = CSSValueTop;
150     if (!value)
151         keyword = CSSValueCenter;
152     else if (value->isValueID())
153         keyword = value->getValueID();
154     else if (Pair* pair = value->getPairValue()) {
155         keyword = pair->first()->getValueID();
156         offset = convertToLength(style, rootStyle, pair->second());
157     } else
158         offset = convertToLength(style, rootStyle, value);
159
160     switch (keyword) {
161     case CSSValueTop:
162     case CSSValueLeft:
163         direction = BasicShapeCenterCoordinate::TopLeft;
164         break;
165     case CSSValueRight:
166     case CSSValueBottom:
167         direction = BasicShapeCenterCoordinate::BottomRight;
168         break;
169     case CSSValueCenter:
170         direction = BasicShapeCenterCoordinate::TopLeft;
171         offset = Length(50, Percent);
172         break;
173     default:
174         ASSERT_NOT_REACHED();
175         direction = BasicShapeCenterCoordinate::TopLeft;
176         break;
177     }
178
179     return BasicShapeCenterCoordinate(direction, offset);
180 }
181
182 static BasicShapeRadius cssValueToBasicShapeRadius(const RenderStyle* style, const RenderStyle* rootStyle, PassRefPtr<CSSPrimitiveValue> radius)
183 {
184     if (!radius)
185         return BasicShapeRadius(BasicShapeRadius::ClosestSide);
186
187     if (radius->isValueID()) {
188         switch (radius->getValueID()) {
189         case CSSValueClosestSide:
190             return BasicShapeRadius(BasicShapeRadius::ClosestSide);
191         case CSSValueFarthestSide:
192             return BasicShapeRadius(BasicShapeRadius::FarthestSide);
193         default:
194             ASSERT_NOT_REACHED();
195             break;
196         }
197     }
198
199     return BasicShapeRadius(convertToLength(style, rootStyle, radius.get()));
200 }
201
202 PassRefPtr<BasicShape> basicShapeForValue(const RenderStyle* style, const RenderStyle* rootStyle, const CSSBasicShape* basicShapeValue)
203 {
204     RefPtr<BasicShape> basicShape;
205
206     switch (basicShapeValue->type()) {
207     case CSSBasicShape::CSSBasicShapeCircleType: {
208         const CSSBasicShapeCircle* circleValue = static_cast<const CSSBasicShapeCircle *>(basicShapeValue);
209         RefPtr<BasicShapeCircle> circle = BasicShapeCircle::create();
210
211         circle->setCenterX(convertToCenterCoordinate(style, rootStyle, circleValue->centerX()));
212         circle->setCenterY(convertToCenterCoordinate(style, rootStyle, circleValue->centerY()));
213         circle->setRadius(cssValueToBasicShapeRadius(style, rootStyle, circleValue->radius()));
214
215         basicShape = circle.release();
216         break;
217     }
218     case CSSBasicShape::CSSBasicShapeEllipseType: {
219         const CSSBasicShapeEllipse* ellipseValue = static_cast<const CSSBasicShapeEllipse *>(basicShapeValue);
220         RefPtr<BasicShapeEllipse> ellipse = BasicShapeEllipse::create();
221
222         ellipse->setCenterX(convertToCenterCoordinate(style, rootStyle, ellipseValue->centerX()));
223         ellipse->setCenterY(convertToCenterCoordinate(style, rootStyle, ellipseValue->centerY()));
224
225         ellipse->setRadiusX(cssValueToBasicShapeRadius(style, rootStyle, ellipseValue->radiusX()));
226         ellipse->setRadiusY(cssValueToBasicShapeRadius(style, rootStyle, ellipseValue->radiusY()));
227
228         basicShape = ellipse.release();
229         break;
230     }
231     case CSSBasicShape::CSSBasicShapePolygonType: {
232         const CSSBasicShapePolygon* polygonValue = static_cast<const CSSBasicShapePolygon *>(basicShapeValue);
233         RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create();
234
235         polygon->setWindRule(polygonValue->windRule());
236         const Vector<RefPtr<CSSPrimitiveValue>>& values = polygonValue->values();
237         for (unsigned i = 0; i < values.size(); i += 2)
238             polygon->appendPoint(convertToLength(style, rootStyle, values.at(i).get()), convertToLength(style, rootStyle, values.at(i + 1).get()));
239
240         basicShape = polygon.release();
241         break;
242     }
243     case CSSBasicShape::CSSBasicShapeInsetType: {
244         const CSSBasicShapeInset* rectValue = static_cast<const CSSBasicShapeInset* >(basicShapeValue);
245         RefPtr<BasicShapeInset> rect = BasicShapeInset::create();
246
247         rect->setTop(convertToLength(style, rootStyle, rectValue->top()));
248         rect->setRight(convertToLength(style, rootStyle, rectValue->right()));
249         rect->setBottom(convertToLength(style, rootStyle, rectValue->bottom()));
250         rect->setLeft(convertToLength(style, rootStyle, rectValue->left()));
251
252         rect->setTopLeftRadius(convertToLengthSize(style, rootStyle, rectValue->topLeftRadius()));
253         rect->setTopRightRadius(convertToLengthSize(style, rootStyle, rectValue->topRightRadius()));
254         rect->setBottomRightRadius(convertToLengthSize(style, rootStyle, rectValue->bottomRightRadius()));
255         rect->setBottomLeftRadius(convertToLengthSize(style, rootStyle, rectValue->bottomLeftRadius()));
256
257         basicShape = rect.release();
258         break;
259     }
260     default:
261         break;
262     }
263
264     return basicShape.release();
265 }
266
267 float floatValueForCenterCoordinate(const BasicShapeCenterCoordinate& center, float boxDimension)
268 {
269     float offset = floatValueForLength(center.length(), boxDimension);
270     if (center.direction() == BasicShapeCenterCoordinate::TopLeft)
271         return offset;
272     return boxDimension - offset;
273 }
274
275 }