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 "CSSParser.h"
26 #include "CSSPropertyNames.h"
27 #include "CSSStyleSheet.h"
28 #include "CSSValueKeywords.h"
29 #include "Color.h"
30 #include "Counter.h"
31 #include "ExceptionCode.h"
32 #include "Node.h"
33 #include "Pair.h"
34 #include "RGBColor.h"
35 #include "Rect.h"
36 #include "RenderStyle.h"
37 #include <wtf/ASCIICType.h>
38 #include <wtf/DecimalNumber.h>
39 #include <wtf/MathExtras.h>
40 #include <wtf/StdLibExtras.h>
41 #include <wtf/text/StringBuffer.h>
42
43 #if ENABLE(DASHBOARD_SUPPORT)
44 #include "DashboardRegion.h"
45 #endif
46
47 using namespace WTF;
48
49 namespace WebCore {
50
unitCategory(CSSPrimitiveValue::UnitTypes type)51 static CSSPrimitiveValue::UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
52 {
53 // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
54 // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment).
55 switch (type) {
56 case CSSPrimitiveValue::CSS_NUMBER:
57 return CSSPrimitiveValue::UNumber;
58 case CSSPrimitiveValue::CSS_PERCENTAGE:
59 return CSSPrimitiveValue::UPercent;
60 case CSSPrimitiveValue::CSS_PX:
61 case CSSPrimitiveValue::CSS_CM:
62 case CSSPrimitiveValue::CSS_MM:
63 case CSSPrimitiveValue::CSS_IN:
64 case CSSPrimitiveValue::CSS_PT:
65 case CSSPrimitiveValue::CSS_PC:
66 return CSSPrimitiveValue::ULength;
67 case CSSPrimitiveValue::CSS_MS:
68 case CSSPrimitiveValue::CSS_S:
69 return CSSPrimitiveValue::UTime;
70 case CSSPrimitiveValue::CSS_DEG:
71 case CSSPrimitiveValue::CSS_RAD:
72 case CSSPrimitiveValue::CSS_GRAD:
73 case CSSPrimitiveValue::CSS_TURN:
74 return CSSPrimitiveValue::UAngle;
75 case CSSPrimitiveValue::CSS_HZ:
76 case CSSPrimitiveValue::CSS_KHZ:
77 return CSSPrimitiveValue::UFrequency;
78 default:
79 return CSSPrimitiveValue::UOther;
80 }
81 }
82
83 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
cssTextCache()84 static CSSTextCache& cssTextCache()
85 {
86 DEFINE_STATIC_LOCAL(CSSTextCache, cache, ());
87 return cache;
88 }
89
valueOrPropertyName(int valueOrPropertyID)90 static const AtomicString& valueOrPropertyName(int valueOrPropertyID)
91 {
92 ASSERT_ARG(valueOrPropertyID, valueOrPropertyID >= 0);
93 ASSERT_ARG(valueOrPropertyID, valueOrPropertyID < numCSSValueKeywords || (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties));
94
95 if (valueOrPropertyID < 0)
96 return nullAtom;
97
98 if (valueOrPropertyID < numCSSValueKeywords) {
99 static AtomicString* cssValueKeywordStrings[numCSSValueKeywords];
100 if (!cssValueKeywordStrings[valueOrPropertyID])
101 cssValueKeywordStrings[valueOrPropertyID] = new AtomicString(getValueName(valueOrPropertyID));
102 return *cssValueKeywordStrings[valueOrPropertyID];
103 }
104
105 if (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties) {
106 static AtomicString* cssPropertyStrings[numCSSProperties];
107 int propertyIndex = valueOrPropertyID - firstCSSProperty;
108 if (!cssPropertyStrings[propertyIndex])
109 cssPropertyStrings[propertyIndex] = new AtomicString(getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID)));
110 return *cssPropertyStrings[propertyIndex];
111 }
112
113 return nullAtom;
114 }
115
CSSPrimitiveValue()116 CSSPrimitiveValue::CSSPrimitiveValue()
117 : m_type(0)
118 , m_hasCachedCSSText(false)
119 {
120 }
121
CSSPrimitiveValue(int ident)122 CSSPrimitiveValue::CSSPrimitiveValue(int ident)
123 : m_type(CSS_IDENT)
124 , m_hasCachedCSSText(false)
125 {
126 m_value.ident = ident;
127 }
128
CSSPrimitiveValue(double num,UnitTypes type)129 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
130 : m_type(type)
131 , m_hasCachedCSSText(false)
132 {
133 m_value.num = num;
134 }
135
CSSPrimitiveValue(const String & str,UnitTypes type)136 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
137 : m_type(type)
138 , m_hasCachedCSSText(false)
139 {
140 if ((m_value.string = str.impl()))
141 m_value.string->ref();
142 }
143
CSSPrimitiveValue(RGBA32 color)144 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
145 : m_type(CSS_RGBCOLOR)
146 , m_hasCachedCSSText(false)
147 {
148 m_value.rgbcolor = color;
149 }
150
CSSPrimitiveValue(const Length & length)151 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
152 : m_hasCachedCSSText(false)
153 {
154 switch (length.type()) {
155 case Auto:
156 m_type = CSS_IDENT;
157 m_value.ident = CSSValueAuto;
158 break;
159 case WebCore::Fixed:
160 m_type = CSS_PX;
161 m_value.num = length.value();
162 break;
163 case Intrinsic:
164 m_type = CSS_IDENT;
165 m_value.ident = CSSValueIntrinsic;
166 break;
167 case MinIntrinsic:
168 m_type = CSS_IDENT;
169 m_value.ident = CSSValueMinIntrinsic;
170 break;
171 case Percent:
172 m_type = CSS_PERCENTAGE;
173 m_value.num = length.percent();
174 break;
175 case Relative:
176 ASSERT_NOT_REACHED();
177 break;
178 }
179 }
180
init(PassRefPtr<Counter> c)181 void CSSPrimitiveValue::init(PassRefPtr<Counter> c)
182 {
183 m_type = CSS_COUNTER;
184 m_hasCachedCSSText = false;
185 m_value.counter = c.releaseRef();
186 }
187
init(PassRefPtr<Rect> r)188 void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
189 {
190 m_type = CSS_RECT;
191 m_hasCachedCSSText = false;
192 m_value.rect = r.releaseRef();
193 }
194
195 #if ENABLE(DASHBOARD_SUPPORT)
init(PassRefPtr<DashboardRegion> r)196 void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r)
197 {
198 m_type = CSS_DASHBOARD_REGION;
199 m_hasCachedCSSText = false;
200 m_value.region = r.releaseRef();
201 }
202 #endif
203
init(PassRefPtr<Pair> p)204 void CSSPrimitiveValue::init(PassRefPtr<Pair> p)
205 {
206 m_type = CSS_PAIR;
207 m_hasCachedCSSText = false;
208 m_value.pair = p.releaseRef();
209 }
210
~CSSPrimitiveValue()211 CSSPrimitiveValue::~CSSPrimitiveValue()
212 {
213 cleanup();
214 }
215
cleanup()216 void CSSPrimitiveValue::cleanup()
217 {
218 switch (m_type) {
219 case CSS_STRING:
220 case CSS_URI:
221 case CSS_ATTR:
222 case CSS_PARSER_HEXCOLOR:
223 if (m_value.string)
224 m_value.string->deref();
225 break;
226 case CSS_COUNTER:
227 m_value.counter->deref();
228 break;
229 case CSS_RECT:
230 m_value.rect->deref();
231 break;
232 case CSS_PAIR:
233 m_value.pair->deref();
234 break;
235 #if ENABLE(DASHBOARD_SUPPORT)
236 case CSS_DASHBOARD_REGION:
237 if (m_value.region)
238 m_value.region->deref();
239 break;
240 #endif
241 default:
242 break;
243 }
244
245 m_type = 0;
246 if (m_hasCachedCSSText) {
247 cssTextCache().remove(this);
248 m_hasCachedCSSText = false;
249 }
250 }
251
computeLengthInt(RenderStyle * style,RenderStyle * rootStyle)252 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle)
253 {
254 return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle));
255 }
256
computeLengthInt(RenderStyle * style,RenderStyle * rootStyle,double multiplier)257 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
258 {
259 return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle, multiplier));
260 }
261
262 // Lengths expect an int that is only 28-bits, so we have to check for a
263 // different overflow.
computeLengthIntForLength(RenderStyle * style,RenderStyle * rootStyle)264 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle)
265 {
266 return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle));
267 }
268
computeLengthIntForLength(RenderStyle * style,RenderStyle * rootStyle,double multiplier)269 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
270 {
271 return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle, multiplier));
272 }
273
computeLengthShort(RenderStyle * style,RenderStyle * rootStyle)274 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle)
275 {
276 return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle));
277 }
278
computeLengthShort(RenderStyle * style,RenderStyle * rootStyle,double multiplier)279 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
280 {
281 return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle, multiplier));
282 }
283
computeLengthFloat(RenderStyle * style,RenderStyle * rootStyle,bool computingFontSize)284 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize)
285 {
286 return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize));
287 }
288
computeLengthFloat(RenderStyle * style,RenderStyle * rootStyle,double multiplier,bool computingFontSize)289 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
290 {
291 return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
292 }
293
computeLengthDouble(RenderStyle * style,RenderStyle * rootStyle,double multiplier,bool computingFontSize)294 double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
295 {
296 unsigned short type = primitiveType();
297
298 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
299 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
300 // as well as enforcing the implicit "smart minimum." In addition the CSS property text-size-adjust is used to
301 // prevent text from zooming at all. Therefore we will not apply the zoom here if we are computing font-size.
302 bool applyZoomMultiplier = !computingFontSize;
303
304 double factor = 1.0;
305 switch (type) {
306 case CSS_EMS:
307 applyZoomMultiplier = false;
308 factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
309 break;
310 case CSS_EXS:
311 // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
312 // We really need to compute EX using fontMetrics for the original specifiedSize and not use
313 // our actual constructed rendering font.
314 applyZoomMultiplier = false;
315 factor = style->fontMetrics().xHeight();
316 break;
317 case CSS_REMS:
318 applyZoomMultiplier = false;
319 if (rootStyle)
320 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
321 break;
322 case CSS_PX:
323 break;
324 case CSS_CM:
325 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
326 break;
327 case CSS_MM:
328 factor = cssPixelsPerInch / 25.4;
329 break;
330 case CSS_IN:
331 factor = cssPixelsPerInch;
332 break;
333 case CSS_PT:
334 factor = cssPixelsPerInch / 72.0;
335 break;
336 case CSS_PC:
337 // 1 pc == 12 pt
338 factor = cssPixelsPerInch * 12.0 / 72.0;
339 break;
340 default:
341 return -1.0;
342 }
343
344 double result = getDoubleValue() * factor;
345 if (!applyZoomMultiplier || multiplier == 1.0)
346 return result;
347
348 // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from
349 // vanishing.
350 double zoomedResult = result * multiplier;
351 if (result >= 1.0)
352 zoomedResult = max(1.0, zoomedResult);
353 return zoomedResult;
354 }
355
setFloatValue(unsigned short,double,ExceptionCode & ec)356 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec)
357 {
358 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
359 // No other engine supports mutating style through this API. Computed style is always read-only anyway.
360 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
361 ec = NO_MODIFICATION_ALLOWED_ERR;
362 }
363
conversionToCanonicalUnitsScaleFactor(unsigned short unitType)364 static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType)
365 {
366 double factor = 1.0;
367 // FIXME: the switch can be replaced by an array of scale factors.
368 switch (unitType) {
369 // These are "canonical" units in their respective categories.
370 case CSSPrimitiveValue::CSS_PX:
371 case CSSPrimitiveValue::CSS_DEG:
372 case CSSPrimitiveValue::CSS_MS:
373 case CSSPrimitiveValue::CSS_HZ:
374 break;
375 case CSSPrimitiveValue::CSS_CM:
376 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
377 break;
378 case CSSPrimitiveValue::CSS_MM:
379 factor = cssPixelsPerInch / 25.4;
380 break;
381 case CSSPrimitiveValue::CSS_IN:
382 factor = cssPixelsPerInch;
383 break;
384 case CSSPrimitiveValue::CSS_PT:
385 factor = cssPixelsPerInch / 72.0;
386 break;
387 case CSSPrimitiveValue::CSS_PC:
388 factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
389 break;
390 case CSSPrimitiveValue::CSS_RAD:
391 factor = 180 / piDouble;
392 break;
393 case CSSPrimitiveValue::CSS_GRAD:
394 factor = 0.9;
395 break;
396 case CSSPrimitiveValue::CSS_TURN:
397 factor = 360;
398 break;
399 case CSSPrimitiveValue::CSS_S:
400 case CSSPrimitiveValue::CSS_KHZ:
401 factor = 1000;
402 break;
403 default:
404 break;
405 }
406
407 return factor;
408 }
409
getDoubleValue(unsigned short unitType,ExceptionCode & ec) const410 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const
411 {
412 double result = 0;
413 bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
414 if (!success) {
415 ec = INVALID_ACCESS_ERR;
416 return 0.0;
417 }
418
419 ec = 0;
420 return result;
421 }
422
getDoubleValue(unsigned short unitType) const423 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const
424 {
425 double result = 0;
426 getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
427 return result;
428 }
429
canonicalUnitTypeForCategory(UnitCategory category)430 CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
431 {
432 // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit
433 // in each category (based on unitflags).
434 switch (category) {
435 case UNumber:
436 return CSS_NUMBER;
437 case ULength:
438 return CSS_PX;
439 case UPercent:
440 return CSS_UNKNOWN; // Cannot convert between numbers and percent.
441 case UTime:
442 return CSS_MS;
443 case UAngle:
444 return CSS_DEG;
445 case UFrequency:
446 return CSS_HZ;
447 default:
448 return CSS_UNKNOWN;
449 }
450 }
451
getDoubleValueInternal(UnitTypes requestedUnitType,double * result) const452 bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const
453 {
454 if (m_type < CSS_NUMBER || (m_type > CSS_DIMENSION && m_type < CSS_TURN) || requestedUnitType < CSS_NUMBER || (requestedUnitType > CSS_DIMENSION && requestedUnitType < CSS_TURN))
455 return false;
456 if (requestedUnitType == m_type || requestedUnitType == CSS_DIMENSION) {
457 *result = m_value.num;
458 return true;
459 }
460
461 UnitTypes sourceUnitType = static_cast<UnitTypes>(m_type);
462 UnitCategory sourceCategory = unitCategory(sourceUnitType);
463 ASSERT(sourceCategory != UOther);
464
465 UnitTypes targetUnitType = requestedUnitType;
466 UnitCategory targetCategory = unitCategory(targetUnitType);
467 ASSERT(targetCategory != UOther);
468
469 // Cannot convert between unrelated unit categories if one of them is not UNumber.
470 if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
471 return false;
472
473 if (targetCategory == UNumber) {
474 // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
475 targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
476 if (targetUnitType == CSS_UNKNOWN)
477 return false;
478 }
479
480 if (sourceUnitType == CSS_NUMBER) {
481 // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode.
482 sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
483 if (sourceUnitType == CSS_UNKNOWN)
484 return false;
485 }
486
487 double convertedValue = m_value.num;
488
489 // First convert the value from m_type to canonical type.
490 double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
491 convertedValue *= factor;
492
493 // Now convert from canonical type to the target unitType.
494 factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
495 convertedValue /= factor;
496
497 *result = convertedValue;
498 return true;
499 }
500
setStringValue(unsigned short,const String &,ExceptionCode & ec)501 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec)
502 {
503 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
504 // No other engine supports mutating style through this API. Computed style is always read-only anyway.
505 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
506 ec = NO_MODIFICATION_ALLOWED_ERR;
507 }
508
getStringValue(ExceptionCode & ec) const509 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const
510 {
511 ec = 0;
512 switch (m_type) {
513 case CSS_STRING:
514 case CSS_ATTR:
515 case CSS_URI:
516 return m_value.string;
517 case CSS_IDENT:
518 return valueOrPropertyName(m_value.ident);
519 default:
520 ec = INVALID_ACCESS_ERR;
521 break;
522 }
523
524 return String();
525 }
526
getStringValue() const527 String CSSPrimitiveValue::getStringValue() const
528 {
529 switch (m_type) {
530 case CSS_STRING:
531 case CSS_ATTR:
532 case CSS_URI:
533 return m_value.string;
534 case CSS_IDENT:
535 return valueOrPropertyName(m_value.ident);
536 default:
537 break;
538 }
539
540 return String();
541 }
542
getCounterValue(ExceptionCode & ec) const543 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const
544 {
545 ec = 0;
546 if (m_type != CSS_COUNTER) {
547 ec = INVALID_ACCESS_ERR;
548 return 0;
549 }
550
551 return m_value.counter;
552 }
553
getRectValue(ExceptionCode & ec) const554 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const
555 {
556 ec = 0;
557 if (m_type != CSS_RECT) {
558 ec = INVALID_ACCESS_ERR;
559 return 0;
560 }
561
562 return m_value.rect;
563 }
564
getRGBColorValue(ExceptionCode & ec) const565 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const
566 {
567 ec = 0;
568 if (m_type != CSS_RGBCOLOR) {
569 ec = INVALID_ACCESS_ERR;
570 return 0;
571 }
572
573 // FIMXE: This should not return a new object for each invocation.
574 return RGBColor::create(m_value.rgbcolor);
575 }
576
getPairValue(ExceptionCode & ec) const577 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const
578 {
579 ec = 0;
580 if (m_type != CSS_PAIR) {
581 ec = INVALID_ACCESS_ERR;
582 return 0;
583 }
584
585 return m_value.pair;
586 }
587
cssValueType() const588 unsigned short CSSPrimitiveValue::cssValueType() const
589 {
590 return CSS_PRIMITIVE_VALUE;
591 }
592
parseString(const String &,bool)593 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/)
594 {
595 // FIXME
596 return false;
597 }
598
getIdent() const599 int CSSPrimitiveValue::getIdent() const
600 {
601 if (m_type != CSS_IDENT)
602 return 0;
603 return m_value.ident;
604 }
605
formatNumber(double number)606 static String formatNumber(double number)
607 {
608 DecimalNumber decimal(number);
609
610 StringBuffer buffer(decimal.bufferLengthForStringDecimal());
611 unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length());
612 ASSERT_UNUSED(length, length == buffer.length());
613
614 return String::adopt(buffer);
615 }
616
cssText() const617 String CSSPrimitiveValue::cssText() const
618 {
619 // FIXME: return the original value instead of a generated one (e.g. color
620 // name if it was specified) - check what spec says about this
621
622 if (m_hasCachedCSSText) {
623 ASSERT(cssTextCache().contains(this));
624 return cssTextCache().get(this);
625 }
626
627 String text;
628 switch (m_type) {
629 case CSS_UNKNOWN:
630 // FIXME
631 break;
632 case CSS_NUMBER:
633 case CSS_PARSER_INTEGER:
634 text = formatNumber(m_value.num);
635 break;
636 case CSS_PERCENTAGE:
637 text = formatNumber(m_value.num) + "%";
638 break;
639 case CSS_EMS:
640 text = formatNumber(m_value.num) + "em";
641 break;
642 case CSS_EXS:
643 text = formatNumber(m_value.num) + "ex";
644 break;
645 case CSS_REMS:
646 text = formatNumber(m_value.num) + "rem";
647 break;
648 case CSS_PX:
649 text = formatNumber(m_value.num) + "px";
650 break;
651 case CSS_CM:
652 text = formatNumber(m_value.num) + "cm";
653 break;
654 case CSS_MM:
655 text = formatNumber(m_value.num) + "mm";
656 break;
657 case CSS_IN:
658 text = formatNumber(m_value.num) + "in";
659 break;
660 case CSS_PT:
661 text = formatNumber(m_value.num) + "pt";
662 break;
663 case CSS_PC:
664 text = formatNumber(m_value.num) + "pc";
665 break;
666 case CSS_DEG:
667 text = formatNumber(m_value.num) + "deg";
668 break;
669 case CSS_RAD:
670 text = formatNumber(m_value.num) + "rad";
671 break;
672 case CSS_GRAD:
673 text = formatNumber(m_value.num) + "grad";
674 break;
675 case CSS_MS:
676 text = formatNumber(m_value.num) + "ms";
677 break;
678 case CSS_S:
679 text = formatNumber(m_value.num) + "s";
680 break;
681 case CSS_HZ:
682 text = formatNumber(m_value.num) + "hz";
683 break;
684 case CSS_KHZ:
685 text = formatNumber(m_value.num) + "khz";
686 break;
687 case CSS_TURN:
688 text = formatNumber(m_value.num) + "turn";
689 break;
690 case CSS_DIMENSION:
691 // FIXME
692 break;
693 case CSS_STRING:
694 text = quoteCSSStringIfNeeded(m_value.string);
695 break;
696 case CSS_URI:
697 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
698 break;
699 case CSS_IDENT:
700 text = valueOrPropertyName(m_value.ident);
701 break;
702 case CSS_ATTR: {
703 DEFINE_STATIC_LOCAL(const String, attrParen, ("attr("));
704
705 Vector<UChar> result;
706 result.reserveInitialCapacity(6 + m_value.string->length());
707
708 append(result, attrParen);
709 append(result, m_value.string);
710 result.uncheckedAppend(')');
711
712 text = String::adopt(result);
713 break;
714 }
715 case CSS_COUNTER_NAME:
716 text = "counter(";
717 text += m_value.string;
718 text += ")";
719 break;
720 case CSS_COUNTER:
721 text = "counter(";
722 text += String::number(m_value.num);
723 text += ")";
724 // FIXME: Add list-style and separator
725 break;
726 case CSS_RECT: {
727 DEFINE_STATIC_LOCAL(const String, rectParen, ("rect("));
728
729 Rect* rectVal = getRectValue();
730 Vector<UChar> result;
731 result.reserveInitialCapacity(32);
732 append(result, rectParen);
733
734 append(result, rectVal->top()->cssText());
735 result.append(' ');
736
737 append(result, rectVal->right()->cssText());
738 result.append(' ');
739
740 append(result, rectVal->bottom()->cssText());
741 result.append(' ');
742
743 append(result, rectVal->left()->cssText());
744 result.append(')');
745
746 text = String::adopt(result);
747 break;
748 }
749 case CSS_RGBCOLOR:
750 case CSS_PARSER_HEXCOLOR: {
751 DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
752 DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb("));
753 DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
754
755 RGBA32 rgbColor = m_value.rgbcolor;
756 if (m_type == CSS_PARSER_HEXCOLOR)
757 Color::parseHexColor(m_value.string, rgbColor);
758 Color color(rgbColor);
759
760 Vector<UChar> result;
761 result.reserveInitialCapacity(32);
762 if (color.hasAlpha())
763 append(result, rgbaParen);
764 else
765 append(result, rgbParen);
766
767 appendNumber(result, static_cast<unsigned char>(color.red()));
768 append(result, commaSpace);
769
770 appendNumber(result, static_cast<unsigned char>(color.green()));
771 append(result, commaSpace);
772
773 appendNumber(result, static_cast<unsigned char>(color.blue()));
774 if (color.hasAlpha()) {
775 append(result, commaSpace);
776 append(result, String::number(color.alpha() / 256.0f));
777 }
778
779 result.append(')');
780 text = String::adopt(result);
781 break;
782 }
783 case CSS_PAIR:
784 text = m_value.pair->first()->cssText();
785 text += " ";
786 text += m_value.pair->second()->cssText();
787 break;
788 #if ENABLE(DASHBOARD_SUPPORT)
789 case CSS_DASHBOARD_REGION:
790 for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) {
791 if (!text.isEmpty())
792 text.append(' ');
793 text += "dashboard-region(";
794 text += region->m_label;
795 if (region->m_isCircle)
796 text += " circle";
797 else if (region->m_isRectangle)
798 text += " rectangle";
799 else
800 break;
801 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) {
802 ASSERT(region->right()->m_type == CSS_IDENT);
803 ASSERT(region->bottom()->m_type == CSS_IDENT);
804 ASSERT(region->left()->m_type == CSS_IDENT);
805 ASSERT(region->right()->getIdent() == CSSValueInvalid);
806 ASSERT(region->bottom()->getIdent() == CSSValueInvalid);
807 ASSERT(region->left()->getIdent() == CSSValueInvalid);
808 } else {
809 text.append(' ');
810 text += region->top()->cssText() + " ";
811 text += region->right()->cssText() + " ";
812 text += region->bottom()->cssText() + " ";
813 text += region->left()->cssText();
814 }
815 text += ")";
816 }
817 break;
818 #endif
819 case CSS_PARSER_OPERATOR: {
820 char c = static_cast<char>(m_value.ident);
821 text = String(&c, 1U);
822 break;
823 }
824 case CSS_PARSER_IDENTIFIER:
825 text = quoteCSSStringIfNeeded(m_value.string);
826 break;
827 }
828
829 ASSERT(!cssTextCache().contains(this));
830 cssTextCache().set(this, text);
831 m_hasCachedCSSText = true;
832 return text;
833 }
834
addSubresourceStyleURLs(ListHashSet<KURL> & urls,const CSSStyleSheet * styleSheet)835 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
836 {
837 if (m_type == CSS_URI)
838 addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
839 }
840
841 } // namespace WebCore
842