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