• 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 "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