2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved.
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.
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.
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.
22 #include "core/css/CSSPrimitiveValue.h"
24 #include "bindings/v8/ExceptionState.h"
25 #include "core/css/CSSBasicShapes.h"
26 #include "core/css/CSSCalculationValue.h"
27 #include "core/css/CSSHelper.h"
28 #include "core/css/CSSMarkup.h"
29 #include "core/css/CSSToLengthConversionData.h"
30 #include "core/css/Counter.h"
31 #include "core/css/Pair.h"
32 #include "core/css/RGBColor.h"
33 #include "core/css/Rect.h"
34 #include "core/css/StyleSheetContents.h"
35 #include "core/dom/ExceptionCode.h"
36 #include "core/dom/Node.h"
37 #include "core/rendering/style/RenderStyle.h"
38 #include "platform/LayoutUnit.h"
39 #include "wtf/DecimalNumber.h"
40 #include "wtf/StdLibExtras.h"
41 #include "wtf/text/StringBuffer.h"
42 #include "wtf/text/StringBuilder.h"
48 // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing.
49 // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max.
50 const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2;
51 const int minValueForCssLength = INT_MIN / kFixedPointDenominator + 2;
53 static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitTypes unitType)
56 case CSSPrimitiveValue::CSS_CALC:
57 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
58 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
59 case CSSPrimitiveValue::CSS_CM:
60 case CSSPrimitiveValue::CSS_DEG:
61 case CSSPrimitiveValue::CSS_DIMENSION:
62 case CSSPrimitiveValue::CSS_DPPX:
63 case CSSPrimitiveValue::CSS_DPI:
64 case CSSPrimitiveValue::CSS_DPCM:
65 case CSSPrimitiveValue::CSS_EMS:
66 case CSSPrimitiveValue::CSS_EXS:
67 case CSSPrimitiveValue::CSS_GRAD:
68 case CSSPrimitiveValue::CSS_HZ:
69 case CSSPrimitiveValue::CSS_IN:
70 case CSSPrimitiveValue::CSS_KHZ:
71 case CSSPrimitiveValue::CSS_MM:
72 case CSSPrimitiveValue::CSS_MS:
73 case CSSPrimitiveValue::CSS_NUMBER:
74 case CSSPrimitiveValue::CSS_PERCENTAGE:
75 case CSSPrimitiveValue::CSS_PC:
76 case CSSPrimitiveValue::CSS_PT:
77 case CSSPrimitiveValue::CSS_PX:
78 case CSSPrimitiveValue::CSS_RAD:
79 case CSSPrimitiveValue::CSS_REMS:
80 case CSSPrimitiveValue::CSS_CHS:
81 case CSSPrimitiveValue::CSS_S:
82 case CSSPrimitiveValue::CSS_TURN:
83 case CSSPrimitiveValue::CSS_VW:
84 case CSSPrimitiveValue::CSS_VH:
85 case CSSPrimitiveValue::CSS_VMIN:
86 case CSSPrimitiveValue::CSS_VMAX:
87 case CSSPrimitiveValue::CSS_FR:
89 case CSSPrimitiveValue::CSS_ATTR:
90 case CSSPrimitiveValue::CSS_COUNTER:
91 case CSSPrimitiveValue::CSS_COUNTER_NAME:
92 case CSSPrimitiveValue::CSS_IDENT:
93 case CSSPrimitiveValue::CSS_PROPERTY_ID:
94 case CSSPrimitiveValue::CSS_VALUE_ID:
95 case CSSPrimitiveValue::CSS_PAIR:
96 case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
97 case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
98 case CSSPrimitiveValue::CSS_PARSER_INTEGER:
99 case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
100 case CSSPrimitiveValue::CSS_RECT:
101 case CSSPrimitiveValue::CSS_QUAD:
102 case CSSPrimitiveValue::CSS_RGBCOLOR:
103 case CSSPrimitiveValue::CSS_SHAPE:
104 case CSSPrimitiveValue::CSS_STRING:
105 case CSSPrimitiveValue::CSS_UNICODE_RANGE:
106 case CSSPrimitiveValue::CSS_UNKNOWN:
107 case CSSPrimitiveValue::CSS_URI:
111 ASSERT_NOT_REACHED();
115 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitTypes type)
117 // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
118 // between CSS_PX and relative lengths (see cssPixelsPerInch comment in core/css/CSSHelper.h for the topic treatment).
121 return CSSPrimitiveValue::UNumber;
123 return CSSPrimitiveValue::UPercent;
130 return CSSPrimitiveValue::ULength;
133 return CSSPrimitiveValue::UTime;
138 return CSSPrimitiveValue::UAngle;
141 return CSSPrimitiveValue::UFrequency;
145 return CSSPrimitiveValue::UResolution;
147 return CSSPrimitiveValue::UOther;
151 bool CSSPrimitiveValue::colorIsDerivedFromElement() const
153 int valueID = getValueID();
155 case CSSValueWebkitText:
156 case CSSValueWebkitLink:
157 case CSSValueWebkitActivelink:
158 case CSSValueCurrentcolor:
165 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
166 static CSSTextCache& cssTextCache()
168 DEFINE_STATIC_LOCAL(CSSTextCache, cache, ());
172 unsigned short CSSPrimitiveValue::primitiveType() const
174 if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID)
177 if (m_primitiveUnitType != CSS_CALC)
178 return m_primitiveUnitType;
180 switch (m_value.calc->category()) {
184 return CSS_PERCENTAGE;
187 case CalcPercentNumber:
188 return CSS_CALC_PERCENTAGE_WITH_NUMBER;
189 case CalcPercentLength:
190 return CSS_CALC_PERCENTAGE_WITH_LENGTH;
197 static const AtomicString& propertyName(CSSPropertyID propertyID)
199 ASSERT_ARG(propertyID, propertyID >= 0);
200 ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties));
205 return getPropertyNameAtomicString(propertyID);
208 static const AtomicString& valueName(CSSValueID valueID)
210 ASSERT_ARG(valueID, valueID >= 0);
211 ASSERT_ARG(valueID, valueID < numCSSValueKeywords);
216 static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally.
217 AtomicString& keywordString = keywordStrings[valueID];
218 if (keywordString.isNull())
219 keywordString = getValueName(valueID);
220 return keywordString;
223 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
224 : CSSValue(PrimitiveClass)
226 m_primitiveUnitType = CSS_VALUE_ID;
227 m_value.valueID = valueID;
230 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
231 : CSSValue(PrimitiveClass)
233 m_primitiveUnitType = CSS_PROPERTY_ID;
234 m_value.propertyID = propertyID;
237 CSSPrimitiveValue::CSSPrimitiveValue(int parserOperator)
238 : CSSValue(PrimitiveClass)
240 m_primitiveUnitType = CSS_PARSER_OPERATOR;
241 m_value.parserOperator = parserOperator;
244 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
245 : CSSValue(PrimitiveClass)
247 m_primitiveUnitType = type;
248 ASSERT(std::isfinite(num));
252 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
253 : CSSValue(PrimitiveClass)
255 m_primitiveUnitType = type;
256 if ((m_value.string = str.impl()))
257 m_value.string->ref();
260 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize)
261 : CSSValue(PrimitiveClass)
266 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
267 : CSSValue(PrimitiveClass)
269 m_primitiveUnitType = CSS_RGBCOLOR;
270 m_value.rgbcolor = color;
273 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, float zoom)
274 : CSSValue(PrimitiveClass)
276 switch (length.type()) {
289 m_primitiveUnitType = CSS_PX;
290 m_value.num = length.value() / zoom;
293 init(CSSCalcValue::create(length.calculationValue(), zoom));
298 ASSERT_NOT_REACHED();
303 // Remove below specialized constructors once all callers of CSSPrimitiveValue(...)
304 // have been converted to PassRefPtrWillBeRawPtr, ie. when
305 // template<typename T> CSSPrimitiveValue(T* val)
306 // template<typename T> CSSPrimitiveValue(PassRefPtr<T> val)
307 // both can be converted to use PassRefPtrWillBeRawPtr.
308 CSSPrimitiveValue::CSSPrimitiveValue(CSSCalcValue* value)
309 : CSSValue(PrimitiveClass)
311 init(PassRefPtrWillBeRawPtr<CSSCalcValue>(value));
313 CSSPrimitiveValue::CSSPrimitiveValue(PassRefPtrWillBeRawPtr<CSSCalcValue> value)
314 : CSSValue(PrimitiveClass)
318 CSSPrimitiveValue::CSSPrimitiveValue(Pair* value)
319 : CSSValue(PrimitiveClass)
321 init(PassRefPtrWillBeRawPtr<Pair>(value));
323 CSSPrimitiveValue::CSSPrimitiveValue(PassRefPtrWillBeRawPtr<Pair> value)
324 : CSSValue(PrimitiveClass)
328 CSSPrimitiveValue::CSSPrimitiveValue(Counter* value)
329 : CSSValue(PrimitiveClass)
331 init(PassRefPtrWillBeRawPtr<Counter>(value));
333 CSSPrimitiveValue::CSSPrimitiveValue(PassRefPtrWillBeRawPtr<Counter> value)
334 : CSSValue(PrimitiveClass)
339 void CSSPrimitiveValue::init(const Length& length)
341 switch (length.type()) {
343 m_primitiveUnitType = CSS_VALUE_ID;
344 m_value.valueID = CSSValueAuto;
347 m_primitiveUnitType = CSS_PX;
348 m_value.num = length.value();
351 m_primitiveUnitType = CSS_VALUE_ID;
352 m_value.valueID = CSSValueIntrinsic;
355 m_primitiveUnitType = CSS_VALUE_ID;
356 m_value.valueID = CSSValueMinIntrinsic;
359 m_primitiveUnitType = CSS_VALUE_ID;
360 m_value.valueID = CSSValueMinContent;
363 m_primitiveUnitType = CSS_VALUE_ID;
364 m_value.valueID = CSSValueMaxContent;
367 m_primitiveUnitType = CSS_VALUE_ID;
368 m_value.valueID = CSSValueWebkitFillAvailable;
371 m_primitiveUnitType = CSS_VALUE_ID;
372 m_value.valueID = CSSValueWebkitFitContent;
375 m_primitiveUnitType = CSS_VALUE_ID;
376 m_value.valueID = CSSValueInternalExtendToZoom;
379 m_primitiveUnitType = CSS_PERCENTAGE;
380 ASSERT(std::isfinite(length.percent()));
381 m_value.num = length.percent();
387 ASSERT_NOT_REACHED();
392 void CSSPrimitiveValue::init(const LengthSize& lengthSize)
394 m_primitiveUnitType = CSS_PAIR;
395 m_hasCachedCSSText = false;
396 m_value.pair = Pair::create(create(lengthSize.width()), create(lengthSize.height()), Pair::KeepIdenticalValues).leakRef();
399 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Counter> c)
401 m_primitiveUnitType = CSS_COUNTER;
402 m_hasCachedCSSText = false;
403 m_value.counter = c.leakRef();
406 void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
408 m_primitiveUnitType = CSS_RECT;
409 m_hasCachedCSSText = false;
410 m_value.rect = r.leakRef();
413 void CSSPrimitiveValue::init(PassRefPtr<Quad> quad)
415 m_primitiveUnitType = CSS_QUAD;
416 m_hasCachedCSSText = false;
417 m_value.quad = quad.leakRef();
420 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Pair> p)
422 m_primitiveUnitType = CSS_PAIR;
423 m_hasCachedCSSText = false;
424 m_value.pair = p.leakRef();
427 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSCalcValue> c)
429 m_primitiveUnitType = CSS_CALC;
430 m_hasCachedCSSText = false;
431 m_value.calc = c.leakRef();
434 void CSSPrimitiveValue::init(PassRefPtr<CSSBasicShape> shape)
436 m_primitiveUnitType = CSS_SHAPE;
437 m_hasCachedCSSText = false;
438 m_value.shape = shape.leakRef();
441 CSSPrimitiveValue::~CSSPrimitiveValue()
446 void CSSPrimitiveValue::cleanup()
448 switch (static_cast<UnitTypes>(m_primitiveUnitType)) {
452 case CSS_COUNTER_NAME:
453 case CSS_PARSER_HEXCOLOR:
455 m_value.string->deref();
458 // We must not call deref() when oilpan is enabled because m_value.counter is traced.
460 m_value.counter->deref();
464 m_value.rect->deref();
467 m_value.quad->deref();
470 // We must not call deref() when oilpan is enabled because m_value.pair is traced.
472 m_value.pair->deref();
476 // We must not call deref() when oilpan is enabled because m_value.calc is traced.
478 m_value.calc->deref();
481 case CSS_CALC_PERCENTAGE_WITH_NUMBER:
482 case CSS_CALC_PERCENTAGE_WITH_LENGTH:
483 ASSERT_NOT_REACHED();
486 m_value.shape->deref();
489 case CSS_PARSER_INTEGER:
521 case CSS_UNICODE_RANGE:
522 case CSS_PARSER_OPERATOR:
523 case CSS_PARSER_IDENTIFIER:
524 case CSS_PROPERTY_ID:
528 m_primitiveUnitType = 0;
529 if (m_hasCachedCSSText) {
530 cssTextCache().remove(this);
531 m_hasCachedCSSText = false;
535 double CSSPrimitiveValue::computeDegrees()
537 switch (m_primitiveUnitType) {
539 return getDoubleValue();
541 return rad2deg(getDoubleValue());
543 return grad2deg(getDoubleValue());
545 return turn2deg(getDoubleValue());
547 ASSERT_NOT_REACHED();
552 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
554 return roundForImpreciseConversion<int>(computeLengthDouble(conversionData));
557 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
559 return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData));
562 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
564 return Length(clampTo<float>(computeLengthDouble(conversionData), minValueForCssLength, maxValueForCssLength), Fixed);
567 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
569 return roundForImpreciseConversion<short>(computeLengthDouble(conversionData));
572 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
574 return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData));
577 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
579 return static_cast<float>(computeLengthDouble(conversionData));
582 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
584 return computeLengthDouble(conversionData);
587 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData)
589 if (m_primitiveUnitType == CSS_CALC)
590 return m_value.calc->computeLengthPx(conversionData);
592 const RenderStyle& style = conversionData.style();
593 const RenderStyle& rootStyle = conversionData.rootStyle();
594 bool computingFontSize = conversionData.computingFontSize();
598 switch (primitiveType()) {
600 factor = computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize();
603 // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
604 // We really need to compute EX using fontMetrics for the original specifiedSize and not use
605 // our actual constructed rendering font.
606 if (style.fontMetrics().hasXHeight())
607 factor = style.fontMetrics().xHeight();
609 factor = (computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize()) / 2.0;
612 factor = computingFontSize ? rootStyle.fontDescription().specifiedSize() : rootStyle.fontDescription().computedSize();
615 factor = style.fontMetrics().zeroWidth();
621 factor = cssPixelsPerCentimeter;
624 factor = cssPixelsPerMillimeter;
627 factor = cssPixelsPerInch;
630 factor = cssPixelsPerPoint;
633 factor = cssPixelsPerPica;
636 factor = conversionData.viewportWidthPercent();
639 factor = conversionData.viewportHeightPercent();
642 factor = conversionData.viewportMinPercent();
645 factor = conversionData.viewportMaxPercent();
647 case CSS_CALC_PERCENTAGE_WITH_LENGTH:
648 case CSS_CALC_PERCENTAGE_WITH_NUMBER:
649 ASSERT_NOT_REACHED();
652 ASSERT_NOT_REACHED();
656 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
657 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
658 // as well as enforcing the implicit "smart minimum."
659 double result = getDoubleValue() * factor;
660 if (computingFontSize || isFontRelativeLength())
663 return result * conversionData.zoom();
666 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionState& exceptionState)
668 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
669 // No other engine supports mutating style through this API. Computed style is always read-only anyway.
670 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
671 exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only.");
674 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(unsigned short unitType)
677 // FIXME: the switch can be replaced by an array of scale factors.
679 // These are "canonical" units in their respective categories.
686 factor = cssPixelsPerCentimeter;
689 factor = 1 / cssPixelsPerCentimeter;
692 factor = cssPixelsPerMillimeter;
695 factor = cssPixelsPerInch;
698 factor = 1 / cssPixelsPerInch;
701 factor = cssPixelsPerPoint;
704 factor = cssPixelsPerPica;
707 factor = 180 / piDouble;
726 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionState& exceptionState) const
729 bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
731 exceptionState.throwDOMException(InvalidAccessError, "Failed to obtain a double value.");
738 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const
741 getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
745 double CSSPrimitiveValue::getDoubleValue() const
747 return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue();
750 CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
752 // The canonical unit type is chosen according to the way BisonCSSParser::validUnit() chooses the default unit
753 // in each category (based on unitflags).
760 return CSS_UNKNOWN; // Cannot convert between numbers and percent.
774 bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const
776 if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitTypes>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType))
779 UnitTypes sourceUnitType = static_cast<UnitTypes>(primitiveType());
780 if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) {
781 *result = getDoubleValue();
785 UnitCategory sourceCategory = unitCategory(sourceUnitType);
786 ASSERT(sourceCategory != UOther);
788 UnitTypes targetUnitType = requestedUnitType;
789 UnitCategory targetCategory = unitCategory(targetUnitType);
790 ASSERT(targetCategory != UOther);
792 // Cannot convert between unrelated unit categories if one of them is not UNumber.
793 if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
796 if (targetCategory == UNumber) {
797 // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
798 targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
799 if (targetUnitType == CSS_UNKNOWN)
803 if (sourceUnitType == CSS_NUMBER) {
804 // We interpret conversion from CSS_NUMBER in the same way as BisonCSSParser::validUnit() while using non-strict mode.
805 sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
806 if (sourceUnitType == CSS_UNKNOWN)
810 double convertedValue = getDoubleValue();
812 // First convert the value from m_primitiveUnitType to canonical type.
813 double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
814 convertedValue *= factor;
816 // Now convert from canonical type to the target unitType.
817 factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
818 convertedValue /= factor;
820 *result = convertedValue;
824 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionState& exceptionState)
826 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
827 // No other engine supports mutating style through this API. Computed style is always read-only anyway.
828 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
829 exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only.");
832 String CSSPrimitiveValue::getStringValue(ExceptionState& exceptionState) const
834 switch (m_primitiveUnitType) {
838 return m_value.string;
840 return valueName(m_value.valueID);
841 case CSS_PROPERTY_ID:
842 return propertyName(m_value.propertyID);
844 exceptionState.throwDOMException(InvalidAccessError, "This object's value cannot be represented as a string.");
851 String CSSPrimitiveValue::getStringValue() const
853 switch (m_primitiveUnitType) {
857 return m_value.string;
859 return valueName(m_value.valueID);
860 case CSS_PROPERTY_ID:
861 return propertyName(m_value.propertyID);
869 Counter* CSSPrimitiveValue::getCounterValue(ExceptionState& exceptionState) const
871 if (m_primitiveUnitType != CSS_COUNTER) {
872 exceptionState.throwDOMException(InvalidAccessError, "This object is not a counter value.");
876 return m_value.counter;
879 Rect* CSSPrimitiveValue::getRectValue(ExceptionState& exceptionState) const
881 if (m_primitiveUnitType != CSS_RECT) {
882 exceptionState.throwDOMException(InvalidAccessError, "This object is not a rect value.");
889 Quad* CSSPrimitiveValue::getQuadValue(ExceptionState& exceptionState) const
891 if (m_primitiveUnitType != CSS_QUAD) {
892 exceptionState.throwDOMException(InvalidAccessError, "This object is not a quad value.");
899 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionState& exceptionState) const
901 if (m_primitiveUnitType != CSS_RGBCOLOR) {
902 exceptionState.throwDOMException(InvalidAccessError, "This object is not an RGB color value.");
906 // FIMXE: This should not return a new object for each invocation.
907 return RGBColor::create(m_value.rgbcolor);
910 Pair* CSSPrimitiveValue::getPairValue(ExceptionState& exceptionState) const
912 if (m_primitiveUnitType != CSS_PAIR) {
913 exceptionState.throwDOMException(InvalidAccessError, "This object is not a pair value.");
920 static String formatNumber(double number, const char* suffix, unsigned suffixLength)
922 DecimalNumber decimal(number);
924 StringBuffer<LChar> buffer(decimal.bufferLengthForStringDecimal() + suffixLength);
925 unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length());
926 ASSERT(length + suffixLength == buffer.length());
928 for (unsigned i = 0; i < suffixLength; ++i)
929 buffer[length + i] = static_cast<LChar>(suffix[i]);
931 return String::adopt(buffer);
934 template <unsigned characterCount>
935 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount])
937 return formatNumber(number, characters, characterCount - 1);
940 String CSSPrimitiveValue::customCSSText(CSSTextFormattingFlags formattingFlag) const
942 // FIXME: return the original value instead of a generated one (e.g. color
943 // name if it was specified) - check what spec says about this
945 if (m_hasCachedCSSText) {
946 ASSERT(cssTextCache().contains(this));
947 return cssTextCache().get(this);
951 switch (m_primitiveUnitType) {
956 case CSS_PARSER_INTEGER:
957 text = formatNumber(m_value.num, "");
960 text = formatNumber(m_value.num, "%");
963 text = formatNumber(m_value.num, "em");
966 text = formatNumber(m_value.num, "ex");
969 text = formatNumber(m_value.num, "rem");
972 text = formatNumber(m_value.num, "ch");
975 text = formatNumber(m_value.num, "px");
978 text = formatNumber(m_value.num, "cm");
981 text = formatNumber(m_value.num, "dppx");
984 text = formatNumber(m_value.num, "dpi");
987 text = formatNumber(m_value.num, "dpcm");
990 text = formatNumber(m_value.num, "mm");
993 text = formatNumber(m_value.num, "in");
996 text = formatNumber(m_value.num, "pt");
999 text = formatNumber(m_value.num, "pc");
1002 text = formatNumber(m_value.num, "deg");
1005 text = formatNumber(m_value.num, "rad");
1008 text = formatNumber(m_value.num, "grad");
1011 text = formatNumber(m_value.num, "ms");
1014 text = formatNumber(m_value.num, "s");
1017 text = formatNumber(m_value.num, "hz");
1020 text = formatNumber(m_value.num, "khz");
1023 text = formatNumber(m_value.num, "turn");
1026 // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store
1027 // the actual dimension, just the numeric value as a string.
1030 text = formattingFlag == AlwaysQuoteCSSString ? quoteCSSString(m_value.string) : quoteCSSStringIfNeeded(m_value.string);
1033 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
1036 text = valueName(m_value.valueID);
1038 case CSS_PROPERTY_ID:
1039 text = propertyName(m_value.propertyID);
1042 StringBuilder result;
1043 result.reserveCapacity(6 + m_value.string->length());
1044 result.appendLiteral("attr(");
1045 result.append(m_value.string);
1048 text = result.toString();
1051 case CSS_COUNTER_NAME:
1052 text = "counter(" + String(m_value.string) + ')';
1055 StringBuilder result;
1056 String separator = m_value.counter->separator();
1057 if (separator.isEmpty())
1058 result.appendLiteral("counter(");
1060 result.appendLiteral("counters(");
1062 result.append(m_value.counter->identifier());
1063 if (!separator.isEmpty()) {
1064 result.appendLiteral(", ");
1065 result.append(quoteCSSStringIfNeeded(separator));
1067 String listStyle = m_value.counter->listStyle();
1068 if (!listStyle.isEmpty()) {
1069 result.appendLiteral(", ");
1070 result.append(listStyle);
1074 text = result.toString();
1078 text = getRectValue()->cssText();
1081 text = getQuadValue()->cssText();
1084 case CSS_PARSER_HEXCOLOR: {
1085 RGBA32 rgbColor = m_value.rgbcolor;
1086 if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR)
1087 Color::parseHexColor(m_value.string, rgbColor);
1088 Color color(rgbColor);
1089 text = color.serializedAsCSSComponentValue();
1093 text = formatNumber(m_value.num, "fr");
1096 text = getPairValue()->cssText();
1098 case CSS_PARSER_OPERATOR: {
1099 char c = static_cast<char>(m_value.parserOperator);
1100 text = String(&c, 1U);
1103 case CSS_PARSER_IDENTIFIER:
1104 text = quoteCSSStringIfNeeded(m_value.string);
1107 text = m_value.calc->cssText();
1110 text = m_value.shape->cssText();
1113 text = formatNumber(m_value.num, "vw");
1116 text = formatNumber(m_value.num, "vh");
1119 text = formatNumber(m_value.num, "vmin");
1122 text = formatNumber(m_value.num, "vmax");
1126 ASSERT(!cssTextCache().contains(this));
1127 cssTextCache().set(this, text);
1128 m_hasCachedCSSText = true;
1132 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPrimitiveValue::cloneForCSSOM() const
1134 RefPtrWillBeRawPtr<CSSPrimitiveValue> result;
1136 switch (m_primitiveUnitType) {
1140 case CSS_COUNTER_NAME:
1141 result = CSSPrimitiveValue::create(m_value.string, static_cast<UnitTypes>(m_primitiveUnitType));
1144 result = CSSPrimitiveValue::create(m_value.counter->cloneForCSSOM());
1147 result = CSSPrimitiveValue::create(m_value.rect->cloneForCSSOM());
1150 result = CSSPrimitiveValue::create(m_value.quad->cloneForCSSOM());
1153 // Pair is not exposed to the CSSOM, no need for a deep clone.
1154 result = CSSPrimitiveValue::create(m_value.pair);
1157 // CSSCalcValue is not exposed to the CSSOM, no need for a deep clone.
1158 result = CSSPrimitiveValue::create(m_value.calc);
1161 // CSSShapeValue is not exposed to the CSSOM, no need for a deep clone.
1162 result = CSSPrimitiveValue::create(m_value.shape);
1165 case CSS_PARSER_INTEGER:
1166 case CSS_PERCENTAGE:
1193 result = CSSPrimitiveValue::create(m_value.num, static_cast<UnitTypes>(m_primitiveUnitType));
1195 case CSS_PROPERTY_ID:
1196 result = CSSPrimitiveValue::createIdentifier(m_value.propertyID);
1199 result = CSSPrimitiveValue::createIdentifier(m_value.valueID);
1202 result = CSSPrimitiveValue::createColor(m_value.rgbcolor);
1206 case CSS_PARSER_OPERATOR:
1207 case CSS_PARSER_IDENTIFIER:
1208 case CSS_PARSER_HEXCOLOR:
1209 ASSERT_NOT_REACHED();
1213 result->setCSSOMSafe();
1218 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
1220 if (m_primitiveUnitType != other.m_primitiveUnitType)
1223 switch (m_primitiveUnitType) {
1227 case CSS_PARSER_INTEGER:
1228 case CSS_PERCENTAGE:
1255 return m_value.num == other.m_value.num;
1256 case CSS_PROPERTY_ID:
1257 return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID);
1259 return valueName(m_value.valueID) == valueName(other.m_value.valueID);
1263 case CSS_COUNTER_NAME:
1264 case CSS_PARSER_IDENTIFIER:
1265 case CSS_PARSER_HEXCOLOR:
1266 return equal(m_value.string, other.m_value.string);
1268 return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter);
1270 return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect);
1272 return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad);
1274 return m_value.rgbcolor == other.m_value.rgbcolor;
1276 return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair);
1277 case CSS_PARSER_OPERATOR:
1278 return m_value.parserOperator == other.m_value.parserOperator;
1280 return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
1282 return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
1287 void CSSPrimitiveValue::traceAfterDispatch(Visitor* visitor)
1289 switch (m_primitiveUnitType) {
1291 visitor->trace(m_value.counter);
1294 visitor->trace(m_value.pair);
1297 visitor->trace(m_value.calc);
1302 CSSValue::traceAfterDispatch(visitor);
1305 } // namespace WebCore