Home | History | Annotate | Download | only in css
      1 /*
      2  * (C) 1999-2003 Lars Knoll (knoll (at) kde.org)
      3  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 #include "CSSPrimitiveValue.h"
     23 
     24 #include "CSSHelper.h"
     25 #include "CSSPropertyNames.h"
     26 #include "CSSStyleSheet.h"
     27 #include "CSSValueKeywords.h"
     28 #include "Color.h"
     29 #include "Counter.h"
     30 #include "ExceptionCode.h"
     31 #include "Node.h"
     32 #include "Pair.h"
     33 #include "RGBColor.h"
     34 #include "Rect.h"
     35 #include "RenderStyle.h"
     36 #include <wtf/ASCIICType.h>
     37 #include <wtf/StdLibExtras.h>
     38 
     39 #if ENABLE(DASHBOARD_SUPPORT)
     40 #include "DashboardRegion.h"
     41 #endif
     42 
     43 using namespace WTF;
     44 
     45 namespace WebCore {
     46 
     47 // A more stylish solution than sharing would be to turn CSSPrimitiveValue (or CSSValues in general) into non-virtual,
     48 // non-refcounted simple type with value semantics. In practice these sharing tricks get similar memory benefits
     49 // with less need for refactoring.
     50 
     51 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createIdentifier(int ident)
     52 {
     53     static RefPtr<CSSPrimitiveValue>* identValueCache = new RefPtr<CSSPrimitiveValue>[numCSSValueKeywords];
     54     if (ident >= 0 && ident < numCSSValueKeywords) {
     55         RefPtr<CSSPrimitiveValue> primitiveValue = identValueCache[ident];
     56         if (!primitiveValue) {
     57             primitiveValue = adoptRef(new CSSPrimitiveValue(ident));
     58             identValueCache[ident] = primitiveValue;
     59         }
     60         return primitiveValue.release();
     61     }
     62     return adoptRef(new CSSPrimitiveValue(ident));
     63 }
     64 
     65 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createColor(unsigned rgbValue)
     66 {
     67     typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache;
     68     static ColorValueCache* colorValueCache = new ColorValueCache;
     69     // These are the empty and deleted values of the hash table.
     70     if (rgbValue == Color::transparent) {
     71         static CSSPrimitiveValue* colorTransparent = new CSSPrimitiveValue(Color::transparent);
     72         return colorTransparent;
     73     }
     74     if (rgbValue == Color::white) {
     75         static CSSPrimitiveValue* colorWhite = new CSSPrimitiveValue(Color::white);
     76         return colorWhite;
     77     }
     78     RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue);
     79     if (primitiveValue)
     80         return primitiveValue.release();
     81     primitiveValue = adoptRef(new CSSPrimitiveValue(rgbValue));
     82     // Just wipe out the cache and start rebuilding when it gets too big.
     83     const int maxColorCacheSize = 512;
     84     if (colorValueCache->size() >= maxColorCacheSize)
     85         colorValueCache->clear();
     86     colorValueCache->add(rgbValue, primitiveValue);
     87 
     88     return primitiveValue.release();
     89 }
     90 
     91 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(double value, UnitTypes type)
     92 {
     93     // Small integers are very common. Try to share them.
     94     const int cachedIntegerCount = 128;
     95     // Other common primitive types have UnitTypes smaller than this.
     96     const int maxCachedUnitType = CSS_PX;
     97     typedef RefPtr<CSSPrimitiveValue>(* IntegerValueCache)[maxCachedUnitType + 1];
     98     static IntegerValueCache integerValueCache = new RefPtr<CSSPrimitiveValue>[cachedIntegerCount][maxCachedUnitType + 1];
     99     if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) {
    100         int intValue = static_cast<int>(value);
    101         if (value == intValue) {
    102             RefPtr<CSSPrimitiveValue> primitiveValue = integerValueCache[intValue][type];
    103             if (!primitiveValue) {
    104                 primitiveValue = adoptRef(new CSSPrimitiveValue(value, type));
    105                 integerValueCache[intValue][type] = primitiveValue;
    106             }
    107             return primitiveValue.release();
    108         }
    109     }
    110 
    111     return adoptRef(new CSSPrimitiveValue(value, type));
    112 }
    113 
    114 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type)
    115 {
    116     return adoptRef(new CSSPrimitiveValue(value, type));
    117 }
    118 
    119 static const char* valueOrPropertyName(int valueOrPropertyID)
    120 {
    121     if (const char* valueName = getValueName(valueOrPropertyID))
    122         return valueName;
    123     return getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID));
    124 }
    125 
    126 // "ident" from the CSS tokenizer, minus backslash-escape sequences
    127 static bool isCSSTokenizerIdentifier(const String& string)
    128 {
    129     const UChar* p = string.characters();
    130     const UChar* end = p + string.length();
    131 
    132     // -?
    133     if (p != end && p[0] == '-')
    134         ++p;
    135 
    136     // {nmstart}
    137     if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
    138         return false;
    139     ++p;
    140 
    141     // {nmchar}*
    142     for (; p != end; ++p) {
    143         if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
    144             return false;
    145     }
    146 
    147     return true;
    148 }
    149 
    150 // "url" from the CSS tokenizer, minus backslash-escape sequences
    151 static bool isCSSTokenizerURL(const String& string)
    152 {
    153     const UChar* p = string.characters();
    154     const UChar* end = p + string.length();
    155 
    156     for (; p != end; ++p) {
    157         UChar c = p[0];
    158         switch (c) {
    159             case '!':
    160             case '#':
    161             case '$':
    162             case '%':
    163             case '&':
    164                 break;
    165             default:
    166                 if (c < '*')
    167                     return false;
    168                 if (c <= '~')
    169                     break;
    170                 if (c < 128)
    171                     return false;
    172         }
    173     }
    174 
    175     return true;
    176 }
    177 
    178 // We use single quotes for now because markup.cpp uses double quotes.
    179 static String quoteString(const String& string)
    180 {
    181     // FIXME: Also need to escape characters like '\n'.
    182     String s = string;
    183     s.replace('\\', "\\\\");
    184     s.replace('\'', "\\'");
    185     return "'" + s + "'";
    186 }
    187 
    188 static String quoteStringIfNeeded(const String& string)
    189 {
    190     return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
    191 }
    192 
    193 static String quoteURLIfNeeded(const String& string)
    194 {
    195     return isCSSTokenizerURL(string) ? string : quoteString(string);
    196 }
    197 
    198 CSSPrimitiveValue::CSSPrimitiveValue()
    199     : m_type(0)
    200 {
    201 }
    202 
    203 CSSPrimitiveValue::CSSPrimitiveValue(int ident)
    204     : m_type(CSS_IDENT)
    205 {
    206     m_value.ident = ident;
    207 }
    208 
    209 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
    210     : m_type(type)
    211 {
    212     m_value.num = num;
    213 }
    214 
    215 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
    216     : m_type(type)
    217 {
    218     if ((m_value.string = str.impl()))
    219         m_value.string->ref();
    220 }
    221 
    222 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
    223     : m_type(CSS_RGBCOLOR)
    224 {
    225     m_value.rgbcolor = color;
    226 }
    227 
    228 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
    229 {
    230     switch (length.type()) {
    231         case Auto:
    232             m_type = CSS_IDENT;
    233             m_value.ident = CSSValueAuto;
    234             break;
    235         case WebCore::Fixed:
    236             m_type = CSS_PX;
    237             m_value.num = length.value();
    238             break;
    239         case Intrinsic:
    240             m_type = CSS_IDENT;
    241             m_value.ident = CSSValueIntrinsic;
    242             break;
    243         case MinIntrinsic:
    244             m_type = CSS_IDENT;
    245             m_value.ident = CSSValueMinIntrinsic;
    246             break;
    247         case Percent:
    248             m_type = CSS_PERCENTAGE;
    249             m_value.num = length.percent();
    250             break;
    251         case Relative:
    252         case Static:
    253             ASSERT_NOT_REACHED();
    254             break;
    255     }
    256 }
    257 
    258 void CSSPrimitiveValue::init(PassRefPtr<Counter> c)
    259 {
    260     m_type = CSS_COUNTER;
    261     m_value.counter = c.releaseRef();
    262 }
    263 
    264 void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
    265 {
    266     m_type = CSS_RECT;
    267     m_value.rect = r.releaseRef();
    268 }
    269 
    270 #if ENABLE(DASHBOARD_SUPPORT)
    271 void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r)
    272 {
    273     m_type = CSS_DASHBOARD_REGION;
    274     m_value.region = r.releaseRef();
    275 }
    276 #endif
    277 
    278 void CSSPrimitiveValue::init(PassRefPtr<Pair> p)
    279 {
    280     m_type = CSS_PAIR;
    281     m_value.pair = p.releaseRef();
    282 }
    283 
    284 CSSPrimitiveValue::~CSSPrimitiveValue()
    285 {
    286     cleanup();
    287 }
    288 
    289 void CSSPrimitiveValue::cleanup()
    290 {
    291     switch (m_type) {
    292         case CSS_STRING:
    293         case CSS_URI:
    294         case CSS_ATTR:
    295         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
    296         case CSS_PARSER_HEXCOLOR:
    297             if (m_value.string)
    298                 m_value.string->deref();
    299             break;
    300         case CSS_COUNTER:
    301             m_value.counter->deref();
    302             break;
    303         case CSS_RECT:
    304             m_value.rect->deref();
    305             break;
    306         case CSS_PAIR:
    307             m_value.pair->deref();
    308             break;
    309 #if ENABLE(DASHBOARD_SUPPORT)
    310         case CSS_DASHBOARD_REGION:
    311             if (m_value.region)
    312                 m_value.region->deref();
    313             break;
    314 #endif
    315         default:
    316             break;
    317     }
    318 
    319     m_type = 0;
    320 }
    321 
    322 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle)
    323 {
    324     double result = computeLengthDouble(style, rootStyle);
    325 
    326     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    327     // need to go ahead and round if we're really close to the next integer value.
    328     result += result < 0 ? -0.01 : +0.01;
    329 
    330     if (result > INT_MAX || result < INT_MIN)
    331         return 0;
    332     return static_cast<int>(result);
    333 }
    334 
    335 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
    336 {
    337     double result = computeLengthDouble(style, rootStyle, multiplier);
    338 
    339     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    340     // need to go ahead and round if we're really close to the next integer value.
    341     result += result < 0 ? -0.01 : +0.01;
    342 
    343     if (result > INT_MAX || result < INT_MIN)
    344         return 0;
    345     return static_cast<int>(result);
    346 }
    347 
    348 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
    349 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
    350 
    351 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow.
    352 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle)
    353 {
    354     double result = computeLengthDouble(style, rootStyle);
    355 
    356     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    357     // need to go ahead and round if we're really close to the next integer value.
    358     result += result < 0 ? -0.01 : +0.01;
    359 
    360     if (result > intMaxForLength || result < intMinForLength)
    361         return 0;
    362     return static_cast<int>(result);
    363 }
    364 
    365 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow.
    366 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
    367 {
    368     double result = computeLengthDouble(style, rootStyle, multiplier);
    369 
    370     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    371     // need to go ahead and round if we're really close to the next integer value.
    372     result += result < 0 ? -0.01 : +0.01;
    373 
    374     if (result > intMaxForLength || result < intMinForLength)
    375         return 0;
    376     return static_cast<int>(result);
    377 }
    378 
    379 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle)
    380 {
    381     double result = computeLengthDouble(style, rootStyle);
    382 
    383     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    384     // need to go ahead and round if we're really close to the next integer value.
    385     result += result < 0 ? -0.01 : +0.01;
    386 
    387     if (result > SHRT_MAX || result < SHRT_MIN)
    388         return 0;
    389     return static_cast<short>(result);
    390 }
    391 
    392 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
    393 {
    394     double result = computeLengthDouble(style, rootStyle, multiplier);
    395 
    396     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
    397     // need to go ahead and round if we're really close to the next integer value.
    398     result += result < 0 ? -0.01 : +0.01;
    399 
    400     if (result > SHRT_MAX || result < SHRT_MIN)
    401         return 0;
    402     return static_cast<short>(result);
    403 }
    404 
    405 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize)
    406 {
    407     return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize));
    408 }
    409 
    410 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
    411 {
    412     return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    413 }
    414 
    415 double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
    416 {
    417     unsigned short type = primitiveType();
    418 
    419     // We do not apply the zoom factor when we are computing the value of the font-size property.  The zooming
    420     // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
    421     // as well as enforcing the implicit "smart minimum."  In addition the CSS property text-size-adjust is used to
    422     // prevent text from zooming at all.  Therefore we will not apply the zoom here if we are computing font-size.
    423     bool applyZoomMultiplier = !computingFontSize;
    424 
    425     double factor = 1.0;
    426     switch (type) {
    427         case CSS_EMS:
    428             applyZoomMultiplier = false;
    429             factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
    430             break;
    431         case CSS_EXS:
    432             // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
    433             // We really need to compute EX using fontMetrics for the original specifiedSize and not use
    434             // our actual constructed rendering font.
    435             applyZoomMultiplier = false;
    436             factor = style->font().xHeight();
    437             break;
    438         case CSS_REMS:
    439             applyZoomMultiplier = false;
    440             factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
    441             break;
    442         case CSS_PX:
    443             break;
    444         case CSS_CM:
    445             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
    446             break;
    447         case CSS_MM:
    448             factor = cssPixelsPerInch / 25.4;
    449             break;
    450         case CSS_IN:
    451             factor = cssPixelsPerInch;
    452             break;
    453         case CSS_PT:
    454             factor = cssPixelsPerInch / 72.0;
    455             break;
    456         case CSS_PC:
    457             // 1 pc == 12 pt
    458             factor = cssPixelsPerInch * 12.0 / 72.0;
    459             break;
    460         default:
    461             return -1.0;
    462     }
    463 
    464     double result = getDoubleValue() * factor;
    465     if (!applyZoomMultiplier || multiplier == 1.0)
    466         return result;
    467 
    468     // Any original result that was >= 1 should not be allowed to fall below 1.  This keeps border lines from
    469     // vanishing.
    470     double zoomedResult = result * multiplier;
    471     if (result >= 1.0)
    472         zoomedResult = max(1.0, zoomedResult);
    473     return zoomedResult;
    474 }
    475 
    476 void CSSPrimitiveValue::setFloatValue(unsigned short unitType, double floatValue, ExceptionCode& ec)
    477 {
    478     ec = 0;
    479 
    480     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) {
    481         ec = INVALID_ACCESS_ERR;
    482         return;
    483     }
    484 
    485     cleanup();
    486 
    487     //if(m_type > CSS_DIMENSION) throw DOMException(INVALID_ACCESS_ERR);
    488     m_value.num = floatValue;
    489     m_type = unitType;
    490 }
    491 
    492 static double scaleFactorForConversion(unsigned short unitType)
    493 {
    494     double factor = 1.0;
    495     switch (unitType) {
    496         case CSSPrimitiveValue::CSS_PX:
    497             break;
    498         case CSSPrimitiveValue::CSS_CM:
    499             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
    500             break;
    501         case CSSPrimitiveValue::CSS_MM:
    502             factor = cssPixelsPerInch / 25.4;
    503             break;
    504         case CSSPrimitiveValue::CSS_IN:
    505             factor = cssPixelsPerInch;
    506             break;
    507         case CSSPrimitiveValue::CSS_PT:
    508             factor = cssPixelsPerInch / 72.0;
    509             break;
    510         case CSSPrimitiveValue::CSS_PC:
    511             factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
    512             break;
    513         default:
    514             break;
    515     }
    516 
    517     return factor;
    518 }
    519 
    520 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec)
    521 {
    522     ec = 0;
    523     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) {
    524         ec = INVALID_ACCESS_ERR;
    525         return 0.0;
    526     }
    527 
    528     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
    529         return m_value.num;
    530 
    531     double convertedValue = m_value.num;
    532 
    533     // First convert the value from m_type into CSSPixels
    534     double factor = scaleFactorForConversion(m_type);
    535     convertedValue *= factor;
    536 
    537     // Now convert from CSSPixels to the specified unitType
    538     factor = scaleFactorForConversion(unitType);
    539     convertedValue /= factor;
    540 
    541     return convertedValue;
    542 }
    543 
    544 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType)
    545 {
    546     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION)
    547         return 0;
    548 
    549     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
    550         return m_value.num;
    551 
    552     double convertedValue = m_value.num;
    553 
    554     // First convert the value from m_type into CSSPixels
    555     double factor = scaleFactorForConversion(m_type);
    556     convertedValue *= factor;
    557 
    558     // Now convert from CSSPixels to the specified unitType
    559     factor = scaleFactorForConversion(unitType);
    560     convertedValue /= factor;
    561 
    562     return convertedValue;
    563 }
    564 
    565 
    566 void CSSPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode& ec)
    567 {
    568     ec = 0;
    569 
    570     if (m_type < CSS_STRING || m_type > CSS_ATTR || stringType < CSS_STRING || stringType > CSS_ATTR) {
    571         ec = INVALID_ACCESS_ERR;
    572         return;
    573     }
    574 
    575     cleanup();
    576 
    577     if (stringType != CSS_IDENT) {
    578         m_value.string = stringValue.impl();
    579         m_value.string->ref();
    580         m_type = stringType;
    581     }
    582     // FIXME: parse ident
    583 }
    584 
    585 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const
    586 {
    587     ec = 0;
    588     switch (m_type) {
    589         case CSS_STRING:
    590         case CSS_ATTR:
    591         case CSS_URI:
    592         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
    593             return m_value.string;
    594         case CSS_IDENT:
    595             return valueOrPropertyName(m_value.ident);
    596         default:
    597             ec = INVALID_ACCESS_ERR;
    598             break;
    599     }
    600 
    601     return String();
    602 }
    603 
    604 String CSSPrimitiveValue::getStringValue() const
    605 {
    606     switch (m_type) {
    607         case CSS_STRING:
    608         case CSS_ATTR:
    609         case CSS_URI:
    610         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
    611              return m_value.string;
    612         case CSS_IDENT:
    613             return valueOrPropertyName(m_value.ident);
    614         default:
    615             break;
    616     }
    617 
    618     return String();
    619 }
    620 
    621 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const
    622 {
    623     ec = 0;
    624     if (m_type != CSS_COUNTER) {
    625         ec = INVALID_ACCESS_ERR;
    626         return 0;
    627     }
    628 
    629     return m_value.counter;
    630 }
    631 
    632 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const
    633 {
    634     ec = 0;
    635     if (m_type != CSS_RECT) {
    636         ec = INVALID_ACCESS_ERR;
    637         return 0;
    638     }
    639 
    640     return m_value.rect;
    641 }
    642 
    643 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const
    644 {
    645     ec = 0;
    646     if (m_type != CSS_RGBCOLOR) {
    647         ec = INVALID_ACCESS_ERR;
    648         return 0;
    649     }
    650 
    651     // FIMXE: This should not return a new object for each invocation.
    652     return RGBColor::create(m_value.rgbcolor);
    653 }
    654 
    655 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const
    656 {
    657     ec = 0;
    658     if (m_type != CSS_PAIR) {
    659         ec = INVALID_ACCESS_ERR;
    660         return 0;
    661     }
    662 
    663     return m_value.pair;
    664 }
    665 
    666 unsigned short CSSPrimitiveValue::cssValueType() const
    667 {
    668     return CSS_PRIMITIVE_VALUE;
    669 }
    670 
    671 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/)
    672 {
    673     // FIXME
    674     return false;
    675 }
    676 
    677 int CSSPrimitiveValue::getIdent()
    678 {
    679     if (m_type != CSS_IDENT)
    680         return 0;
    681     return m_value.ident;
    682 }
    683 
    684 String CSSPrimitiveValue::cssText() const
    685 {
    686     // FIXME: return the original value instead of a generated one (e.g. color
    687     // name if it was specified) - check what spec says about this
    688     String text;
    689     switch (m_type) {
    690         case CSS_UNKNOWN:
    691             // FIXME
    692             break;
    693         case CSS_NUMBER:
    694         case CSS_PARSER_INTEGER:
    695             text = String::number(m_value.num);
    696             break;
    697         case CSS_PERCENTAGE:
    698             text = String::format("%.6lg%%", m_value.num);
    699             break;
    700         case CSS_EMS:
    701             text = String::format("%.6lgem", m_value.num);
    702             break;
    703         case CSS_EXS:
    704             text = String::format("%.6lgex", m_value.num);
    705             break;
    706         case CSS_REMS:
    707             text = String::format("%.6lgrem", m_value.num);
    708             break;
    709         case CSS_PX:
    710             text = String::format("%.6lgpx", m_value.num);
    711             break;
    712         case CSS_CM:
    713             text = String::format("%.6lgcm", m_value.num);
    714             break;
    715         case CSS_MM:
    716             text = String::format("%.6lgmm", m_value.num);
    717             break;
    718         case CSS_IN:
    719             text = String::format("%.6lgin", m_value.num);
    720             break;
    721         case CSS_PT:
    722             text = String::format("%.6lgpt", m_value.num);
    723             break;
    724         case CSS_PC:
    725             text = String::format("%.6lgpc", m_value.num);
    726             break;
    727         case CSS_DEG:
    728             text = String::format("%.6lgdeg", m_value.num);
    729             break;
    730         case CSS_RAD:
    731             text = String::format("%.6lgrad", m_value.num);
    732             break;
    733         case CSS_GRAD:
    734             text = String::format("%.6lggrad", m_value.num);
    735             break;
    736         case CSS_MS:
    737             text = String::format("%.6lgms", m_value.num);
    738             break;
    739         case CSS_S:
    740             text = String::format("%.6lgs", m_value.num);
    741             break;
    742         case CSS_HZ:
    743             text = String::format("%.6lghz", m_value.num);
    744             break;
    745         case CSS_KHZ:
    746             text = String::format("%.6lgkhz", m_value.num);
    747             break;
    748         case CSS_TURN:
    749             text = String::format("%.6lgturn", m_value.num);
    750             break;
    751         case CSS_DIMENSION:
    752             // FIXME
    753             break;
    754         case CSS_STRING:
    755             text = quoteStringIfNeeded(m_value.string);
    756             break;
    757         case CSS_URI:
    758             text = "url(" + quoteURLIfNeeded(m_value.string) + ")";
    759             break;
    760         case CSS_IDENT:
    761             text = valueOrPropertyName(m_value.ident);
    762             break;
    763         case CSS_ATTR: {
    764             DEFINE_STATIC_LOCAL(const String, attrParen, ("attr("));
    765 
    766             Vector<UChar> result;
    767             result.reserveInitialCapacity(6 + m_value.string->length());
    768 
    769             append(result, attrParen);
    770             append(result, m_value.string);
    771             result.uncheckedAppend(')');
    772 
    773             return String::adopt(result);
    774         }
    775         case CSS_COUNTER:
    776             text = "counter(";
    777             text += String::number(m_value.num);
    778             text += ")";
    779             // FIXME: Add list-style and separator
    780             break;
    781         case CSS_RECT: {
    782             DEFINE_STATIC_LOCAL(const String, rectParen, ("rect("));
    783 
    784             Rect* rectVal = getRectValue();
    785             Vector<UChar> result;
    786             result.reserveInitialCapacity(32);
    787             append(result, rectParen);
    788 
    789             append(result, rectVal->top()->cssText());
    790             result.append(' ');
    791 
    792             append(result, rectVal->right()->cssText());
    793             result.append(' ');
    794 
    795             append(result, rectVal->bottom()->cssText());
    796             result.append(' ');
    797 
    798             append(result, rectVal->left()->cssText());
    799             result.append(')');
    800 
    801             return String::adopt(result);
    802         }
    803         case CSS_RGBCOLOR:
    804         case CSS_PARSER_HEXCOLOR: {
    805             DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
    806             DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb("));
    807             DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
    808 
    809             RGBA32 rgbColor = m_value.rgbcolor;
    810             if (m_type == CSS_PARSER_HEXCOLOR)
    811                 Color::parseHexColor(m_value.string, rgbColor);
    812             Color color(rgbColor);
    813 
    814             Vector<UChar> result;
    815             result.reserveInitialCapacity(32);
    816             if (color.hasAlpha())
    817                 append(result, rgbaParen);
    818             else
    819                 append(result, rgbParen);
    820 
    821             appendNumber(result, static_cast<unsigned char>(color.red()));
    822             append(result, commaSpace);
    823 
    824             appendNumber(result, static_cast<unsigned char>(color.green()));
    825             append(result, commaSpace);
    826 
    827             appendNumber(result, static_cast<unsigned char>(color.blue()));
    828             if (color.hasAlpha()) {
    829                 append(result, commaSpace);
    830                 append(result, String::number(static_cast<float>(color.alpha()) / 256.0f));
    831             }
    832 
    833             result.append(')');
    834             return String::adopt(result);
    835         }
    836         case CSS_PAIR:
    837             text = m_value.pair->first()->cssText();
    838             text += " ";
    839             text += m_value.pair->second()->cssText();
    840             break;
    841 #if ENABLE(DASHBOARD_SUPPORT)
    842         case CSS_DASHBOARD_REGION:
    843             for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) {
    844                 if (!text.isEmpty())
    845                     text.append(' ');
    846                 text += "dashboard-region(";
    847                 text += region->m_label;
    848                 if (region->m_isCircle)
    849                     text += " circle";
    850                 else if (region->m_isRectangle)
    851                     text += " rectangle";
    852                 else
    853                     break;
    854                 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) {
    855                     ASSERT(region->right()->m_type == CSS_IDENT);
    856                     ASSERT(region->bottom()->m_type == CSS_IDENT);
    857                     ASSERT(region->left()->m_type == CSS_IDENT);
    858                     ASSERT(region->right()->getIdent() == CSSValueInvalid);
    859                     ASSERT(region->bottom()->getIdent() == CSSValueInvalid);
    860                     ASSERT(region->left()->getIdent() == CSSValueInvalid);
    861                 } else {
    862                     text.append(' ');
    863                     text += region->top()->cssText() + " ";
    864                     text += region->right()->cssText() + " ";
    865                     text += region->bottom()->cssText() + " ";
    866                     text += region->left()->cssText();
    867                 }
    868                 text += ")";
    869             }
    870             break;
    871 #endif
    872         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
    873             text = "-webkit-var(";
    874             text += m_value.string;
    875             text += ")";
    876             break;
    877         case CSS_PARSER_OPERATOR: {
    878             char c = static_cast<char>(m_value.ident);
    879             text = String(&c, 1U);
    880             break;
    881         }
    882         case CSS_PARSER_IDENTIFIER:
    883             text = quoteStringIfNeeded(m_value.string);
    884             break;
    885     }
    886     return text;
    887 }
    888 
    889 CSSParserValue CSSPrimitiveValue::parserValue() const
    890 {
    891     // We only have to handle a subset of types.
    892     CSSParserValue value;
    893     value.id = 0;
    894     value.isInt = false;
    895     value.unit = CSSPrimitiveValue::CSS_IDENT;
    896     switch (m_type) {
    897         case CSS_NUMBER:
    898         case CSS_PERCENTAGE:
    899         case CSS_EMS:
    900         case CSS_EXS:
    901         case CSS_REMS:
    902         case CSS_PX:
    903         case CSS_CM:
    904         case CSS_MM:
    905         case CSS_IN:
    906         case CSS_PT:
    907         case CSS_PC:
    908         case CSS_DEG:
    909         case CSS_RAD:
    910         case CSS_GRAD:
    911         case CSS_MS:
    912         case CSS_S:
    913         case CSS_HZ:
    914         case CSS_KHZ:
    915         case CSS_DIMENSION:
    916         case CSS_TURN:
    917             value.fValue = m_value.num;
    918             value.unit = m_type;
    919             break;
    920         case CSS_STRING:
    921         case CSS_URI:
    922         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
    923         case CSS_PARSER_HEXCOLOR:
    924             value.string.characters = const_cast<UChar*>(m_value.string->characters());
    925             value.string.length = m_value.string->length();
    926             value.unit = m_type;
    927             break;
    928         case CSS_IDENT: {
    929             value.id = m_value.ident;
    930             String name = valueOrPropertyName(m_value.ident);
    931             value.string.characters = const_cast<UChar*>(name.characters());
    932             value.string.length = name.length();
    933             break;
    934         }
    935         case CSS_PARSER_OPERATOR:
    936             value.iValue = m_value.ident;
    937             value.unit = CSSParserValue::Operator;
    938             break;
    939         case CSS_PARSER_INTEGER:
    940             value.fValue = m_value.num;
    941             value.unit = CSSPrimitiveValue::CSS_NUMBER;
    942             value.isInt = true;
    943             break;
    944         case CSS_PARSER_IDENTIFIER:
    945             value.string.characters = const_cast<UChar*>(m_value.string->characters());
    946             value.string.length = m_value.string->length();
    947             value.unit = CSSPrimitiveValue::CSS_IDENT;
    948             break;
    949         case CSS_UNKNOWN:
    950         case CSS_ATTR:
    951         case CSS_COUNTER:
    952         case CSS_RECT:
    953         case CSS_RGBCOLOR:
    954         case CSS_PAIR:
    955 #if ENABLE(DASHBOARD_SUPPORT)
    956         case CSS_DASHBOARD_REGION:
    957 #endif
    958             ASSERT_NOT_REACHED();
    959             break;
    960     }
    961 
    962     return value;
    963 }
    964 
    965 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
    966 {
    967     if (m_type == CSS_URI)
    968         addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
    969 }
    970 
    971 } // namespace WebCore
    972