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