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, 2012 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 "core/css/CSSPrimitiveValue.h"
     23 
     24 #include "CSSPropertyNames.h"
     25 #include "CSSValueKeywords.h"
     26 #include "bindings/v8/ExceptionState.h"
     27 #include "core/css/CSSBasicShapes.h"
     28 #include "core/css/CSSCalculationValue.h"
     29 #include "core/css/CSSHelper.h"
     30 #include "core/css/CSSParser.h"
     31 #include "core/css/Counter.h"
     32 #include "core/css/Pair.h"
     33 #include "core/css/RGBColor.h"
     34 #include "core/css/Rect.h"
     35 #include "core/css/StyleSheetContents.h"
     36 #include "core/dom/ExceptionCode.h"
     37 #include "core/dom/Node.h"
     38 #include "core/platform/LayoutUnit.h"
     39 #include "core/platform/graphics/Color.h"
     40 #include "core/rendering/style/RenderStyle.h"
     41 #include "wtf/DecimalNumber.h"
     42 #include "wtf/StdLibExtras.h"
     43 #include "wtf/text/StringBuffer.h"
     44 #include "wtf/text/StringBuilder.h"
     45 
     46 using namespace WTF;
     47 
     48 namespace WebCore {
     49 
     50 // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing.
     51 // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max.
     52 const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2;
     53 const int minValueForCssLength = INT_MIN / kFixedPointDenominator + 2;
     54 
     55 static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitTypes unitType)
     56 {
     57     switch (unitType) {
     58     case CSSPrimitiveValue::CSS_CALC:
     59     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
     60     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
     61     case CSSPrimitiveValue::CSS_CM:
     62     case CSSPrimitiveValue::CSS_DEG:
     63     case CSSPrimitiveValue::CSS_DIMENSION:
     64     case CSSPrimitiveValue::CSS_DPPX:
     65     case CSSPrimitiveValue::CSS_DPI:
     66     case CSSPrimitiveValue::CSS_DPCM:
     67     case CSSPrimitiveValue::CSS_EMS:
     68     case CSSPrimitiveValue::CSS_EXS:
     69     case CSSPrimitiveValue::CSS_GRAD:
     70     case CSSPrimitiveValue::CSS_HZ:
     71     case CSSPrimitiveValue::CSS_IN:
     72     case CSSPrimitiveValue::CSS_KHZ:
     73     case CSSPrimitiveValue::CSS_MM:
     74     case CSSPrimitiveValue::CSS_MS:
     75     case CSSPrimitiveValue::CSS_NUMBER:
     76     case CSSPrimitiveValue::CSS_PERCENTAGE:
     77     case CSSPrimitiveValue::CSS_PC:
     78     case CSSPrimitiveValue::CSS_PT:
     79     case CSSPrimitiveValue::CSS_PX:
     80     case CSSPrimitiveValue::CSS_RAD:
     81     case CSSPrimitiveValue::CSS_REMS:
     82     case CSSPrimitiveValue::CSS_CHS:
     83     case CSSPrimitiveValue::CSS_S:
     84     case CSSPrimitiveValue::CSS_TURN:
     85     case CSSPrimitiveValue::CSS_VW:
     86     case CSSPrimitiveValue::CSS_VH:
     87     case CSSPrimitiveValue::CSS_VMIN:
     88     case CSSPrimitiveValue::CSS_VMAX:
     89     case CSSPrimitiveValue::CSS_FR:
     90         return true;
     91     case CSSPrimitiveValue::CSS_ATTR:
     92     case CSSPrimitiveValue::CSS_COUNTER:
     93     case CSSPrimitiveValue::CSS_COUNTER_NAME:
     94     case CSSPrimitiveValue::CSS_IDENT:
     95     case CSSPrimitiveValue::CSS_PROPERTY_ID:
     96     case CSSPrimitiveValue::CSS_VALUE_ID:
     97     case CSSPrimitiveValue::CSS_PAIR:
     98     case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
     99     case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
    100     case CSSPrimitiveValue::CSS_PARSER_INTEGER:
    101     case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
    102     case CSSPrimitiveValue::CSS_RECT:
    103     case CSSPrimitiveValue::CSS_QUAD:
    104     case CSSPrimitiveValue::CSS_RGBCOLOR:
    105     case CSSPrimitiveValue::CSS_SHAPE:
    106     case CSSPrimitiveValue::CSS_STRING:
    107     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
    108     case CSSPrimitiveValue::CSS_UNKNOWN:
    109     case CSSPrimitiveValue::CSS_URI:
    110     case CSSPrimitiveValue::CSS_VARIABLE_NAME:
    111         return false;
    112     }
    113 
    114     ASSERT_NOT_REACHED();
    115     return false;
    116 }
    117 
    118 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitTypes type)
    119 {
    120     // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
    121     // between CSS_PX and relative lengths (see cssPixelsPerInch comment in core/css/CSSHelper.h for the topic treatment).
    122     switch (type) {
    123     case CSS_NUMBER:
    124         return CSSPrimitiveValue::UNumber;
    125     case CSS_PERCENTAGE:
    126         return CSSPrimitiveValue::UPercent;
    127     case CSS_PX:
    128     case CSS_CM:
    129     case CSS_MM:
    130     case CSS_IN:
    131     case CSS_PT:
    132     case CSS_PC:
    133         return CSSPrimitiveValue::ULength;
    134     case CSS_MS:
    135     case CSS_S:
    136         return CSSPrimitiveValue::UTime;
    137     case CSS_DEG:
    138     case CSS_RAD:
    139     case CSS_GRAD:
    140     case CSS_TURN:
    141         return CSSPrimitiveValue::UAngle;
    142     case CSS_HZ:
    143     case CSS_KHZ:
    144         return CSSPrimitiveValue::UFrequency;
    145     case CSS_VW:
    146     case CSS_VH:
    147     case CSS_VMIN:
    148     case CSS_VMAX:
    149         return CSSPrimitiveValue::UViewportPercentageLength;
    150     case CSS_DPPX:
    151     case CSS_DPI:
    152     case CSS_DPCM:
    153         return CSSPrimitiveValue::UResolution;
    154     default:
    155         return CSSPrimitiveValue::UOther;
    156     }
    157 }
    158 
    159 bool CSSPrimitiveValue::colorIsDerivedFromElement() const
    160 {
    161     int valueID = getValueID();
    162     switch (valueID) {
    163     case CSSValueWebkitText:
    164     case CSSValueWebkitLink:
    165     case CSSValueWebkitActivelink:
    166     case CSSValueCurrentcolor:
    167         return true;
    168     default:
    169         return false;
    170     }
    171 }
    172 
    173 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
    174 static CSSTextCache& cssTextCache()
    175 {
    176     DEFINE_STATIC_LOCAL(CSSTextCache, cache, ());
    177     return cache;
    178 }
    179 
    180 unsigned short CSSPrimitiveValue::primitiveType() const
    181 {
    182     if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID)
    183         return CSS_IDENT;
    184 
    185     if (m_primitiveUnitType != CSS_CALC)
    186         return m_primitiveUnitType;
    187 
    188     switch (m_value.calc->category()) {
    189     case CalcNumber:
    190         return CSS_NUMBER;
    191     case CalcPercent:
    192         return CSS_PERCENTAGE;
    193     case CalcLength:
    194         return CSS_PX;
    195     case CalcPercentNumber:
    196         return CSS_CALC_PERCENTAGE_WITH_NUMBER;
    197     case CalcPercentLength:
    198         return CSS_CALC_PERCENTAGE_WITH_LENGTH;
    199     case CalcVariable:
    200         return CSS_UNKNOWN; // The type of a calculation containing a variable cannot be known until the value of the variable is determined.
    201     case CalcOther:
    202         return CSS_UNKNOWN;
    203     }
    204     return CSS_UNKNOWN;
    205 }
    206 
    207 static const AtomicString& propertyName(CSSPropertyID propertyID)
    208 {
    209     ASSERT_ARG(propertyID, propertyID >= 0);
    210     ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties));
    211 
    212     if (propertyID < 0)
    213         return nullAtom;
    214 
    215     return getPropertyNameAtomicString(propertyID);
    216 }
    217 
    218 static const AtomicString& valueName(CSSValueID valueID)
    219 {
    220     ASSERT_ARG(valueID, valueID >= 0);
    221     ASSERT_ARG(valueID, valueID < numCSSValueKeywords);
    222 
    223     if (valueID < 0)
    224         return nullAtom;
    225 
    226     static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally.
    227     AtomicString& keywordString = keywordStrings[valueID];
    228     if (keywordString.isNull())
    229         keywordString = getValueName(valueID);
    230     return keywordString;
    231 }
    232 
    233 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
    234     : CSSValue(PrimitiveClass)
    235 {
    236     m_primitiveUnitType = CSS_VALUE_ID;
    237     m_value.valueID = valueID;
    238 }
    239 
    240 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
    241     : CSSValue(PrimitiveClass)
    242 {
    243     m_primitiveUnitType = CSS_PROPERTY_ID;
    244     m_value.propertyID = propertyID;
    245 }
    246 
    247 CSSPrimitiveValue::CSSPrimitiveValue(int parserOperator)
    248     : CSSValue(PrimitiveClass)
    249 {
    250     m_primitiveUnitType = CSS_PARSER_OPERATOR;
    251     m_value.parserOperator = parserOperator;
    252 }
    253 
    254 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
    255     : CSSValue(PrimitiveClass)
    256 {
    257     m_primitiveUnitType = type;
    258     ASSERT(std::isfinite(num));
    259     m_value.num = num;
    260 }
    261 
    262 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
    263     : CSSValue(PrimitiveClass)
    264 {
    265     m_primitiveUnitType = type;
    266     if ((m_value.string = str.impl()))
    267         m_value.string->ref();
    268 }
    269 
    270 
    271 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
    272     : CSSValue(PrimitiveClass)
    273 {
    274     m_primitiveUnitType = CSS_RGBCOLOR;
    275     m_value.rgbcolor = color;
    276 }
    277 
    278 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
    279     : CSSValue(PrimitiveClass)
    280 {
    281     switch (length.type()) {
    282         case Auto:
    283             m_primitiveUnitType = CSS_VALUE_ID;
    284             m_value.valueID = CSSValueAuto;
    285             break;
    286         case WebCore::Fixed:
    287             m_primitiveUnitType = CSS_PX;
    288             m_value.num = length.value();
    289             break;
    290         case Intrinsic:
    291             m_primitiveUnitType = CSS_VALUE_ID;
    292             m_value.valueID = CSSValueIntrinsic;
    293             break;
    294         case MinIntrinsic:
    295             m_primitiveUnitType = CSS_VALUE_ID;
    296             m_value.valueID = CSSValueMinIntrinsic;
    297             break;
    298         case MinContent:
    299             m_primitiveUnitType = CSS_VALUE_ID;
    300             m_value.valueID = CSSValueMinContent;
    301             break;
    302         case MaxContent:
    303             m_primitiveUnitType = CSS_VALUE_ID;
    304             m_value.valueID = CSSValueMaxContent;
    305             break;
    306         case FillAvailable:
    307             m_primitiveUnitType = CSS_VALUE_ID;
    308             m_value.valueID = CSSValueWebkitFillAvailable;
    309             break;
    310         case FitContent:
    311             m_primitiveUnitType = CSS_VALUE_ID;
    312             m_value.valueID = CSSValueWebkitFitContent;
    313             break;
    314         case ExtendToZoom:
    315             m_primitiveUnitType = CSS_VALUE_ID;
    316             m_value.valueID = CSSValueInternalExtendToZoom;
    317             break;
    318         case Percent:
    319             m_primitiveUnitType = CSS_PERCENTAGE;
    320             ASSERT(std::isfinite(length.percent()));
    321             m_value.num = length.percent();
    322             break;
    323         case ViewportPercentageWidth:
    324             m_primitiveUnitType = CSS_VW;
    325             m_value.num = length.viewportPercentageLength();
    326             break;
    327         case ViewportPercentageHeight:
    328             m_primitiveUnitType = CSS_VH;
    329             m_value.num = length.viewportPercentageLength();
    330             break;
    331         case ViewportPercentageMin:
    332             m_primitiveUnitType = CSS_VMIN;
    333             m_value.num = length.viewportPercentageLength();
    334             break;
    335         case ViewportPercentageMax:
    336             m_primitiveUnitType = CSS_VMAX;
    337             m_value.num = length.viewportPercentageLength();
    338             break;
    339         case Calculated:
    340         case Relative:
    341         case Undefined:
    342             ASSERT_NOT_REACHED();
    343             break;
    344     }
    345 }
    346 
    347 void CSSPrimitiveValue::init(PassRefPtr<Counter> c)
    348 {
    349     m_primitiveUnitType = CSS_COUNTER;
    350     m_hasCachedCSSText = false;
    351     m_value.counter = c.leakRef();
    352 }
    353 
    354 void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
    355 {
    356     m_primitiveUnitType = CSS_RECT;
    357     m_hasCachedCSSText = false;
    358     m_value.rect = r.leakRef();
    359 }
    360 
    361 void CSSPrimitiveValue::init(PassRefPtr<Quad> quad)
    362 {
    363     m_primitiveUnitType = CSS_QUAD;
    364     m_hasCachedCSSText = false;
    365     m_value.quad = quad.leakRef();
    366 }
    367 
    368 void CSSPrimitiveValue::init(PassRefPtr<Pair> p)
    369 {
    370     m_primitiveUnitType = CSS_PAIR;
    371     m_hasCachedCSSText = false;
    372     m_value.pair = p.leakRef();
    373 }
    374 
    375 void CSSPrimitiveValue::init(PassRefPtr<CSSCalcValue> c)
    376 {
    377     m_primitiveUnitType = CSS_CALC;
    378     m_hasCachedCSSText = false;
    379     m_value.calc = c.leakRef();
    380 }
    381 
    382 void CSSPrimitiveValue::init(PassRefPtr<CSSBasicShape> shape)
    383 {
    384     m_primitiveUnitType = CSS_SHAPE;
    385     m_hasCachedCSSText = false;
    386     m_value.shape = shape.leakRef();
    387 }
    388 
    389 CSSPrimitiveValue::~CSSPrimitiveValue()
    390 {
    391     cleanup();
    392 }
    393 
    394 void CSSPrimitiveValue::cleanup()
    395 {
    396     switch (static_cast<UnitTypes>(m_primitiveUnitType)) {
    397     case CSS_STRING:
    398     case CSS_URI:
    399     case CSS_ATTR:
    400     case CSS_COUNTER_NAME:
    401     case CSS_VARIABLE_NAME:
    402     case CSS_PARSER_HEXCOLOR:
    403         if (m_value.string)
    404             m_value.string->deref();
    405         break;
    406     case CSS_COUNTER:
    407         m_value.counter->deref();
    408         break;
    409     case CSS_RECT:
    410         m_value.rect->deref();
    411         break;
    412     case CSS_QUAD:
    413         m_value.quad->deref();
    414         break;
    415     case CSS_PAIR:
    416         m_value.pair->deref();
    417         break;
    418     case CSS_CALC:
    419         m_value.calc->deref();
    420         break;
    421     case CSS_CALC_PERCENTAGE_WITH_NUMBER:
    422     case CSS_CALC_PERCENTAGE_WITH_LENGTH:
    423         ASSERT_NOT_REACHED();
    424         break;
    425     case CSS_SHAPE:
    426         m_value.shape->deref();
    427         break;
    428     case CSS_NUMBER:
    429     case CSS_PARSER_INTEGER:
    430     case CSS_PERCENTAGE:
    431     case CSS_EMS:
    432     case CSS_EXS:
    433     case CSS_REMS:
    434     case CSS_CHS:
    435     case CSS_PX:
    436     case CSS_CM:
    437     case CSS_MM:
    438     case CSS_IN:
    439     case CSS_PT:
    440     case CSS_PC:
    441     case CSS_DEG:
    442     case CSS_RAD:
    443     case CSS_GRAD:
    444     case CSS_MS:
    445     case CSS_S:
    446     case CSS_HZ:
    447     case CSS_KHZ:
    448     case CSS_TURN:
    449     case CSS_VW:
    450     case CSS_VH:
    451     case CSS_VMIN:
    452     case CSS_VMAX:
    453     case CSS_DPPX:
    454     case CSS_DPI:
    455     case CSS_DPCM:
    456     case CSS_FR:
    457     case CSS_IDENT:
    458     case CSS_RGBCOLOR:
    459     case CSS_DIMENSION:
    460     case CSS_UNKNOWN:
    461     case CSS_UNICODE_RANGE:
    462     case CSS_PARSER_OPERATOR:
    463     case CSS_PARSER_IDENTIFIER:
    464     case CSS_PROPERTY_ID:
    465     case CSS_VALUE_ID:
    466         break;
    467     }
    468     m_primitiveUnitType = 0;
    469     if (m_hasCachedCSSText) {
    470         cssTextCache().remove(this);
    471         m_hasCachedCSSText = false;
    472     }
    473 }
    474 
    475 double CSSPrimitiveValue::computeDegrees()
    476 {
    477     switch (m_primitiveUnitType) {
    478     case CSS_DEG:
    479         return getDoubleValue();
    480     case CSS_RAD:
    481         return rad2deg(getDoubleValue());
    482     case CSS_GRAD:
    483         return grad2deg(getDoubleValue());
    484     case CSS_TURN:
    485         return turn2deg(getDoubleValue());
    486     default:
    487         ASSERT_NOT_REACHED();
    488         return 0;
    489     }
    490 }
    491 
    492 template<> int CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    493 {
    494     return roundForImpreciseConversion<int>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    495 }
    496 
    497 template<> unsigned CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    498 {
    499     return roundForImpreciseConversion<unsigned>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    500 }
    501 
    502 template<> Length CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    503 {
    504     return Length(clampTo<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize), minValueForCssLength, maxValueForCssLength), Fixed);
    505 }
    506 
    507 template<> short CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    508 {
    509     return roundForImpreciseConversion<short>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    510 }
    511 
    512 template<> unsigned short CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    513 {
    514     return roundForImpreciseConversion<unsigned short>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    515 }
    516 
    517 template<> float CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    518 {
    519     return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
    520 }
    521 
    522 template<> double CSSPrimitiveValue::computeLength(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    523 {
    524     return computeLengthDouble(style, rootStyle, multiplier, computingFontSize);
    525 }
    526 
    527 double CSSPrimitiveValue::computeLengthDouble(const RenderStyle* style, const RenderStyle* rootStyle, float multiplier, bool computingFontSize)
    528 {
    529     if (m_primitiveUnitType == CSS_CALC)
    530         // The multiplier and factor is applied to each value in the calc expression individually
    531         return m_value.calc->computeLengthPx(style, rootStyle, multiplier, computingFontSize);
    532 
    533     double factor;
    534 
    535     switch (primitiveType()) {
    536         case CSS_EMS:
    537             factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
    538             break;
    539         case CSS_EXS:
    540             // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
    541             // We really need to compute EX using fontMetrics for the original specifiedSize and not use
    542             // our actual constructed rendering font.
    543             if (style->fontMetrics().hasXHeight())
    544                 factor = style->fontMetrics().xHeight();
    545             else
    546                 factor = (computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize()) / 2.0;
    547             break;
    548         case CSS_REMS:
    549             if (rootStyle)
    550                 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
    551             else
    552                 factor = 1.0;
    553             break;
    554         case CSS_CHS:
    555             factor = style->fontMetrics().zeroWidth();
    556             break;
    557         case CSS_PX:
    558             factor = 1.0;
    559             break;
    560         case CSS_CM:
    561             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
    562             break;
    563         case CSS_MM:
    564             factor = cssPixelsPerInch / 25.4;
    565             break;
    566         case CSS_IN:
    567             factor = cssPixelsPerInch;
    568             break;
    569         case CSS_PT:
    570             factor = cssPixelsPerInch / 72.0;
    571             break;
    572         case CSS_PC:
    573             // 1 pc == 12 pt
    574             factor = cssPixelsPerInch * 12.0 / 72.0;
    575             break;
    576         case CSS_CALC_PERCENTAGE_WITH_LENGTH:
    577         case CSS_CALC_PERCENTAGE_WITH_NUMBER:
    578             ASSERT_NOT_REACHED();
    579             return -1.0;
    580         default:
    581             ASSERT_NOT_REACHED();
    582             return -1.0;
    583     }
    584 
    585     // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
    586     // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
    587     // as well as enforcing the implicit "smart minimum."
    588     double result = getDoubleValue() * factor;
    589     if (computingFontSize || isFontRelativeLength())
    590         return result;
    591 
    592     return result * multiplier;
    593 }
    594 
    595 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionState& es)
    596 {
    597     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
    598     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
    599     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
    600     es.throwDOMException(NoModificationAllowedError);
    601 }
    602 
    603 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(unsigned short unitType)
    604 {
    605     double factor = 1.0;
    606     // FIXME: the switch can be replaced by an array of scale factors.
    607     switch (unitType) {
    608     // These are "canonical" units in their respective categories.
    609     case CSS_PX:
    610     case CSS_DEG:
    611     case CSS_MS:
    612     case CSS_HZ:
    613         break;
    614     case CSS_CM:
    615         factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
    616         break;
    617     case CSS_DPCM:
    618         factor = 2.54 / cssPixelsPerInch; // (2.54 cm/in)
    619         break;
    620     case CSS_MM:
    621         factor = cssPixelsPerInch / 25.4;
    622         break;
    623     case CSS_IN:
    624         factor = cssPixelsPerInch;
    625         break;
    626     case CSS_DPI:
    627         factor = 1 / cssPixelsPerInch;
    628         break;
    629     case CSS_PT:
    630         factor = cssPixelsPerInch / 72.0;
    631         break;
    632     case CSS_PC:
    633         factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
    634         break;
    635     case CSS_RAD:
    636         factor = 180 / piDouble;
    637         break;
    638     case CSS_GRAD:
    639         factor = 0.9;
    640         break;
    641     case CSS_TURN:
    642         factor = 360;
    643         break;
    644     case CSS_S:
    645     case CSS_KHZ:
    646         factor = 1000;
    647         break;
    648     default:
    649         break;
    650     }
    651 
    652     return factor;
    653 }
    654 
    655 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionState& es) const
    656 {
    657     double result = 0;
    658     bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
    659     if (!success) {
    660         es.throwDOMException(InvalidAccessError);
    661         return 0.0;
    662     }
    663 
    664     return result;
    665 }
    666 
    667 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const
    668 {
    669     double result = 0;
    670     getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
    671     return result;
    672 }
    673 
    674 double CSSPrimitiveValue::getDoubleValue() const
    675 {
    676     return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue();
    677 }
    678 
    679 CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
    680 {
    681     // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit
    682     // in each category (based on unitflags).
    683     switch (category) {
    684     case UNumber:
    685         return CSS_NUMBER;
    686     case ULength:
    687         return CSS_PX;
    688     case UPercent:
    689         return CSS_UNKNOWN; // Cannot convert between numbers and percent.
    690     case UTime:
    691         return CSS_MS;
    692     case UAngle:
    693         return CSS_DEG;
    694     case UFrequency:
    695         return CSS_HZ;
    696     case UViewportPercentageLength:
    697         return CSS_UNKNOWN; // Cannot convert between numbers and relative lengths.
    698     case UResolution:
    699         return CSS_DPPX;
    700     default:
    701         return CSS_UNKNOWN;
    702     }
    703 }
    704 
    705 bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const
    706 {
    707     if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitTypes>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType))
    708         return false;
    709 
    710     UnitTypes sourceUnitType = static_cast<UnitTypes>(primitiveType());
    711     if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) {
    712         *result = getDoubleValue();
    713         return true;
    714     }
    715 
    716     UnitCategory sourceCategory = unitCategory(sourceUnitType);
    717     ASSERT(sourceCategory != UOther);
    718 
    719     UnitTypes targetUnitType = requestedUnitType;
    720     UnitCategory targetCategory = unitCategory(targetUnitType);
    721     ASSERT(targetCategory != UOther);
    722 
    723     // Cannot convert between unrelated unit categories if one of them is not UNumber.
    724     if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
    725         return false;
    726 
    727     if (targetCategory == UNumber) {
    728         // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
    729         targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
    730         if (targetUnitType == CSS_UNKNOWN)
    731             return false;
    732     }
    733 
    734     if (sourceUnitType == CSS_NUMBER) {
    735         // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode.
    736         sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
    737         if (sourceUnitType == CSS_UNKNOWN)
    738             return false;
    739     }
    740 
    741     double convertedValue = getDoubleValue();
    742 
    743     // First convert the value from m_primitiveUnitType to canonical type.
    744     double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
    745     convertedValue *= factor;
    746 
    747     // Now convert from canonical type to the target unitType.
    748     factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
    749     convertedValue /= factor;
    750 
    751     *result = convertedValue;
    752     return true;
    753 }
    754 
    755 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionState& es)
    756 {
    757     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
    758     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
    759     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
    760     es.throwDOMException(NoModificationAllowedError);
    761 }
    762 
    763 String CSSPrimitiveValue::getStringValue(ExceptionState& es) const
    764 {
    765     switch (m_primitiveUnitType) {
    766         case CSS_STRING:
    767         case CSS_ATTR:
    768         case CSS_URI:
    769         case CSS_VARIABLE_NAME:
    770             return m_value.string;
    771         case CSS_VALUE_ID:
    772             return valueName(m_value.valueID);
    773         case CSS_PROPERTY_ID:
    774             return propertyName(m_value.propertyID);
    775         default:
    776             es.throwDOMException(InvalidAccessError);
    777             break;
    778     }
    779 
    780     return String();
    781 }
    782 
    783 String CSSPrimitiveValue::getStringValue() const
    784 {
    785     switch (m_primitiveUnitType) {
    786         case CSS_STRING:
    787         case CSS_ATTR:
    788         case CSS_URI:
    789         case CSS_VARIABLE_NAME:
    790             return m_value.string;
    791         case CSS_VALUE_ID:
    792             return valueName(m_value.valueID);
    793         case CSS_PROPERTY_ID:
    794             return propertyName(m_value.propertyID);
    795         default:
    796             break;
    797     }
    798 
    799     return String();
    800 }
    801 
    802 Counter* CSSPrimitiveValue::getCounterValue(ExceptionState& es) const
    803 {
    804     if (m_primitiveUnitType != CSS_COUNTER) {
    805         es.throwDOMException(InvalidAccessError);
    806         return 0;
    807     }
    808 
    809     return m_value.counter;
    810 }
    811 
    812 Rect* CSSPrimitiveValue::getRectValue(ExceptionState& es) const
    813 {
    814     if (m_primitiveUnitType != CSS_RECT) {
    815         es.throwDOMException(InvalidAccessError);
    816         return 0;
    817     }
    818 
    819     return m_value.rect;
    820 }
    821 
    822 Quad* CSSPrimitiveValue::getQuadValue(ExceptionState& es) const
    823 {
    824     if (m_primitiveUnitType != CSS_QUAD) {
    825         es.throwDOMException(InvalidAccessError);
    826         return 0;
    827     }
    828 
    829     return m_value.quad;
    830 }
    831 
    832 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionState& es) const
    833 {
    834     if (m_primitiveUnitType != CSS_RGBCOLOR) {
    835         es.throwDOMException(InvalidAccessError);
    836         return 0;
    837     }
    838 
    839     // FIMXE: This should not return a new object for each invocation.
    840     return RGBColor::create(m_value.rgbcolor);
    841 }
    842 
    843 Pair* CSSPrimitiveValue::getPairValue(ExceptionState& es) const
    844 {
    845     if (m_primitiveUnitType != CSS_PAIR) {
    846         es.throwDOMException(InvalidAccessError);
    847         return 0;
    848     }
    849 
    850     return m_value.pair;
    851 }
    852 
    853 static String formatNumber(double number, const char* suffix, unsigned suffixLength)
    854 {
    855     DecimalNumber decimal(number);
    856 
    857     StringBuffer<LChar> buffer(decimal.bufferLengthForStringDecimal() + suffixLength);
    858     unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length());
    859     ASSERT(length + suffixLength == buffer.length());
    860 
    861     for (unsigned i = 0; i < suffixLength; ++i)
    862         buffer[length + i] = static_cast<LChar>(suffix[i]);
    863 
    864     return String::adopt(buffer);
    865 }
    866 
    867 template <unsigned characterCount>
    868 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount])
    869 {
    870     return formatNumber(number, characters, characterCount - 1);
    871 }
    872 
    873 String CSSPrimitiveValue::customCssText(CssTextFormattingFlags formattingFlag) const
    874 {
    875     // FIXME: return the original value instead of a generated one (e.g. color
    876     // name if it was specified) - check what spec says about this
    877 
    878     if (m_hasCachedCSSText) {
    879         ASSERT(cssTextCache().contains(this));
    880         return cssTextCache().get(this);
    881     }
    882 
    883     String text;
    884     switch (m_primitiveUnitType) {
    885         case CSS_UNKNOWN:
    886             // FIXME
    887             break;
    888         case CSS_NUMBER:
    889         case CSS_PARSER_INTEGER:
    890             text = formatNumber(m_value.num, "");
    891             break;
    892         case CSS_PERCENTAGE:
    893             text = formatNumber(m_value.num, "%");
    894             break;
    895         case CSS_EMS:
    896             text = formatNumber(m_value.num, "em");
    897             break;
    898         case CSS_EXS:
    899             text = formatNumber(m_value.num, "ex");
    900             break;
    901         case CSS_REMS:
    902             text = formatNumber(m_value.num, "rem");
    903             break;
    904         case CSS_CHS:
    905             text = formatNumber(m_value.num, "ch");
    906             break;
    907         case CSS_PX:
    908             text = formatNumber(m_value.num, "px");
    909             break;
    910         case CSS_CM:
    911             text = formatNumber(m_value.num, "cm");
    912             break;
    913         case CSS_DPPX:
    914             text = formatNumber(m_value.num, "dppx");
    915             break;
    916         case CSS_DPI:
    917             text = formatNumber(m_value.num, "dpi");
    918             break;
    919         case CSS_DPCM:
    920             text = formatNumber(m_value.num, "dpcm");
    921             break;
    922         case CSS_MM:
    923             text = formatNumber(m_value.num, "mm");
    924             break;
    925         case CSS_IN:
    926             text = formatNumber(m_value.num, "in");
    927             break;
    928         case CSS_PT:
    929             text = formatNumber(m_value.num, "pt");
    930             break;
    931         case CSS_PC:
    932             text = formatNumber(m_value.num, "pc");
    933             break;
    934         case CSS_DEG:
    935             text = formatNumber(m_value.num, "deg");
    936             break;
    937         case CSS_RAD:
    938             text = formatNumber(m_value.num, "rad");
    939             break;
    940         case CSS_GRAD:
    941             text = formatNumber(m_value.num, "grad");
    942             break;
    943         case CSS_MS:
    944             text = formatNumber(m_value.num, "ms");
    945             break;
    946         case CSS_S:
    947             text = formatNumber(m_value.num, "s");
    948             break;
    949         case CSS_HZ:
    950             text = formatNumber(m_value.num, "hz");
    951             break;
    952         case CSS_KHZ:
    953             text = formatNumber(m_value.num, "khz");
    954             break;
    955         case CSS_TURN:
    956             text = formatNumber(m_value.num, "turn");
    957             break;
    958         case CSS_DIMENSION:
    959             text = m_value.string;
    960             break;
    961         case CSS_STRING:
    962             text = formattingFlag == AlwaysQuoteCSSString ? quoteCSSString(m_value.string) : quoteCSSStringIfNeeded(m_value.string);
    963             break;
    964         case CSS_URI:
    965             text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
    966             break;
    967         case CSS_VALUE_ID:
    968             text = valueName(m_value.valueID);
    969             break;
    970         case CSS_PROPERTY_ID:
    971             text = propertyName(m_value.propertyID);
    972             break;
    973         case CSS_ATTR: {
    974             StringBuilder result;
    975             result.reserveCapacity(6 + m_value.string->length());
    976             result.appendLiteral("attr(");
    977             result.append(m_value.string);
    978             result.append(')');
    979 
    980             text = result.toString();
    981             break;
    982         }
    983         case CSS_COUNTER_NAME:
    984             text = "counter(" + String(m_value.string) + ')';
    985             break;
    986         case CSS_COUNTER: {
    987             StringBuilder result;
    988             String separator = m_value.counter->separator();
    989             if (separator.isEmpty())
    990                 result.appendLiteral("counter(");
    991             else
    992                 result.appendLiteral("counters(");
    993 
    994             result.append(m_value.counter->identifier());
    995             if (!separator.isEmpty()) {
    996                 result.appendLiteral(", ");
    997                 result.append(quoteCSSStringIfNeeded(separator));
    998             }
    999             String listStyle = m_value.counter->listStyle();
   1000             if (!listStyle.isEmpty()) {
   1001                 result.appendLiteral(", ");
   1002                 result.append(listStyle);
   1003             }
   1004             result.append(')');
   1005 
   1006             text = result.toString();
   1007             break;
   1008         }
   1009         case CSS_RECT:
   1010             text = getRectValue()->cssText();
   1011             break;
   1012         case CSS_QUAD:
   1013             text = getQuadValue()->cssText();
   1014             break;
   1015         case CSS_RGBCOLOR:
   1016         case CSS_PARSER_HEXCOLOR: {
   1017             RGBA32 rgbColor = m_value.rgbcolor;
   1018             if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR)
   1019                 Color::parseHexColor(m_value.string, rgbColor);
   1020             Color color(rgbColor);
   1021 
   1022             StringBuilder result;
   1023             result.reserveCapacity(32);
   1024             bool colorHasAlpha = color.hasAlpha();
   1025             if (colorHasAlpha)
   1026                 result.append("rgba(", 5);
   1027             else
   1028                 result.append("rgb(", 4);
   1029 
   1030             result.appendNumber(static_cast<unsigned char>(color.red()));
   1031             result.append(", ", 2);
   1032 
   1033             result.appendNumber(static_cast<unsigned char>(color.green()));
   1034             result.append(", ", 2);
   1035 
   1036             result.appendNumber(static_cast<unsigned char>(color.blue()));
   1037             if (colorHasAlpha) {
   1038                 result.append(", ", 2);
   1039 
   1040                 NumberToStringBuffer buffer;
   1041                 const char* alphaString = numberToFixedPrecisionString(color.alpha() / 255.0f, 6, buffer, true);
   1042                 result.append(alphaString, strlen(alphaString));
   1043             }
   1044 
   1045             result.append(')');
   1046             text = result.toString();
   1047             break;
   1048         }
   1049         case CSS_PAIR:
   1050             text = getPairValue()->cssText();
   1051             break;
   1052         case CSS_PARSER_OPERATOR: {
   1053             char c = static_cast<char>(m_value.parserOperator);
   1054             text = String(&c, 1U);
   1055             break;
   1056         }
   1057         case CSS_PARSER_IDENTIFIER:
   1058             text = quoteCSSStringIfNeeded(m_value.string);
   1059             break;
   1060         case CSS_CALC:
   1061             text = m_value.calc->cssText();
   1062             break;
   1063         case CSS_SHAPE:
   1064             text = m_value.shape->cssText();
   1065             break;
   1066         case CSS_VW:
   1067             text = formatNumber(m_value.num, "vw");
   1068             break;
   1069         case CSS_VH:
   1070             text = formatNumber(m_value.num, "vh");
   1071             break;
   1072         case CSS_VMIN:
   1073             text = formatNumber(m_value.num, "vmin");
   1074             break;
   1075         case CSS_VMAX:
   1076             text = formatNumber(m_value.num, "vmax");
   1077             break;
   1078         case CSS_VARIABLE_NAME:
   1079             text = "var(" + String(m_value.string) + ")";
   1080             break;
   1081     }
   1082 
   1083     ASSERT(!cssTextCache().contains(this));
   1084     cssTextCache().set(this, text);
   1085     m_hasCachedCSSText = true;
   1086     return text;
   1087 }
   1088 
   1089 String CSSPrimitiveValue::customSerializeResolvingVariables(const HashMap<AtomicString, String>& variables) const
   1090 {
   1091     if (isVariableName() && variables.contains(m_value.string))
   1092         return variables.get(m_value.string);
   1093     if (CSSCalcValue* calcValue = cssCalcValue())
   1094         return calcValue->customSerializeResolvingVariables(variables);
   1095     if (Pair* pairValue = getPairValue())
   1096         return pairValue->serializeResolvingVariables(variables);
   1097     if (Rect* rectVal = getRectValue())
   1098         return rectVal->serializeResolvingVariables(variables);
   1099     if (Quad* quadVal = getQuadValue())
   1100         return quadVal->serializeResolvingVariables(variables);
   1101     if (CSSBasicShape* shapeValue = getShapeValue())
   1102         return shapeValue->serializeResolvingVariables(variables);
   1103     return customCssText();
   1104 }
   1105 
   1106 bool CSSPrimitiveValue::hasVariableReference() const
   1107 {
   1108     if (CSSCalcValue* calcValue = cssCalcValue())
   1109         return calcValue->hasVariableReference();
   1110     if (Pair* pairValue = getPairValue())
   1111         return pairValue->hasVariableReference();
   1112     if (Quad* quadValue = getQuadValue())
   1113         return quadValue->hasVariableReference();
   1114     if (Rect* rectValue = getRectValue())
   1115         return rectValue->hasVariableReference();
   1116     if (CSSBasicShape* shapeValue = getShapeValue())
   1117         return shapeValue->hasVariableReference();
   1118     return isVariableName();
   1119 }
   1120 
   1121 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const StyleSheetContents* styleSheet) const
   1122 {
   1123     if (m_primitiveUnitType == CSS_URI)
   1124         addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
   1125 }
   1126 
   1127 Length CSSPrimitiveValue::viewportPercentageLength()
   1128 {
   1129     ASSERT(isViewportPercentageLength());
   1130     Length viewportLength;
   1131     switch (m_primitiveUnitType) {
   1132     case CSS_VW:
   1133         viewportLength = Length(getDoubleValue(), ViewportPercentageWidth);
   1134         break;
   1135     case CSS_VH:
   1136         viewportLength = Length(getDoubleValue(), ViewportPercentageHeight);
   1137         break;
   1138     case CSS_VMIN:
   1139         viewportLength = Length(getDoubleValue(), ViewportPercentageMin);
   1140         break;
   1141     case CSS_VMAX:
   1142         viewportLength = Length(getDoubleValue(), ViewportPercentageMax);
   1143         break;
   1144     default:
   1145         break;
   1146     }
   1147     return viewportLength;
   1148 }
   1149 
   1150 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::cloneForCSSOM() const
   1151 {
   1152     RefPtr<CSSPrimitiveValue> result;
   1153 
   1154     switch (m_primitiveUnitType) {
   1155     case CSS_STRING:
   1156     case CSS_URI:
   1157     case CSS_ATTR:
   1158     case CSS_COUNTER_NAME:
   1159         result = CSSPrimitiveValue::create(m_value.string, static_cast<UnitTypes>(m_primitiveUnitType));
   1160         break;
   1161     case CSS_COUNTER:
   1162         result = CSSPrimitiveValue::create(m_value.counter->cloneForCSSOM());
   1163         break;
   1164     case CSS_RECT:
   1165         result = CSSPrimitiveValue::create(m_value.rect->cloneForCSSOM());
   1166         break;
   1167     case CSS_QUAD:
   1168         result = CSSPrimitiveValue::create(m_value.quad->cloneForCSSOM());
   1169         break;
   1170     case CSS_PAIR:
   1171         // Pair is not exposed to the CSSOM, no need for a deep clone.
   1172         result = CSSPrimitiveValue::create(m_value.pair);
   1173         break;
   1174     case CSS_CALC:
   1175         // CSSCalcValue is not exposed to the CSSOM, no need for a deep clone.
   1176         result = CSSPrimitiveValue::create(m_value.calc);
   1177         break;
   1178     case CSS_SHAPE:
   1179         // CSSShapeValue is not exposed to the CSSOM, no need for a deep clone.
   1180         result = CSSPrimitiveValue::create(m_value.shape);
   1181         break;
   1182     case CSS_NUMBER:
   1183     case CSS_PARSER_INTEGER:
   1184     case CSS_PERCENTAGE:
   1185     case CSS_EMS:
   1186     case CSS_EXS:
   1187     case CSS_REMS:
   1188     case CSS_CHS:
   1189     case CSS_PX:
   1190     case CSS_CM:
   1191     case CSS_MM:
   1192     case CSS_IN:
   1193     case CSS_PT:
   1194     case CSS_PC:
   1195     case CSS_DEG:
   1196     case CSS_RAD:
   1197     case CSS_GRAD:
   1198     case CSS_MS:
   1199     case CSS_S:
   1200     case CSS_HZ:
   1201     case CSS_KHZ:
   1202     case CSS_TURN:
   1203     case CSS_VW:
   1204     case CSS_VH:
   1205     case CSS_VMIN:
   1206     case CSS_VMAX:
   1207     case CSS_DPPX:
   1208     case CSS_DPI:
   1209     case CSS_DPCM:
   1210         result = CSSPrimitiveValue::create(m_value.num, static_cast<UnitTypes>(m_primitiveUnitType));
   1211         break;
   1212     case CSS_PROPERTY_ID:
   1213         result = CSSPrimitiveValue::createIdentifier(m_value.propertyID);
   1214         break;
   1215     case CSS_VALUE_ID:
   1216         result = CSSPrimitiveValue::createIdentifier(m_value.valueID);
   1217         break;
   1218     case CSS_RGBCOLOR:
   1219         result = CSSPrimitiveValue::createColor(m_value.rgbcolor);
   1220         break;
   1221     case CSS_DIMENSION:
   1222     case CSS_UNKNOWN:
   1223     case CSS_PARSER_OPERATOR:
   1224     case CSS_PARSER_IDENTIFIER:
   1225     case CSS_PARSER_HEXCOLOR:
   1226         ASSERT_NOT_REACHED();
   1227         break;
   1228     }
   1229     if (result)
   1230         result->setCSSOMSafe();
   1231 
   1232     return result;
   1233 }
   1234 
   1235 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
   1236 {
   1237     if (m_primitiveUnitType != other.m_primitiveUnitType)
   1238         return false;
   1239 
   1240     switch (m_primitiveUnitType) {
   1241     case CSS_UNKNOWN:
   1242         return false;
   1243     case CSS_NUMBER:
   1244     case CSS_PARSER_INTEGER:
   1245     case CSS_PERCENTAGE:
   1246     case CSS_EMS:
   1247     case CSS_EXS:
   1248     case CSS_REMS:
   1249     case CSS_PX:
   1250     case CSS_CM:
   1251     case CSS_DPPX:
   1252     case CSS_DPI:
   1253     case CSS_DPCM:
   1254     case CSS_MM:
   1255     case CSS_IN:
   1256     case CSS_PT:
   1257     case CSS_PC:
   1258     case CSS_DEG:
   1259     case CSS_RAD:
   1260     case CSS_GRAD:
   1261     case CSS_MS:
   1262     case CSS_S:
   1263     case CSS_HZ:
   1264     case CSS_KHZ:
   1265     case CSS_TURN:
   1266     case CSS_VW:
   1267     case CSS_VH:
   1268     case CSS_VMIN:
   1269     case CSS_VMAX:
   1270     case CSS_DIMENSION:
   1271         return m_value.num == other.m_value.num;
   1272     case CSS_PROPERTY_ID:
   1273         return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID);
   1274     case CSS_VALUE_ID:
   1275         return valueName(m_value.valueID) == valueName(other.m_value.valueID);
   1276     case CSS_STRING:
   1277     case CSS_URI:
   1278     case CSS_ATTR:
   1279     case CSS_COUNTER_NAME:
   1280     case CSS_PARSER_IDENTIFIER:
   1281     case CSS_PARSER_HEXCOLOR:
   1282     case CSS_VARIABLE_NAME:
   1283         return equal(m_value.string, other.m_value.string);
   1284     case CSS_COUNTER:
   1285         return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter);
   1286     case CSS_RECT:
   1287         return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect);
   1288     case CSS_QUAD:
   1289         return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad);
   1290     case CSS_RGBCOLOR:
   1291         return m_value.rgbcolor == other.m_value.rgbcolor;
   1292     case CSS_PAIR:
   1293         return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair);
   1294     case CSS_PARSER_OPERATOR:
   1295         return m_value.parserOperator == other.m_value.parserOperator;
   1296     case CSS_CALC:
   1297         return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
   1298     case CSS_SHAPE:
   1299         return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
   1300     }
   1301     return false;
   1302 }
   1303 
   1304 } // namespace WebCore
   1305