• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "CSSHelper.h"
25 #include "CSSPropertyNames.h"
26 #include "CSSStyleSheet.h"
27 #include "CSSValueKeywords.h"
28 #include "Color.h"
29 #include "Counter.h"
30 #include "ExceptionCode.h"
31 #include "Node.h"
32 #include "Pair.h"
33 #include "RGBColor.h"
34 #include "Rect.h"
35 #include "RenderStyle.h"
36 #include <wtf/ASCIICType.h>
37 #include <wtf/StdLibExtras.h>
38 
39 #if ENABLE(DASHBOARD_SUPPORT)
40 #include "DashboardRegion.h"
41 #endif
42 
43 using namespace WTF;
44 
45 namespace WebCore {
46 
47 // A more stylish solution than sharing would be to turn CSSPrimitiveValue (or CSSValues in general) into non-virtual,
48 // non-refcounted simple type with value semantics. In practice these sharing tricks get similar memory benefits
49 // with less need for refactoring.
50 
createIdentifier(int ident)51 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createIdentifier(int ident)
52 {
53     static RefPtr<CSSPrimitiveValue>* identValueCache = new RefPtr<CSSPrimitiveValue>[numCSSValueKeywords];
54     if (ident >= 0 && ident < numCSSValueKeywords) {
55         RefPtr<CSSPrimitiveValue> primitiveValue = identValueCache[ident];
56         if (!primitiveValue) {
57             primitiveValue = adoptRef(new CSSPrimitiveValue(ident));
58             identValueCache[ident] = primitiveValue;
59         }
60         return primitiveValue.release();
61     }
62     return adoptRef(new CSSPrimitiveValue(ident));
63 }
64 
createColor(unsigned rgbValue)65 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createColor(unsigned rgbValue)
66 {
67     typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache;
68     static ColorValueCache* colorValueCache = new ColorValueCache;
69     // These are the empty and deleted values of the hash table.
70     if (rgbValue == Color::transparent) {
71         static CSSPrimitiveValue* colorTransparent = new CSSPrimitiveValue(Color::transparent);
72         return colorTransparent;
73     }
74     if (rgbValue == Color::white) {
75         static CSSPrimitiveValue* colorWhite = new CSSPrimitiveValue(Color::white);
76         return colorWhite;
77     }
78     RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue);
79     if (primitiveValue)
80         return primitiveValue.release();
81     primitiveValue = adoptRef(new CSSPrimitiveValue(rgbValue));
82     // Just wipe out the cache and start rebuilding when it gets too big.
83     const int maxColorCacheSize = 512;
84     if (colorValueCache->size() >= maxColorCacheSize)
85         colorValueCache->clear();
86     colorValueCache->add(rgbValue, primitiveValue);
87 
88     return primitiveValue.release();
89 }
90 
create(double value,UnitTypes type)91 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(double value, UnitTypes type)
92 {
93     // Small integers are very common. Try to share them.
94     const int cachedIntegerCount = 128;
95     // Other common primitive types have UnitTypes smaller than this.
96     const int maxCachedUnitType = CSS_PX;
97     typedef RefPtr<CSSPrimitiveValue>(* IntegerValueCache)[maxCachedUnitType + 1];
98     static IntegerValueCache integerValueCache = new RefPtr<CSSPrimitiveValue>[cachedIntegerCount][maxCachedUnitType + 1];
99     if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) {
100         int intValue = static_cast<int>(value);
101         if (value == intValue) {
102             RefPtr<CSSPrimitiveValue> primitiveValue = integerValueCache[intValue][type];
103             if (!primitiveValue) {
104                 primitiveValue = adoptRef(new CSSPrimitiveValue(value, type));
105                 integerValueCache[intValue][type] = primitiveValue;
106             }
107             return primitiveValue.release();
108         }
109     }
110 
111     return adoptRef(new CSSPrimitiveValue(value, type));
112 }
113 
create(const String & value,UnitTypes type)114 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type)
115 {
116     return adoptRef(new CSSPrimitiveValue(value, type));
117 }
118 
valueOrPropertyName(int valueOrPropertyID)119 static const char* valueOrPropertyName(int valueOrPropertyID)
120 {
121     if (const char* valueName = getValueName(valueOrPropertyID))
122         return valueName;
123     return getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID));
124 }
125 
126 // "ident" from the CSS tokenizer, minus backslash-escape sequences
isCSSTokenizerIdentifier(const String & string)127 static bool isCSSTokenizerIdentifier(const String& string)
128 {
129     const UChar* p = string.characters();
130     const UChar* end = p + string.length();
131 
132     // -?
133     if (p != end && p[0] == '-')
134         ++p;
135 
136     // {nmstart}
137     if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0])))
138         return false;
139     ++p;
140 
141     // {nmchar}*
142     for (; p != end; ++p) {
143         if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0])))
144             return false;
145     }
146 
147     return true;
148 }
149 
150 // "url" from the CSS tokenizer, minus backslash-escape sequences
isCSSTokenizerURL(const String & string)151 static bool isCSSTokenizerURL(const String& string)
152 {
153     const UChar* p = string.characters();
154     const UChar* end = p + string.length();
155 
156     for (; p != end; ++p) {
157         UChar c = p[0];
158         switch (c) {
159             case '!':
160             case '#':
161             case '$':
162             case '%':
163             case '&':
164                 break;
165             default:
166                 if (c < '*')
167                     return false;
168                 if (c <= '~')
169                     break;
170                 if (c < 128)
171                     return false;
172         }
173     }
174 
175     return true;
176 }
177 
178 // We use single quotes for now because markup.cpp uses double quotes.
quoteString(const String & string)179 static String quoteString(const String& string)
180 {
181     // FIXME: Also need to escape characters like '\n'.
182     String s = string;
183     s.replace('\\', "\\\\");
184     s.replace('\'', "\\'");
185     return "'" + s + "'";
186 }
187 
quoteStringIfNeeded(const String & string)188 static String quoteStringIfNeeded(const String& string)
189 {
190     return isCSSTokenizerIdentifier(string) ? string : quoteString(string);
191 }
192 
quoteURLIfNeeded(const String & string)193 static String quoteURLIfNeeded(const String& string)
194 {
195     return isCSSTokenizerURL(string) ? string : quoteString(string);
196 }
197 
CSSPrimitiveValue()198 CSSPrimitiveValue::CSSPrimitiveValue()
199     : m_type(0)
200 {
201 }
202 
CSSPrimitiveValue(int ident)203 CSSPrimitiveValue::CSSPrimitiveValue(int ident)
204     : m_type(CSS_IDENT)
205 {
206     m_value.ident = ident;
207 }
208 
CSSPrimitiveValue(double num,UnitTypes type)209 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
210     : m_type(type)
211 {
212     m_value.num = num;
213 }
214 
CSSPrimitiveValue(const String & str,UnitTypes type)215 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
216     : m_type(type)
217 {
218     if ((m_value.string = str.impl()))
219         m_value.string->ref();
220 }
221 
CSSPrimitiveValue(RGBA32 color)222 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
223     : m_type(CSS_RGBCOLOR)
224 {
225     m_value.rgbcolor = color;
226 }
227 
CSSPrimitiveValue(const Length & length)228 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
229 {
230     switch (length.type()) {
231         case Auto:
232             m_type = CSS_IDENT;
233             m_value.ident = CSSValueAuto;
234             break;
235         case WebCore::Fixed:
236             m_type = CSS_PX;
237             m_value.num = length.value();
238             break;
239         case Intrinsic:
240             m_type = CSS_IDENT;
241             m_value.ident = CSSValueIntrinsic;
242             break;
243         case MinIntrinsic:
244             m_type = CSS_IDENT;
245             m_value.ident = CSSValueMinIntrinsic;
246             break;
247         case Percent:
248             m_type = CSS_PERCENTAGE;
249             m_value.num = length.percent();
250             break;
251         case Relative:
252         case Static:
253             ASSERT_NOT_REACHED();
254             break;
255     }
256 }
257 
init(PassRefPtr<Counter> c)258 void CSSPrimitiveValue::init(PassRefPtr<Counter> c)
259 {
260     m_type = CSS_COUNTER;
261     m_value.counter = c.releaseRef();
262 }
263 
init(PassRefPtr<Rect> r)264 void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
265 {
266     m_type = CSS_RECT;
267     m_value.rect = r.releaseRef();
268 }
269 
270 #if ENABLE(DASHBOARD_SUPPORT)
init(PassRefPtr<DashboardRegion> r)271 void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r)
272 {
273     m_type = CSS_DASHBOARD_REGION;
274     m_value.region = r.releaseRef();
275 }
276 #endif
277 
init(PassRefPtr<Pair> p)278 void CSSPrimitiveValue::init(PassRefPtr<Pair> p)
279 {
280     m_type = CSS_PAIR;
281     m_value.pair = p.releaseRef();
282 }
283 
~CSSPrimitiveValue()284 CSSPrimitiveValue::~CSSPrimitiveValue()
285 {
286     cleanup();
287 }
288 
cleanup()289 void CSSPrimitiveValue::cleanup()
290 {
291     switch (m_type) {
292         case CSS_STRING:
293         case CSS_URI:
294         case CSS_ATTR:
295         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
296         case CSS_PARSER_HEXCOLOR:
297             if (m_value.string)
298                 m_value.string->deref();
299             break;
300         case CSS_COUNTER:
301             m_value.counter->deref();
302             break;
303         case CSS_RECT:
304             m_value.rect->deref();
305             break;
306         case CSS_PAIR:
307             m_value.pair->deref();
308             break;
309 #if ENABLE(DASHBOARD_SUPPORT)
310         case CSS_DASHBOARD_REGION:
311             if (m_value.region)
312                 m_value.region->deref();
313             break;
314 #endif
315         default:
316             break;
317     }
318 
319     m_type = 0;
320 }
321 
computeLengthInt(RenderStyle * style,RenderStyle * rootStyle)322 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle)
323 {
324     double result = computeLengthDouble(style, rootStyle);
325 
326     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
327     // need to go ahead and round if we're really close to the next integer value.
328     result += result < 0 ? -0.01 : +0.01;
329 
330     if (result > INT_MAX || result < INT_MIN)
331         return 0;
332     return static_cast<int>(result);
333 }
334 
computeLengthInt(RenderStyle * style,RenderStyle * rootStyle,double multiplier)335 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
336 {
337     double result = computeLengthDouble(style, rootStyle, multiplier);
338 
339     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
340     // need to go ahead and round if we're really close to the next integer value.
341     result += result < 0 ? -0.01 : +0.01;
342 
343     if (result > INT_MAX || result < INT_MIN)
344         return 0;
345     return static_cast<int>(result);
346 }
347 
348 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
349 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
350 
351 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow.
computeLengthIntForLength(RenderStyle * style,RenderStyle * rootStyle)352 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle)
353 {
354     double result = computeLengthDouble(style, rootStyle);
355 
356     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
357     // need to go ahead and round if we're really close to the next integer value.
358     result += result < 0 ? -0.01 : +0.01;
359 
360     if (result > intMaxForLength || result < intMinForLength)
361         return 0;
362     return static_cast<int>(result);
363 }
364 
365 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow.
computeLengthIntForLength(RenderStyle * style,RenderStyle * rootStyle,double multiplier)366 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
367 {
368     double result = computeLengthDouble(style, rootStyle, multiplier);
369 
370     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
371     // need to go ahead and round if we're really close to the next integer value.
372     result += result < 0 ? -0.01 : +0.01;
373 
374     if (result > intMaxForLength || result < intMinForLength)
375         return 0;
376     return static_cast<int>(result);
377 }
378 
computeLengthShort(RenderStyle * style,RenderStyle * rootStyle)379 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle)
380 {
381     double result = computeLengthDouble(style, rootStyle);
382 
383     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
384     // need to go ahead and round if we're really close to the next integer value.
385     result += result < 0 ? -0.01 : +0.01;
386 
387     if (result > SHRT_MAX || result < SHRT_MIN)
388         return 0;
389     return static_cast<short>(result);
390 }
391 
computeLengthShort(RenderStyle * style,RenderStyle * rootStyle,double multiplier)392 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
393 {
394     double result = computeLengthDouble(style, rootStyle, multiplier);
395 
396     // This conversion is imprecise, often resulting in values of, e.g., 44.99998.  We
397     // need to go ahead and round if we're really close to the next integer value.
398     result += result < 0 ? -0.01 : +0.01;
399 
400     if (result > SHRT_MAX || result < SHRT_MIN)
401         return 0;
402     return static_cast<short>(result);
403 }
404 
computeLengthFloat(RenderStyle * style,RenderStyle * rootStyle,bool computingFontSize)405 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize)
406 {
407     return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize));
408 }
409 
computeLengthFloat(RenderStyle * style,RenderStyle * rootStyle,double multiplier,bool computingFontSize)410 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
411 {
412     return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
413 }
414 
computeLengthDouble(RenderStyle * style,RenderStyle * rootStyle,double multiplier,bool computingFontSize)415 double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
416 {
417     unsigned short type = primitiveType();
418 
419     // We do not apply the zoom factor when we are computing the value of the font-size property.  The zooming
420     // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
421     // as well as enforcing the implicit "smart minimum."  In addition the CSS property text-size-adjust is used to
422     // prevent text from zooming at all.  Therefore we will not apply the zoom here if we are computing font-size.
423     bool applyZoomMultiplier = !computingFontSize;
424 
425     double factor = 1.0;
426     switch (type) {
427         case CSS_EMS:
428             applyZoomMultiplier = false;
429             factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
430             break;
431         case CSS_EXS:
432             // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
433             // We really need to compute EX using fontMetrics for the original specifiedSize and not use
434             // our actual constructed rendering font.
435             applyZoomMultiplier = false;
436             factor = style->font().xHeight();
437             break;
438         case CSS_REMS:
439             applyZoomMultiplier = false;
440             factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
441             break;
442         case CSS_PX:
443             break;
444         case CSS_CM:
445             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
446             break;
447         case CSS_MM:
448             factor = cssPixelsPerInch / 25.4;
449             break;
450         case CSS_IN:
451             factor = cssPixelsPerInch;
452             break;
453         case CSS_PT:
454             factor = cssPixelsPerInch / 72.0;
455             break;
456         case CSS_PC:
457             // 1 pc == 12 pt
458             factor = cssPixelsPerInch * 12.0 / 72.0;
459             break;
460         default:
461             return -1.0;
462     }
463 
464     double result = getDoubleValue() * factor;
465     if (!applyZoomMultiplier || multiplier == 1.0)
466         return result;
467 
468     // Any original result that was >= 1 should not be allowed to fall below 1.  This keeps border lines from
469     // vanishing.
470     double zoomedResult = result * multiplier;
471     if (result >= 1.0)
472         zoomedResult = max(1.0, zoomedResult);
473     return zoomedResult;
474 }
475 
setFloatValue(unsigned short unitType,double floatValue,ExceptionCode & ec)476 void CSSPrimitiveValue::setFloatValue(unsigned short unitType, double floatValue, ExceptionCode& ec)
477 {
478     ec = 0;
479 
480     // FIXME: check if property supports this type
481     if (m_type > CSS_DIMENSION) {
482         ec = SYNTAX_ERR;
483         return;
484     }
485 
486     cleanup();
487 
488     //if(m_type > CSS_DIMENSION) throw DOMException(INVALID_ACCESS_ERR);
489     m_value.num = floatValue;
490     m_type = unitType;
491 }
492 
scaleFactorForConversion(unsigned short unitType)493 static double scaleFactorForConversion(unsigned short unitType)
494 {
495     double factor = 1.0;
496     switch (unitType) {
497         case CSSPrimitiveValue::CSS_PX:
498             break;
499         case CSSPrimitiveValue::CSS_CM:
500             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
501             break;
502         case CSSPrimitiveValue::CSS_MM:
503             factor = cssPixelsPerInch / 25.4;
504             break;
505         case CSSPrimitiveValue::CSS_IN:
506             factor = cssPixelsPerInch;
507             break;
508         case CSSPrimitiveValue::CSS_PT:
509             factor = cssPixelsPerInch / 72.0;
510             break;
511         case CSSPrimitiveValue::CSS_PC:
512             factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
513             break;
514         default:
515             break;
516     }
517 
518     return factor;
519 }
520 
getDoubleValue(unsigned short unitType,ExceptionCode & ec)521 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec)
522 {
523     ec = 0;
524     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) {
525         ec = INVALID_ACCESS_ERR;
526         return 0.0;
527     }
528 
529     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
530         return m_value.num;
531 
532     double convertedValue = m_value.num;
533 
534     // First convert the value from m_type into CSSPixels
535     double factor = scaleFactorForConversion(m_type);
536     convertedValue *= factor;
537 
538     // Now convert from CSSPixels to the specified unitType
539     factor = scaleFactorForConversion(unitType);
540     convertedValue /= factor;
541 
542     return convertedValue;
543 }
544 
getDoubleValue(unsigned short unitType)545 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType)
546 {
547     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION)
548         return 0;
549 
550     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
551         return m_value.num;
552 
553     double convertedValue = m_value.num;
554 
555     // First convert the value from m_type into CSSPixels
556     double factor = scaleFactorForConversion(m_type);
557     convertedValue *= factor;
558 
559     // Now convert from CSSPixels to the specified unitType
560     factor = scaleFactorForConversion(unitType);
561     convertedValue /= factor;
562 
563     return convertedValue;
564 }
565 
566 
setStringValue(unsigned short stringType,const String & stringValue,ExceptionCode & ec)567 void CSSPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode& ec)
568 {
569     ec = 0;
570 
571     //if(m_type < CSS_STRING) throw DOMException(INVALID_ACCESS_ERR);
572     //if(m_type > CSS_ATTR) throw DOMException(INVALID_ACCESS_ERR);
573     if (m_type < CSS_STRING || m_type > CSS_ATTR) {
574         ec = SYNTAX_ERR;
575         return;
576     }
577 
578     cleanup();
579 
580     if (stringType != CSS_IDENT) {
581         m_value.string = stringValue.impl();
582         m_value.string->ref();
583         m_type = stringType;
584     }
585     // FIXME: parse ident
586 }
587 
getStringValue(ExceptionCode & ec) const588 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const
589 {
590     ec = 0;
591     switch (m_type) {
592         case CSS_STRING:
593         case CSS_ATTR:
594         case CSS_URI:
595         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
596             return m_value.string;
597         case CSS_IDENT:
598             return valueOrPropertyName(m_value.ident);
599         default:
600             ec = INVALID_ACCESS_ERR;
601             break;
602     }
603 
604     return String();
605 }
606 
getStringValue() const607 String CSSPrimitiveValue::getStringValue() const
608 {
609     switch (m_type) {
610         case CSS_STRING:
611         case CSS_ATTR:
612         case CSS_URI:
613         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
614              return m_value.string;
615         case CSS_IDENT:
616             return valueOrPropertyName(m_value.ident);
617         default:
618             break;
619     }
620 
621     return String();
622 }
623 
getCounterValue(ExceptionCode & ec) const624 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const
625 {
626     ec = 0;
627     if (m_type != CSS_COUNTER) {
628         ec = INVALID_ACCESS_ERR;
629         return 0;
630     }
631 
632     return m_value.counter;
633 }
634 
getRectValue(ExceptionCode & ec) const635 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const
636 {
637     ec = 0;
638     if (m_type != CSS_RECT) {
639         ec = INVALID_ACCESS_ERR;
640         return 0;
641     }
642 
643     return m_value.rect;
644 }
645 
getRGBColorValue(ExceptionCode & ec) const646 RGBColor* CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const
647 {
648     ec = 0;
649     if (m_type != CSS_RGBCOLOR) {
650         ec = INVALID_ACCESS_ERR;
651         return 0;
652     }
653 
654     // FIMXE: This should not return a new object for each invocation.
655     return RGBColor::create(m_value.rgbcolor).releaseRef();
656 }
657 
getPairValue(ExceptionCode & ec) const658 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const
659 {
660     ec = 0;
661     if (m_type != CSS_PAIR) {
662         ec = INVALID_ACCESS_ERR;
663         return 0;
664     }
665 
666     return m_value.pair;
667 }
668 
cssValueType() const669 unsigned short CSSPrimitiveValue::cssValueType() const
670 {
671     return CSS_PRIMITIVE_VALUE;
672 }
673 
parseString(const String &,bool)674 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/)
675 {
676     // FIXME
677     return false;
678 }
679 
getIdent()680 int CSSPrimitiveValue::getIdent()
681 {
682     if (m_type != CSS_IDENT)
683         return 0;
684     return m_value.ident;
685 }
686 
cssText() const687 String CSSPrimitiveValue::cssText() const
688 {
689     // FIXME: return the original value instead of a generated one (e.g. color
690     // name if it was specified) - check what spec says about this
691     String text;
692     switch (m_type) {
693         case CSS_UNKNOWN:
694             // FIXME
695             break;
696         case CSS_NUMBER:
697         case CSS_PARSER_INTEGER:
698             text = String::number(m_value.num);
699             break;
700         case CSS_PERCENTAGE:
701             text = String::format("%.6lg%%", m_value.num);
702             break;
703         case CSS_EMS:
704             text = String::format("%.6lgem", m_value.num);
705             break;
706         case CSS_EXS:
707             text = String::format("%.6lgex", m_value.num);
708             break;
709         case CSS_REMS:
710             text = String::format("%.6lgrem", m_value.num);
711             break;
712         case CSS_PX:
713             text = String::format("%.6lgpx", m_value.num);
714             break;
715         case CSS_CM:
716             text = String::format("%.6lgcm", m_value.num);
717             break;
718         case CSS_MM:
719             text = String::format("%.6lgmm", m_value.num);
720             break;
721         case CSS_IN:
722             text = String::format("%.6lgin", m_value.num);
723             break;
724         case CSS_PT:
725             text = String::format("%.6lgpt", m_value.num);
726             break;
727         case CSS_PC:
728             text = String::format("%.6lgpc", m_value.num);
729             break;
730         case CSS_DEG:
731             text = String::format("%.6lgdeg", m_value.num);
732             break;
733         case CSS_RAD:
734             text = String::format("%.6lgrad", m_value.num);
735             break;
736         case CSS_GRAD:
737             text = String::format("%.6lggrad", m_value.num);
738             break;
739         case CSS_MS:
740             text = String::format("%.6lgms", m_value.num);
741             break;
742         case CSS_S:
743             text = String::format("%.6lgs", m_value.num);
744             break;
745         case CSS_HZ:
746             text = String::format("%.6lghz", m_value.num);
747             break;
748         case CSS_KHZ:
749             text = String::format("%.6lgkhz", m_value.num);
750             break;
751         case CSS_TURN:
752             text = String::format("%.6lgturn", m_value.num);
753             break;
754         case CSS_DIMENSION:
755             // FIXME
756             break;
757         case CSS_STRING:
758             text = quoteStringIfNeeded(m_value.string);
759             break;
760         case CSS_URI:
761             text = "url(" + quoteURLIfNeeded(m_value.string) + ")";
762             break;
763         case CSS_IDENT:
764             text = valueOrPropertyName(m_value.ident);
765             break;
766         case CSS_ATTR: {
767             DEFINE_STATIC_LOCAL(const String, attrParen, ("attr("));
768 
769             Vector<UChar> result;
770             result.reserveInitialCapacity(6 + m_value.string->length());
771 
772             append(result, attrParen);
773             append(result, m_value.string);
774             result.uncheckedAppend(')');
775 
776             return String::adopt(result);
777         }
778         case CSS_COUNTER:
779             text = "counter(";
780             text += String::number(m_value.num);
781             text += ")";
782             // FIXME: Add list-style and separator
783             break;
784         case CSS_RECT: {
785             DEFINE_STATIC_LOCAL(const String, rectParen, ("rect("));
786 
787             Rect* rectVal = getRectValue();
788             Vector<UChar> result;
789             result.reserveInitialCapacity(32);
790             append(result, rectParen);
791 
792             append(result, rectVal->top()->cssText());
793             result.append(' ');
794 
795             append(result, rectVal->right()->cssText());
796             result.append(' ');
797 
798             append(result, rectVal->bottom()->cssText());
799             result.append(' ');
800 
801             append(result, rectVal->left()->cssText());
802             result.append(')');
803 
804             return String::adopt(result);
805         }
806         case CSS_RGBCOLOR:
807         case CSS_PARSER_HEXCOLOR: {
808             DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
809             DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb("));
810             DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
811 
812             RGBA32 rgbColor = m_value.rgbcolor;
813             if (m_type == CSS_PARSER_HEXCOLOR)
814                 Color::parseHexColor(m_value.string, rgbColor);
815             Color color(rgbColor);
816 
817             Vector<UChar> result;
818             result.reserveInitialCapacity(32);
819             if (color.hasAlpha())
820                 append(result, rgbaParen);
821             else
822                 append(result, rgbParen);
823 
824             appendNumber(result, static_cast<unsigned char>(color.red()));
825             append(result, commaSpace);
826 
827             appendNumber(result, static_cast<unsigned char>(color.green()));
828             append(result, commaSpace);
829 
830             appendNumber(result, static_cast<unsigned char>(color.blue()));
831             if (color.hasAlpha()) {
832                 append(result, commaSpace);
833                 append(result, String::number(static_cast<float>(color.alpha()) / 256.0f));
834             }
835 
836             result.append(')');
837             return String::adopt(result);
838         }
839         case CSS_PAIR:
840             text = m_value.pair->first()->cssText();
841             text += " ";
842             text += m_value.pair->second()->cssText();
843             break;
844 #if ENABLE(DASHBOARD_SUPPORT)
845         case CSS_DASHBOARD_REGION:
846             for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) {
847                 if (!text.isEmpty())
848                     text.append(' ');
849                 text += "dashboard-region(";
850                 text += region->m_label;
851                 if (region->m_isCircle)
852                     text += " circle";
853                 else if (region->m_isRectangle)
854                     text += " rectangle";
855                 else
856                     break;
857                 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) {
858                     ASSERT(region->right()->m_type == CSS_IDENT);
859                     ASSERT(region->bottom()->m_type == CSS_IDENT);
860                     ASSERT(region->left()->m_type == CSS_IDENT);
861                     ASSERT(region->right()->getIdent() == CSSValueInvalid);
862                     ASSERT(region->bottom()->getIdent() == CSSValueInvalid);
863                     ASSERT(region->left()->getIdent() == CSSValueInvalid);
864                 } else {
865                     text.append(' ');
866                     text += region->top()->cssText() + " ";
867                     text += region->right()->cssText() + " ";
868                     text += region->bottom()->cssText() + " ";
869                     text += region->left()->cssText();
870                 }
871                 text += ")";
872             }
873             break;
874 #endif
875         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
876             text = "-webkit-var(";
877             text += m_value.string;
878             text += ")";
879             break;
880         case CSS_PARSER_OPERATOR: {
881             char c = static_cast<char>(m_value.ident);
882             text = String(&c, 1U);
883             break;
884         }
885         case CSS_PARSER_IDENTIFIER:
886             text = quoteStringIfNeeded(m_value.string);
887             break;
888     }
889     return text;
890 }
891 
parserValue() const892 CSSParserValue CSSPrimitiveValue::parserValue() const
893 {
894     // We only have to handle a subset of types.
895     CSSParserValue value;
896     value.id = 0;
897     value.isInt = false;
898     value.unit = CSSPrimitiveValue::CSS_IDENT;
899     switch (m_type) {
900         case CSS_NUMBER:
901         case CSS_PERCENTAGE:
902         case CSS_EMS:
903         case CSS_EXS:
904         case CSS_REMS:
905         case CSS_PX:
906         case CSS_CM:
907         case CSS_MM:
908         case CSS_IN:
909         case CSS_PT:
910         case CSS_PC:
911         case CSS_DEG:
912         case CSS_RAD:
913         case CSS_GRAD:
914         case CSS_MS:
915         case CSS_S:
916         case CSS_HZ:
917         case CSS_KHZ:
918         case CSS_DIMENSION:
919         case CSS_TURN:
920             value.fValue = m_value.num;
921             value.unit = m_type;
922             break;
923         case CSS_STRING:
924         case CSS_URI:
925         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
926         case CSS_PARSER_HEXCOLOR:
927             value.string.characters = const_cast<UChar*>(m_value.string->characters());
928             value.string.length = m_value.string->length();
929             value.unit = m_type;
930             break;
931         case CSS_IDENT: {
932             value.id = m_value.ident;
933             String name = valueOrPropertyName(m_value.ident);
934             value.string.characters = const_cast<UChar*>(name.characters());
935             value.string.length = name.length();
936             break;
937         }
938         case CSS_PARSER_OPERATOR:
939             value.iValue = m_value.ident;
940             value.unit = CSSParserValue::Operator;
941             break;
942         case CSS_PARSER_INTEGER:
943             value.fValue = m_value.num;
944             value.unit = CSSPrimitiveValue::CSS_NUMBER;
945             value.isInt = true;
946             break;
947         case CSS_PARSER_IDENTIFIER:
948             value.string.characters = const_cast<UChar*>(m_value.string->characters());
949             value.string.length = m_value.string->length();
950             value.unit = CSSPrimitiveValue::CSS_IDENT;
951             break;
952         case CSS_UNKNOWN:
953         case CSS_ATTR:
954         case CSS_COUNTER:
955         case CSS_RECT:
956         case CSS_RGBCOLOR:
957         case CSS_PAIR:
958 #if ENABLE(DASHBOARD_SUPPORT)
959         case CSS_DASHBOARD_REGION:
960 #endif
961             ASSERT_NOT_REACHED();
962             break;
963     }
964 
965     return value;
966 }
967 
addSubresourceStyleURLs(ListHashSet<KURL> & urls,const CSSStyleSheet * styleSheet)968 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
969 {
970     if (m_type == CSS_URI)
971         addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
972 }
973 
974 } // namespace WebCore
975