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