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