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