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