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