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