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