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