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