1/* 2 * Copyright (C) 2011 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 32#include "CSSBasicShapes.h" 33 34#include "CSSPrimitiveValueMappings.h" 35 36#include <wtf/text/StringBuilder.h> 37 38using namespace WTF; 39 40namespace WebCore { 41 42static String buildRectangleString(const String& x, const String& y, const String& width, const String& height, const String& radiusX, const String& radiusY) 43{ 44 char opening[] = "rectangle("; 45 char separator[] = ", "; 46 StringBuilder result; 47 // Compute the required capacity in advance to reduce allocations. 48 result.reserveCapacity((sizeof(opening) - 1) + (5 * (sizeof(separator) - 1)) + 1 + x.length() + y.length() + width.length() + height.length() + radiusX.length() + radiusY.length()); 49 result.appendLiteral(opening); 50 result.append(x); 51 result.appendLiteral(separator); 52 result.append(y); 53 result.appendLiteral(separator); 54 result.append(width); 55 result.appendLiteral(separator); 56 result.append(height); 57 if (!radiusX.isNull()) { 58 result.appendLiteral(separator); 59 result.append(radiusX); 60 if (!radiusY.isNull()) { 61 result.appendLiteral(separator); 62 result.append(radiusY); 63 } 64 } 65 result.append(')'); 66 return result.toString(); 67} 68 69String CSSBasicShapeRectangle::cssText() const 70{ 71 return buildRectangleString(m_x->cssText(), 72 m_y->cssText(), 73 m_width->cssText(), 74 m_height->cssText(), 75 m_radiusX.get() ? m_radiusX->cssText() : String(), 76 m_radiusY.get() ? m_radiusY->cssText() : String()); 77} 78 79bool CSSBasicShapeRectangle::equals(const CSSBasicShape& shape) const 80{ 81 if (shape.type() != CSSBasicShapeRectangleType) 82 return false; 83 84 const CSSBasicShapeRectangle& other = static_cast<const CSSBasicShapeRectangle&>(shape); 85 return compareCSSValuePtr(m_x, other.m_x) 86 && compareCSSValuePtr(m_y, other.m_y) 87 && compareCSSValuePtr(m_width, other.m_width) 88 && compareCSSValuePtr(m_height, other.m_height) 89 && compareCSSValuePtr(m_radiusX, other.m_radiusX) 90 && compareCSSValuePtr(m_radiusY, other.m_radiusY); 91} 92 93#if ENABLE(CSS_VARIABLES) 94String CSSBasicShapeRectangle::serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const 95{ 96 return buildRectangleString(m_x->serializeResolvingVariables(variables), 97 m_y->serializeResolvingVariables(variables), 98 m_width->serializeResolvingVariables(variables), 99 m_height->serializeResolvingVariables(variables), 100 m_radiusX.get() ? m_radiusX->serializeResolvingVariables(variables) : String(), 101 m_radiusY.get() ? m_radiusY->serializeResolvingVariables(variables) : String()); 102} 103 104bool CSSBasicShapeRectangle::hasVariableReference() const 105{ 106 return m_x->hasVariableReference() 107 || m_y->hasVariableReference() 108 || m_width->hasVariableReference() 109 || m_height->hasVariableReference() 110 || (m_radiusX.get() && m_radiusX->hasVariableReference()) 111 || (m_radiusY.get() && m_radiusY->hasVariableReference()); 112} 113#endif 114 115static String buildCircleString(const String& x, const String& y, const String& radius) 116{ 117 return "circle(" + x + ", " + y + ", " + radius + ')'; 118} 119 120String CSSBasicShapeCircle::cssText() const 121{ 122 return buildCircleString(m_centerX->cssText(), m_centerY->cssText(), m_radius->cssText()); 123} 124 125bool CSSBasicShapeCircle::equals(const CSSBasicShape& shape) const 126{ 127 if (shape.type() != CSSBasicShapeCircleType) 128 return false; 129 130 const CSSBasicShapeCircle& other = static_cast<const CSSBasicShapeCircle&>(shape); 131 return compareCSSValuePtr(m_centerX, other.m_centerX) 132 && compareCSSValuePtr(m_centerY, other.m_centerY) 133 && compareCSSValuePtr(m_radius, other.m_radius); 134} 135 136#if ENABLE(CSS_VARIABLES) 137String CSSBasicShapeCircle::serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const 138{ 139 return buildCircleString(m_centerX->serializeResolvingVariables(variables), 140 m_centerY->serializeResolvingVariables(variables), 141 m_radius->serializeResolvingVariables(variables)); 142} 143 144bool CSSBasicShapeCircle::hasVariableReference() const 145{ 146 return m_centerX->hasVariableReference() 147 || m_centerY->hasVariableReference() 148 || m_radius->hasVariableReference(); 149} 150#endif 151 152static String buildEllipseString(const String& x, const String& y, const String& radiusX, const String& radiusY) 153{ 154 return "ellipse(" + x + ", " + y + ", " + radiusX + ", " + radiusY + ')'; 155} 156 157String CSSBasicShapeEllipse::cssText() const 158{ 159 return buildEllipseString(m_centerX->cssText(), m_centerY->cssText(), m_radiusX->cssText(), m_radiusY->cssText()); 160} 161 162bool CSSBasicShapeEllipse::equals(const CSSBasicShape& shape) const 163{ 164 if (shape.type() != CSSBasicShapeEllipseType) 165 return false; 166 167 const CSSBasicShapeEllipse& other = static_cast<const CSSBasicShapeEllipse&>(shape); 168 return compareCSSValuePtr(m_centerX, other.m_centerX) 169 && compareCSSValuePtr(m_centerY, other.m_centerY) 170 && compareCSSValuePtr(m_radiusX, other.m_radiusX) 171 && compareCSSValuePtr(m_radiusY, other.m_radiusY); 172} 173 174#if ENABLE(CSS_VARIABLES) 175String CSSBasicShapeEllipse::serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const 176{ 177 return buildEllipseString(m_centerX->serializeResolvingVariables(variables), 178 m_centerY->serializeResolvingVariables(variables), 179 m_radiusX->serializeResolvingVariables(variables), 180 m_radiusY->serializeResolvingVariables(variables)); 181} 182 183bool CSSBasicShapeEllipse::hasVariableReference() const 184{ 185 return m_centerX->hasVariableReference() 186 || m_centerY->hasVariableReference() 187 || m_radiusX->hasVariableReference() 188 || m_radiusY->hasVariableReference(); 189} 190#endif 191 192static String buildPolygonString(const WindRule& windRule, const Vector<String>& points) 193{ 194 ASSERT(!(points.size() % 2)); 195 196 StringBuilder result; 197 char evenOddOpening[] = "polygon(evenodd, "; 198 char nonZeroOpening[] = "polygon(nonzero, "; 199 char commaSeparator[] = ", "; 200 COMPILE_ASSERT(sizeof(evenOddOpening) == sizeof(nonZeroOpening), polygon_string_openings_have_same_length); 201 202 // Compute the required capacity in advance to reduce allocations. 203 size_t length = sizeof(evenOddOpening) - 1; 204 for (size_t i = 0; i < points.size(); i += 2) { 205 if (i) 206 length += (sizeof(commaSeparator) - 1); 207 // add length of two strings, plus one for the space separator. 208 length += points[i].length() + 1 + points[i + 1].length(); 209 } 210 result.reserveCapacity(length); 211 212 if (windRule == RULE_EVENODD) 213 result.appendLiteral(evenOddOpening); 214 else 215 result.appendLiteral(nonZeroOpening); 216 217 for (size_t i = 0; i < points.size(); i += 2) { 218 if (i) 219 result.appendLiteral(commaSeparator); 220 result.append(points[i]); 221 result.append(' '); 222 result.append(points[i + 1]); 223 } 224 225 result.append(')'); 226 227 return result.toString(); 228} 229 230String CSSBasicShapePolygon::cssText() const 231{ 232 Vector<String> points; 233 points.reserveInitialCapacity(m_values.size()); 234 235 for (size_t i = 0; i < m_values.size(); ++i) 236 points.append(m_values.at(i)->cssText()); 237 238 return buildPolygonString(m_windRule, points); 239} 240 241bool CSSBasicShapePolygon::equals(const CSSBasicShape& shape) const 242{ 243 if (shape.type() != CSSBasicShapePolygonType) 244 return false; 245 246 const CSSBasicShapePolygon& rhs = static_cast<const CSSBasicShapePolygon&>(shape); 247 return compareCSSValueVector<CSSPrimitiveValue>(m_values, rhs.m_values); 248} 249 250#if ENABLE(CSS_VARIABLES) 251String CSSBasicShapePolygon::serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const 252{ 253 Vector<String> points; 254 points.reserveInitialCapacity(m_values.size()); 255 256 for (size_t i = 0; i < m_values.size(); ++i) 257 points.append(m_values.at(i)->serializeResolvingVariables(variables)); 258 259 return buildPolygonString(m_windRule, points); 260} 261 262bool CSSBasicShapePolygon::hasVariableReference() const 263{ 264 for (size_t i = 0; i < m_values.size(); ++i) { 265 if (m_values.at(i)->hasVariableReference()) 266 return true; 267 } 268 return false; 269} 270#endif 271 272static String buildInsetRectangleString(const String& top, const String& right, const String& bottom, const String& left, const String& radiusX, const String& radiusY) 273{ 274 char opening[] = "inset-rectangle("; 275 char separator[] = ", "; 276 StringBuilder result; 277 // Compute the required capacity in advance to reduce allocations. 278 result.reserveCapacity((sizeof(opening) - 1) + (5 * (sizeof(separator) - 1)) + 1 + top.length() + right.length() + bottom.length() + left.length() + radiusX.length() + radiusY.length()); 279 result.appendLiteral(opening); 280 result.append(top); 281 result.appendLiteral(separator); 282 result.append(right); 283 result.appendLiteral(separator); 284 result.append(bottom); 285 result.appendLiteral(separator); 286 result.append(left); 287 if (!radiusX.isNull()) { 288 result.appendLiteral(separator); 289 result.append(radiusX); 290 if (!radiusY.isNull()) { 291 result.appendLiteral(separator); 292 result.append(radiusY); 293 } 294 } 295 result.append(')'); 296 return result.toString(); 297} 298 299String CSSBasicShapeInsetRectangle::cssText() const 300{ 301 return buildInsetRectangleString(m_top->cssText(), 302 m_right->cssText(), 303 m_bottom->cssText(), 304 m_left->cssText(), 305 m_radiusX.get() ? m_radiusX->cssText() : String(), 306 m_radiusY.get() ? m_radiusY->cssText() : String()); 307} 308 309bool CSSBasicShapeInsetRectangle::equals(const CSSBasicShape& shape) const 310{ 311 if (shape.type() != CSSBasicShapeInsetRectangleType) 312 return false; 313 314 const CSSBasicShapeInsetRectangle& other = static_cast<const CSSBasicShapeInsetRectangle&>(shape); 315 return compareCSSValuePtr(m_top, other.m_top) 316 && compareCSSValuePtr(m_right, other.m_right) 317 && compareCSSValuePtr(m_bottom, other.m_bottom) 318 && compareCSSValuePtr(m_left, other.m_left) 319 && compareCSSValuePtr(m_radiusX, other.m_radiusX) 320 && compareCSSValuePtr(m_radiusY, other.m_radiusY); 321} 322 323#if ENABLE(CSS_VARIABLES) 324String CSSBasicShapeInsetRectangle::serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const 325{ 326 return buildInsetRectangleString(m_top->serializeResolvingVariables(variables), 327 m_right->serializeResolvingVariables(variables), 328 m_bottom->serializeResolvingVariables(variables), 329 m_left->serializeResolvingVariables(variables), 330 m_radiusX.get() ? m_radiusX->serializeResolvingVariables(variables) : String(), 331 m_radiusY.get() ? m_radiusY->serializeResolvingVariables(variables) : String()); 332} 333 334bool CSSBasicShapeInsetRectangle::hasVariableReference() const 335{ 336 return m_top->hasVariableReference() 337 || m_right->hasVariableReference() 338 || m_bottom->hasVariableReference() 339 || m_left->hasVariableReference() 340 || (m_radiusX.get() && m_radiusX->hasVariableReference()) 341 || (m_radiusY.get() && m_radiusY->hasVariableReference()); 342} 343#endif 344 345} // namespace WebCore 346 347