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