• 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     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) {
481         ec = INVALID_ACCESS_ERR;
482         return;
483     }
484 
485     cleanup();
486 
487     //if(m_type > CSS_DIMENSION) throw DOMException(INVALID_ACCESS_ERR);
488     m_value.num = floatValue;
489     m_type = unitType;
490 }
491 
scaleFactorForConversion(unsigned short unitType)492 static double scaleFactorForConversion(unsigned short unitType)
493 {
494     double factor = 1.0;
495     switch (unitType) {
496         case CSSPrimitiveValue::CSS_PX:
497             break;
498         case CSSPrimitiveValue::CSS_CM:
499             factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
500             break;
501         case CSSPrimitiveValue::CSS_MM:
502             factor = cssPixelsPerInch / 25.4;
503             break;
504         case CSSPrimitiveValue::CSS_IN:
505             factor = cssPixelsPerInch;
506             break;
507         case CSSPrimitiveValue::CSS_PT:
508             factor = cssPixelsPerInch / 72.0;
509             break;
510         case CSSPrimitiveValue::CSS_PC:
511             factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
512             break;
513         default:
514             break;
515     }
516 
517     return factor;
518 }
519 
getDoubleValue(unsigned short unitType,ExceptionCode & ec)520 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec)
521 {
522     ec = 0;
523     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) {
524         ec = INVALID_ACCESS_ERR;
525         return 0.0;
526     }
527 
528     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
529         return m_value.num;
530 
531     double convertedValue = m_value.num;
532 
533     // First convert the value from m_type into CSSPixels
534     double factor = scaleFactorForConversion(m_type);
535     convertedValue *= factor;
536 
537     // Now convert from CSSPixels to the specified unitType
538     factor = scaleFactorForConversion(unitType);
539     convertedValue /= factor;
540 
541     return convertedValue;
542 }
543 
getDoubleValue(unsigned short unitType)544 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType)
545 {
546     if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION)
547         return 0;
548 
549     if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC)
550         return m_value.num;
551 
552     double convertedValue = m_value.num;
553 
554     // First convert the value from m_type into CSSPixels
555     double factor = scaleFactorForConversion(m_type);
556     convertedValue *= factor;
557 
558     // Now convert from CSSPixels to the specified unitType
559     factor = scaleFactorForConversion(unitType);
560     convertedValue /= factor;
561 
562     return convertedValue;
563 }
564 
565 
setStringValue(unsigned short stringType,const String & stringValue,ExceptionCode & ec)566 void CSSPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode& ec)
567 {
568     ec = 0;
569 
570     if (m_type < CSS_STRING || m_type > CSS_ATTR || stringType < CSS_STRING || stringType > CSS_ATTR) {
571         ec = INVALID_ACCESS_ERR;
572         return;
573     }
574 
575     cleanup();
576 
577     if (stringType != CSS_IDENT) {
578         m_value.string = stringValue.impl();
579         m_value.string->ref();
580         m_type = stringType;
581     }
582     // FIXME: parse ident
583 }
584 
getStringValue(ExceptionCode & ec) const585 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const
586 {
587     ec = 0;
588     switch (m_type) {
589         case CSS_STRING:
590         case CSS_ATTR:
591         case CSS_URI:
592         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
593             return m_value.string;
594         case CSS_IDENT:
595             return valueOrPropertyName(m_value.ident);
596         default:
597             ec = INVALID_ACCESS_ERR;
598             break;
599     }
600 
601     return String();
602 }
603 
getStringValue() const604 String CSSPrimitiveValue::getStringValue() const
605 {
606     switch (m_type) {
607         case CSS_STRING:
608         case CSS_ATTR:
609         case CSS_URI:
610         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
611              return m_value.string;
612         case CSS_IDENT:
613             return valueOrPropertyName(m_value.ident);
614         default:
615             break;
616     }
617 
618     return String();
619 }
620 
getCounterValue(ExceptionCode & ec) const621 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const
622 {
623     ec = 0;
624     if (m_type != CSS_COUNTER) {
625         ec = INVALID_ACCESS_ERR;
626         return 0;
627     }
628 
629     return m_value.counter;
630 }
631 
getRectValue(ExceptionCode & ec) const632 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const
633 {
634     ec = 0;
635     if (m_type != CSS_RECT) {
636         ec = INVALID_ACCESS_ERR;
637         return 0;
638     }
639 
640     return m_value.rect;
641 }
642 
getRGBColorValue(ExceptionCode & ec) const643 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const
644 {
645     ec = 0;
646     if (m_type != CSS_RGBCOLOR) {
647         ec = INVALID_ACCESS_ERR;
648         return 0;
649     }
650 
651     // FIMXE: This should not return a new object for each invocation.
652     return RGBColor::create(m_value.rgbcolor);
653 }
654 
getPairValue(ExceptionCode & ec) const655 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const
656 {
657     ec = 0;
658     if (m_type != CSS_PAIR) {
659         ec = INVALID_ACCESS_ERR;
660         return 0;
661     }
662 
663     return m_value.pair;
664 }
665 
cssValueType() const666 unsigned short CSSPrimitiveValue::cssValueType() const
667 {
668     return CSS_PRIMITIVE_VALUE;
669 }
670 
parseString(const String &,bool)671 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/)
672 {
673     // FIXME
674     return false;
675 }
676 
getIdent()677 int CSSPrimitiveValue::getIdent()
678 {
679     if (m_type != CSS_IDENT)
680         return 0;
681     return m_value.ident;
682 }
683 
cssText() const684 String CSSPrimitiveValue::cssText() const
685 {
686     // FIXME: return the original value instead of a generated one (e.g. color
687     // name if it was specified) - check what spec says about this
688     String text;
689     switch (m_type) {
690         case CSS_UNKNOWN:
691             // FIXME
692             break;
693         case CSS_NUMBER:
694         case CSS_PARSER_INTEGER:
695             text = String::number(m_value.num);
696             break;
697         case CSS_PERCENTAGE:
698             text = String::format("%.6lg%%", m_value.num);
699             break;
700         case CSS_EMS:
701             text = String::format("%.6lgem", m_value.num);
702             break;
703         case CSS_EXS:
704             text = String::format("%.6lgex", m_value.num);
705             break;
706         case CSS_REMS:
707             text = String::format("%.6lgrem", m_value.num);
708             break;
709         case CSS_PX:
710             text = String::format("%.6lgpx", m_value.num);
711             break;
712         case CSS_CM:
713             text = String::format("%.6lgcm", m_value.num);
714             break;
715         case CSS_MM:
716             text = String::format("%.6lgmm", m_value.num);
717             break;
718         case CSS_IN:
719             text = String::format("%.6lgin", m_value.num);
720             break;
721         case CSS_PT:
722             text = String::format("%.6lgpt", m_value.num);
723             break;
724         case CSS_PC:
725             text = String::format("%.6lgpc", m_value.num);
726             break;
727         case CSS_DEG:
728             text = String::format("%.6lgdeg", m_value.num);
729             break;
730         case CSS_RAD:
731             text = String::format("%.6lgrad", m_value.num);
732             break;
733         case CSS_GRAD:
734             text = String::format("%.6lggrad", m_value.num);
735             break;
736         case CSS_MS:
737             text = String::format("%.6lgms", m_value.num);
738             break;
739         case CSS_S:
740             text = String::format("%.6lgs", m_value.num);
741             break;
742         case CSS_HZ:
743             text = String::format("%.6lghz", m_value.num);
744             break;
745         case CSS_KHZ:
746             text = String::format("%.6lgkhz", m_value.num);
747             break;
748         case CSS_TURN:
749             text = String::format("%.6lgturn", m_value.num);
750             break;
751         case CSS_DIMENSION:
752             // FIXME
753             break;
754         case CSS_STRING:
755             text = quoteStringIfNeeded(m_value.string);
756             break;
757         case CSS_URI:
758             text = "url(" + quoteURLIfNeeded(m_value.string) + ")";
759             break;
760         case CSS_IDENT:
761             text = valueOrPropertyName(m_value.ident);
762             break;
763         case CSS_ATTR: {
764             DEFINE_STATIC_LOCAL(const String, attrParen, ("attr("));
765 
766             Vector<UChar> result;
767             result.reserveInitialCapacity(6 + m_value.string->length());
768 
769             append(result, attrParen);
770             append(result, m_value.string);
771             result.uncheckedAppend(')');
772 
773             return String::adopt(result);
774         }
775         case CSS_COUNTER:
776             text = "counter(";
777             text += String::number(m_value.num);
778             text += ")";
779             // FIXME: Add list-style and separator
780             break;
781         case CSS_RECT: {
782             DEFINE_STATIC_LOCAL(const String, rectParen, ("rect("));
783 
784             Rect* rectVal = getRectValue();
785             Vector<UChar> result;
786             result.reserveInitialCapacity(32);
787             append(result, rectParen);
788 
789             append(result, rectVal->top()->cssText());
790             result.append(' ');
791 
792             append(result, rectVal->right()->cssText());
793             result.append(' ');
794 
795             append(result, rectVal->bottom()->cssText());
796             result.append(' ');
797 
798             append(result, rectVal->left()->cssText());
799             result.append(')');
800 
801             return String::adopt(result);
802         }
803         case CSS_RGBCOLOR:
804         case CSS_PARSER_HEXCOLOR: {
805             DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
806             DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb("));
807             DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
808 
809             RGBA32 rgbColor = m_value.rgbcolor;
810             if (m_type == CSS_PARSER_HEXCOLOR)
811                 Color::parseHexColor(m_value.string, rgbColor);
812             Color color(rgbColor);
813 
814             Vector<UChar> result;
815             result.reserveInitialCapacity(32);
816             if (color.hasAlpha())
817                 append(result, rgbaParen);
818             else
819                 append(result, rgbParen);
820 
821             appendNumber(result, static_cast<unsigned char>(color.red()));
822             append(result, commaSpace);
823 
824             appendNumber(result, static_cast<unsigned char>(color.green()));
825             append(result, commaSpace);
826 
827             appendNumber(result, static_cast<unsigned char>(color.blue()));
828             if (color.hasAlpha()) {
829                 append(result, commaSpace);
830                 append(result, String::number(static_cast<float>(color.alpha()) / 256.0f));
831             }
832 
833             result.append(')');
834             return String::adopt(result);
835         }
836         case CSS_PAIR:
837             text = m_value.pair->first()->cssText();
838             text += " ";
839             text += m_value.pair->second()->cssText();
840             break;
841 #if ENABLE(DASHBOARD_SUPPORT)
842         case CSS_DASHBOARD_REGION:
843             for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) {
844                 if (!text.isEmpty())
845                     text.append(' ');
846                 text += "dashboard-region(";
847                 text += region->m_label;
848                 if (region->m_isCircle)
849                     text += " circle";
850                 else if (region->m_isRectangle)
851                     text += " rectangle";
852                 else
853                     break;
854                 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) {
855                     ASSERT(region->right()->m_type == CSS_IDENT);
856                     ASSERT(region->bottom()->m_type == CSS_IDENT);
857                     ASSERT(region->left()->m_type == CSS_IDENT);
858                     ASSERT(region->right()->getIdent() == CSSValueInvalid);
859                     ASSERT(region->bottom()->getIdent() == CSSValueInvalid);
860                     ASSERT(region->left()->getIdent() == CSSValueInvalid);
861                 } else {
862                     text.append(' ');
863                     text += region->top()->cssText() + " ";
864                     text += region->right()->cssText() + " ";
865                     text += region->bottom()->cssText() + " ";
866                     text += region->left()->cssText();
867                 }
868                 text += ")";
869             }
870             break;
871 #endif
872         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
873             text = "-webkit-var(";
874             text += m_value.string;
875             text += ")";
876             break;
877         case CSS_PARSER_OPERATOR: {
878             char c = static_cast<char>(m_value.ident);
879             text = String(&c, 1U);
880             break;
881         }
882         case CSS_PARSER_IDENTIFIER:
883             text = quoteStringIfNeeded(m_value.string);
884             break;
885     }
886     return text;
887 }
888 
parserValue() const889 CSSParserValue CSSPrimitiveValue::parserValue() const
890 {
891     // We only have to handle a subset of types.
892     CSSParserValue value;
893     value.id = 0;
894     value.isInt = false;
895     value.unit = CSSPrimitiveValue::CSS_IDENT;
896     switch (m_type) {
897         case CSS_NUMBER:
898         case CSS_PERCENTAGE:
899         case CSS_EMS:
900         case CSS_EXS:
901         case CSS_REMS:
902         case CSS_PX:
903         case CSS_CM:
904         case CSS_MM:
905         case CSS_IN:
906         case CSS_PT:
907         case CSS_PC:
908         case CSS_DEG:
909         case CSS_RAD:
910         case CSS_GRAD:
911         case CSS_MS:
912         case CSS_S:
913         case CSS_HZ:
914         case CSS_KHZ:
915         case CSS_DIMENSION:
916         case CSS_TURN:
917             value.fValue = m_value.num;
918             value.unit = m_type;
919             break;
920         case CSS_STRING:
921         case CSS_URI:
922         case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX:
923         case CSS_PARSER_HEXCOLOR:
924             value.string.characters = const_cast<UChar*>(m_value.string->characters());
925             value.string.length = m_value.string->length();
926             value.unit = m_type;
927             break;
928         case CSS_IDENT: {
929             value.id = m_value.ident;
930             String name = valueOrPropertyName(m_value.ident);
931             value.string.characters = const_cast<UChar*>(name.characters());
932             value.string.length = name.length();
933             break;
934         }
935         case CSS_PARSER_OPERATOR:
936             value.iValue = m_value.ident;
937             value.unit = CSSParserValue::Operator;
938             break;
939         case CSS_PARSER_INTEGER:
940             value.fValue = m_value.num;
941             value.unit = CSSPrimitiveValue::CSS_NUMBER;
942             value.isInt = true;
943             break;
944         case CSS_PARSER_IDENTIFIER:
945             value.string.characters = const_cast<UChar*>(m_value.string->characters());
946             value.string.length = m_value.string->length();
947             value.unit = CSSPrimitiveValue::CSS_IDENT;
948             break;
949         case CSS_UNKNOWN:
950         case CSS_ATTR:
951         case CSS_COUNTER:
952         case CSS_RECT:
953         case CSS_RGBCOLOR:
954         case CSS_PAIR:
955 #if ENABLE(DASHBOARD_SUPPORT)
956         case CSS_DASHBOARD_REGION:
957 #endif
958             ASSERT_NOT_REACHED();
959             break;
960     }
961 
962     return value;
963 }
964 
addSubresourceStyleURLs(ListHashSet<KURL> & urls,const CSSStyleSheet * styleSheet)965 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
966 {
967     if (m_type == CSS_URI)
968         addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
969 }
970 
971 } // namespace WebCore
972