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