Oilpan: fix build after r202625.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / css / CSSBasicShapes.cpp
blob13e7e8ab9a2f8c181f918af9c3eedfb6b8af690b
1 /*
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
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.
30 #include "config.h"
31 #include "core/css/CSSBasicShapes.h"
33 #include "core/css/CSSValuePair.h"
34 #include "core/css/CSSValuePool.h"
35 #include "platform/Length.h"
36 #include "wtf/text/StringBuilder.h"
38 using namespace WTF;
40 namespace blink {
42 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CSSBasicShape)
44 static String buildCircleString(const String& radius, const String& centerX, const String& centerY)
46 char at[] = "at";
47 char separator[] = " ";
48 StringBuilder result;
49 result.appendLiteral("circle(");
50 if (!radius.isNull())
51 result.append(radius);
53 if (!centerX.isNull() || !centerY.isNull()) {
54 if (!radius.isNull())
55 result.appendLiteral(separator);
56 result.append(at);
57 result.appendLiteral(separator);
58 result.append(centerX);
59 result.appendLiteral(separator);
60 result.append(centerY);
62 result.append(')');
63 return result.toString();
66 static String serializePositionOffset(const CSSValuePair& offset, const CSSValuePair& other)
68 if ((toCSSPrimitiveValue(offset.first()).getValueID() == CSSValueLeft && toCSSPrimitiveValue(other.first()).getValueID() == CSSValueTop)
69 || (toCSSPrimitiveValue(offset.first()).getValueID() == CSSValueTop && toCSSPrimitiveValue(other.first()).getValueID() == CSSValueLeft))
70 return offset.second().cssText();
71 return offset.cssText();
74 static PassRefPtrWillBeRawPtr<CSSValuePair> buildSerializablePositionOffset(PassRefPtrWillBeRawPtr<CSSValue> offset, CSSValueID defaultSide)
76 CSSValueID side = defaultSide;
77 RefPtrWillBeRawPtr<CSSPrimitiveValue> amount = nullptr;
79 if (!offset) {
80 side = CSSValueCenter;
81 } else if (offset->isPrimitiveValue() && toCSSPrimitiveValue(offset.get())->isValueID()) {
82 side = toCSSPrimitiveValue(offset.get())->getValueID();
83 } else if (offset->isValuePair()) {
84 side = toCSSPrimitiveValue(toCSSValuePair(*offset).first()).getValueID();
85 amount = &toCSSPrimitiveValue(toCSSValuePair(*offset).second());
86 } else {
87 amount = toCSSPrimitiveValue(offset.get());
90 if (side == CSSValueCenter) {
91 side = defaultSide;
92 amount = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage);
93 } else if ((side == CSSValueRight || side == CSSValueBottom)
94 && amount->isPercentage()) {
95 side = defaultSide;
96 amount = cssValuePool().createValue(100 - amount->getFloatValue(), CSSPrimitiveValue::UnitType::Percentage);
97 } else if (amount->isLength() && !amount->getFloatValue()) {
98 if (side == CSSValueRight || side == CSSValueBottom)
99 amount = cssValuePool().createValue(100, CSSPrimitiveValue::UnitType::Percentage);
100 else
101 amount = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage);
102 side = defaultSide;
105 return CSSValuePair::create(cssValuePool().createValue(side), amount.release(), CSSValuePair::KeepIdenticalValues);
108 String CSSBasicShapeCircle::cssText() const
110 RefPtrWillBeRawPtr<CSSValuePair> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
111 RefPtrWillBeRawPtr<CSSValuePair> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
113 String radius;
114 if (m_radius && m_radius->getValueID() != CSSValueClosestSide)
115 radius = m_radius->cssText();
117 return buildCircleString(radius,
118 serializePositionOffset(*normalizedCX, *normalizedCY),
119 serializePositionOffset(*normalizedCY, *normalizedCX));
122 bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const
124 if (shape.type() != CSSBasicShapeCircleType)
125 return false;
127 const CSSBasicShapeCircle& other = toCSSBasicShapeCircle(shape);
128 return compareCSSValuePtr(m_centerX, other.m_centerX)
129 && compareCSSValuePtr(m_centerY, other.m_centerY)
130 && compareCSSValuePtr(m_radius, other.m_radius);
133 DEFINE_TRACE(CSSBasicShapeCircle)
135 visitor->trace(m_centerX);
136 visitor->trace(m_centerY);
137 visitor->trace(m_radius);
138 CSSBasicShape::trace(visitor);
141 static String buildEllipseString(const String& radiusX, const String& radiusY, const String& centerX, const String& centerY)
143 char at[] = "at";
144 char separator[] = " ";
145 StringBuilder result;
146 result.appendLiteral("ellipse(");
147 bool needsSeparator = false;
148 if (!radiusX.isNull()) {
149 result.append(radiusX);
150 needsSeparator = true;
152 if (!radiusY.isNull()) {
153 if (needsSeparator)
154 result.appendLiteral(separator);
155 result.append(radiusY);
156 needsSeparator = true;
159 if (!centerX.isNull() || !centerY.isNull()) {
160 if (needsSeparator)
161 result.appendLiteral(separator);
162 result.appendLiteral(at);
163 result.appendLiteral(separator);
164 result.append(centerX);
165 result.appendLiteral(separator);
166 result.append(centerY);
168 result.append(')');
169 return result.toString();
172 String CSSBasicShapeEllipse::cssText() const
174 RefPtrWillBeRawPtr<CSSValuePair> normalizedCX = buildSerializablePositionOffset(m_centerX, CSSValueLeft);
175 RefPtrWillBeRawPtr<CSSValuePair> normalizedCY = buildSerializablePositionOffset(m_centerY, CSSValueTop);
177 String radiusX;
178 String radiusY;
179 if (m_radiusX) {
180 bool shouldSerializeRadiusXValue = m_radiusX->getValueID() != CSSValueClosestSide;
181 bool shouldSerializeRadiusYValue = false;
183 if (m_radiusY) {
184 shouldSerializeRadiusYValue = m_radiusY->getValueID() != CSSValueClosestSide;
185 if (shouldSerializeRadiusYValue)
186 radiusY = m_radiusY->cssText();
188 if (shouldSerializeRadiusXValue || (!shouldSerializeRadiusXValue && shouldSerializeRadiusYValue))
189 radiusX = m_radiusX->cssText();
192 return buildEllipseString(radiusX, radiusY,
193 serializePositionOffset(*normalizedCX, *normalizedCY),
194 serializePositionOffset(*normalizedCY, *normalizedCX));
197 bool CSSBasicShapeEllipse::equals(const CSSBasicShape& shape) const
199 if (shape.type() != CSSBasicShapeEllipseType)
200 return false;
202 const CSSBasicShapeEllipse& other = toCSSBasicShapeEllipse(shape);
203 return compareCSSValuePtr(m_centerX, other.m_centerX)
204 && compareCSSValuePtr(m_centerY, other.m_centerY)
205 && compareCSSValuePtr(m_radiusX, other.m_radiusX)
206 && compareCSSValuePtr(m_radiusY, other.m_radiusY);
209 DEFINE_TRACE(CSSBasicShapeEllipse)
211 visitor->trace(m_centerX);
212 visitor->trace(m_centerY);
213 visitor->trace(m_radiusX);
214 visitor->trace(m_radiusY);
215 CSSBasicShape::trace(visitor);
218 static String buildPolygonString(const WindRule& windRule, const Vector<String>& points)
220 ASSERT(!(points.size() % 2));
222 StringBuilder result;
223 const char evenOddOpening[] = "polygon(evenodd, ";
224 const char nonZeroOpening[] = "polygon(";
225 const char commaSeparator[] = ", ";
226 static_assert(sizeof(evenOddOpening) > sizeof(nonZeroOpening), "polygon string openings should be the same length");
228 // Compute the required capacity in advance to reduce allocations.
229 size_t length = sizeof(evenOddOpening) - 1;
230 for (size_t i = 0; i < points.size(); i += 2) {
231 if (i)
232 length += (sizeof(commaSeparator) - 1);
233 // add length of two strings, plus one for the space separator.
234 length += points[i].length() + 1 + points[i + 1].length();
236 result.reserveCapacity(length);
238 if (windRule == RULE_EVENODD)
239 result.appendLiteral(evenOddOpening);
240 else
241 result.appendLiteral(nonZeroOpening);
243 for (size_t i = 0; i < points.size(); i += 2) {
244 if (i)
245 result.appendLiteral(commaSeparator);
246 result.append(points[i]);
247 result.append(' ');
248 result.append(points[i + 1]);
251 result.append(')');
252 return result.toString();
255 String CSSBasicShapePolygon::cssText() const
257 Vector<String> points;
258 points.reserveInitialCapacity(m_values.size());
260 for (size_t i = 0; i < m_values.size(); ++i)
261 points.append(m_values.at(i)->cssText());
263 return buildPolygonString(m_windRule, points);
266 bool CSSBasicShapePolygon::equals(const CSSBasicShape& shape) const
268 if (shape.type() != CSSBasicShapePolygonType)
269 return false;
271 const CSSBasicShapePolygon& rhs = toCSSBasicShapePolygon(shape);
272 return compareCSSValueVector(m_values, rhs.m_values);
275 DEFINE_TRACE(CSSBasicShapePolygon)
277 visitor->trace(m_values);
278 CSSBasicShape::trace(visitor);
281 static bool buildInsetRadii(Vector<String> &radii, const String& topLeftRadius, const String& topRightRadius, const String& bottomRightRadius, const String& bottomLeftRadius)
283 bool showBottomLeft = topRightRadius != bottomLeftRadius;
284 bool showBottomRight = showBottomLeft || (bottomRightRadius != topLeftRadius);
285 bool showTopRight = showBottomRight || (topRightRadius != topLeftRadius);
287 radii.append(topLeftRadius);
288 if (showTopRight)
289 radii.append(topRightRadius);
290 if (showBottomRight)
291 radii.append(bottomRightRadius);
292 if (showBottomLeft)
293 radii.append(bottomLeftRadius);
295 return radii.size() == 1 && radii[0] == "0px";
298 static String buildInsetString(const String& top, const String& right, const String& bottom, const String& left,
299 const String& topLeftRadiusWidth, const String& topLeftRadiusHeight,
300 const String& topRightRadiusWidth, const String& topRightRadiusHeight,
301 const String& bottomRightRadiusWidth, const String& bottomRightRadiusHeight,
302 const String& bottomLeftRadiusWidth, const String& bottomLeftRadiusHeight)
304 char opening[] = "inset(";
305 char separator[] = " ";
306 char cornersSeparator[] = "round";
307 StringBuilder result;
308 result.appendLiteral(opening);
309 result.append(top);
310 bool showLeftArg = !left.isNull() && left != right;
311 bool showBottomArg = !bottom.isNull() && (bottom != top || showLeftArg);
312 bool showRightArg = !right.isNull() && (right != top || showBottomArg);
313 if (showRightArg) {
314 result.appendLiteral(separator);
315 result.append(right);
317 if (showBottomArg) {
318 result.appendLiteral(separator);
319 result.append(bottom);
321 if (showLeftArg) {
322 result.appendLiteral(separator);
323 result.append(left);
326 if (!topLeftRadiusWidth.isNull() && !topLeftRadiusHeight.isNull()) {
327 Vector<String> horizontalRadii;
328 bool areDefaultCornerRadii = buildInsetRadii(horizontalRadii, topLeftRadiusWidth, topRightRadiusWidth, bottomRightRadiusWidth, bottomLeftRadiusWidth);
330 Vector<String> verticalRadii;
331 areDefaultCornerRadii &= buildInsetRadii(verticalRadii, topLeftRadiusHeight, topRightRadiusHeight, bottomRightRadiusHeight, bottomLeftRadiusHeight);
333 if (!areDefaultCornerRadii) {
334 result.appendLiteral(separator);
335 result.appendLiteral(cornersSeparator);
337 for (size_t i = 0; i < horizontalRadii.size(); ++i) {
338 result.appendLiteral(separator);
339 result.append(horizontalRadii[i]);
341 if (horizontalRadii != verticalRadii) {
342 result.appendLiteral(separator);
343 result.appendLiteral("/");
345 for (size_t i = 0; i < verticalRadii.size(); ++i) {
346 result.appendLiteral(separator);
347 result.append(verticalRadii[i]);
352 result.append(')');
354 return result.toString();
357 static inline void updateCornerRadiusWidthAndHeight(const CSSValuePair* cornerRadius, String& width, String& height)
359 if (!cornerRadius)
360 return;
362 width = cornerRadius->first().cssText();
363 height = cornerRadius->second().cssText();
366 String CSSBasicShapeInset::cssText() const
368 String topLeftRadiusWidth;
369 String topLeftRadiusHeight;
370 String topRightRadiusWidth;
371 String topRightRadiusHeight;
372 String bottomRightRadiusWidth;
373 String bottomRightRadiusHeight;
374 String bottomLeftRadiusWidth;
375 String bottomLeftRadiusHeight;
377 updateCornerRadiusWidthAndHeight(topLeftRadius(), topLeftRadiusWidth, topLeftRadiusHeight);
378 updateCornerRadiusWidthAndHeight(topRightRadius(), topRightRadiusWidth, topRightRadiusHeight);
379 updateCornerRadiusWidthAndHeight(bottomRightRadius(), bottomRightRadiusWidth, bottomRightRadiusHeight);
380 updateCornerRadiusWidthAndHeight(bottomLeftRadius(), bottomLeftRadiusWidth, bottomLeftRadiusHeight);
382 return buildInsetString(m_top ? m_top->cssText() : String(),
383 m_right ? m_right->cssText() : String(),
384 m_bottom ? m_bottom->cssText() : String(),
385 m_left ? m_left->cssText() : String(),
386 topLeftRadiusWidth,
387 topLeftRadiusHeight,
388 topRightRadiusWidth,
389 topRightRadiusHeight,
390 bottomRightRadiusWidth,
391 bottomRightRadiusHeight,
392 bottomLeftRadiusWidth,
393 bottomLeftRadiusHeight);
396 bool CSSBasicShapeInset::equals(const CSSBasicShape& shape) const
398 if (shape.type() != CSSBasicShapeInsetType)
399 return false;
401 const CSSBasicShapeInset& other = toCSSBasicShapeInset(shape);
402 return compareCSSValuePtr(m_top, other.m_top)
403 && compareCSSValuePtr(m_right, other.m_right)
404 && compareCSSValuePtr(m_bottom, other.m_bottom)
405 && compareCSSValuePtr(m_left, other.m_left)
406 && compareCSSValuePtr(m_topLeftRadius, other.m_topLeftRadius)
407 && compareCSSValuePtr(m_topRightRadius, other.m_topRightRadius)
408 && compareCSSValuePtr(m_bottomRightRadius, other.m_bottomRightRadius)
409 && compareCSSValuePtr(m_bottomLeftRadius, other.m_bottomLeftRadius);
412 DEFINE_TRACE(CSSBasicShapeInset)
414 visitor->trace(m_top);
415 visitor->trace(m_right);
416 visitor->trace(m_bottom);
417 visitor->trace(m_left);
418 visitor->trace(m_topLeftRadius);
419 visitor->trace(m_topRightRadius);
420 visitor->trace(m_bottomRightRadius);
421 visitor->trace(m_bottomLeftRadius);
422 CSSBasicShape::trace(visitor);
425 } // namespace blink