Home | History | Annotate | Download | only in css
      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 
     35 using namespace WTF;
     36 
     37 namespace WebCore {
     38 
     39 static 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 
     66 String 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 
     76 bool 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 
     90 String 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 
    100 bool 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 
    110 static String buildCircleString(const String& x, const String& y, const String& radius)
    111 {
    112     return "circle(" + x + ", " + y + ", " + radius + ')';
    113 }
    114 
    115 String CSSBasicShapeCircle::cssText() const
    116 {
    117     return buildCircleString(m_centerX->cssText(), m_centerY->cssText(), m_radius->cssText());
    118 }
    119 
    120 bool 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 
    131 String 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 
    138 bool CSSBasicShapeCircle::hasVariableReference() const
    139 {
    140     return m_centerX->hasVariableReference()
    141         || m_centerY->hasVariableReference()
    142         || m_radius->hasVariableReference();
    143 }
    144 
    145 static String buildEllipseString(const String& x, const String& y, const String& radiusX, const String& radiusY)
    146 {
    147     return "ellipse(" + x + ", " + y + ", " + radiusX + ", " + radiusY + ')';
    148 }
    149 
    150 String CSSBasicShapeEllipse::cssText() const
    151 {
    152     return buildEllipseString(m_centerX->cssText(), m_centerY->cssText(), m_radiusX->cssText(), m_radiusY->cssText());
    153 }
    154 
    155 bool 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 
    167 String 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 
    175 bool CSSBasicShapeEllipse::hasVariableReference() const
    176 {
    177     return m_centerX->hasVariableReference()
    178         || m_centerY->hasVariableReference()
    179         || m_radiusX->hasVariableReference()
    180         || m_radiusY->hasVariableReference();
    181 }
    182 
    183 static 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 
    221 String 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 
    232 bool 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 
    241 String 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 
    252 bool 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 
    261 static 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 
    288 String 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 
    298 bool 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 
    312 String 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 
    322 bool 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