summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/css/CSSPrimitiveValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/css/CSSPrimitiveValue.cpp')
-rw-r--r--Source/WebCore/css/CSSPrimitiveValue.cpp998
1 files changed, 998 insertions, 0 deletions
diff --git a/Source/WebCore/css/CSSPrimitiveValue.cpp b/Source/WebCore/css/CSSPrimitiveValue.cpp
new file mode 100644
index 0000000..ce1b87b
--- /dev/null
+++ b/Source/WebCore/css/CSSPrimitiveValue.cpp
@@ -0,0 +1,998 @@
+/*
+ * (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "CSSPrimitiveValue.h"
+
+#include "CSSHelper.h"
+#include "CSSParser.h"
+#include "CSSPropertyNames.h"
+#include "CSSStyleSheet.h"
+#include "CSSValueKeywords.h"
+#include "Color.h"
+#include "Counter.h"
+#include "ExceptionCode.h"
+#include "Node.h"
+#include "Pair.h"
+#include "RGBColor.h"
+#include "Rect.h"
+#include "RenderStyle.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/DecimalNumber.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringBuffer.h>
+
+#if ENABLE(DASHBOARD_SUPPORT)
+#include "DashboardRegion.h"
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+static CSSPrimitiveValue::UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
+{
+ // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
+ // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment).
+ switch (type) {
+ case CSSPrimitiveValue::CSS_NUMBER:
+ return CSSPrimitiveValue::UNumber;
+ case CSSPrimitiveValue::CSS_PERCENTAGE:
+ return CSSPrimitiveValue::UPercent;
+ case CSSPrimitiveValue::CSS_PX:
+ case CSSPrimitiveValue::CSS_CM:
+ case CSSPrimitiveValue::CSS_MM:
+ case CSSPrimitiveValue::CSS_IN:
+ case CSSPrimitiveValue::CSS_PT:
+ case CSSPrimitiveValue::CSS_PC:
+ return CSSPrimitiveValue::ULength;
+ case CSSPrimitiveValue::CSS_MS:
+ case CSSPrimitiveValue::CSS_S:
+ return CSSPrimitiveValue::UTime;
+ case CSSPrimitiveValue::CSS_DEG:
+ case CSSPrimitiveValue::CSS_RAD:
+ case CSSPrimitiveValue::CSS_GRAD:
+ case CSSPrimitiveValue::CSS_TURN:
+ return CSSPrimitiveValue::UAngle;
+ case CSSPrimitiveValue::CSS_HZ:
+ case CSSPrimitiveValue::CSS_KHZ:
+ return CSSPrimitiveValue::UFrequency;
+ default:
+ return CSSPrimitiveValue::UOther;
+ }
+}
+
+typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
+static CSSTextCache& cssTextCache()
+{
+ DEFINE_STATIC_LOCAL(CSSTextCache, cache, ());
+ return cache;
+}
+
+// A more stylish solution than sharing would be to turn CSSPrimitiveValue (or CSSValues in general) into non-virtual,
+// non-refcounted simple type with value semantics. In practice these sharing tricks get similar memory benefits
+// with less need for refactoring.
+
+inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncachedIdentifier(int identifier)
+{
+ return adoptRef(new CSSPrimitiveValue(identifier));
+}
+
+inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncachedColor(unsigned rgbValue)
+{
+ return adoptRef(new CSSPrimitiveValue(rgbValue));
+}
+
+inline PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createUncached(double value, UnitTypes type)
+{
+ return adoptRef(new CSSPrimitiveValue(value, type));
+}
+
+PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createIdentifier(int ident)
+{
+ static RefPtr<CSSPrimitiveValue>* identValueCache = new RefPtr<CSSPrimitiveValue>[numCSSValueKeywords];
+ if (ident >= 0 && ident < numCSSValueKeywords) {
+ RefPtr<CSSPrimitiveValue> primitiveValue = identValueCache[ident];
+ if (!primitiveValue) {
+ primitiveValue = createUncachedIdentifier(ident);
+ identValueCache[ident] = primitiveValue;
+ }
+ return primitiveValue.release();
+ }
+ return createUncachedIdentifier(ident);
+}
+
+PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createColor(unsigned rgbValue)
+{
+ typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache;
+ static ColorValueCache* colorValueCache = new ColorValueCache;
+ // These are the empty and deleted values of the hash table.
+ if (rgbValue == Color::transparent) {
+ static CSSPrimitiveValue* colorTransparent = createUncachedColor(Color::transparent).releaseRef();
+ return colorTransparent;
+ }
+ if (rgbValue == Color::white) {
+ static CSSPrimitiveValue* colorWhite = createUncachedColor(Color::white).releaseRef();
+ return colorWhite;
+ }
+ RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue);
+ if (primitiveValue)
+ return primitiveValue.release();
+ primitiveValue = createUncachedColor(rgbValue);
+ // Just wipe out the cache and start rebuilding when it gets too big.
+ const int maxColorCacheSize = 512;
+ if (colorValueCache->size() >= maxColorCacheSize)
+ colorValueCache->clear();
+ colorValueCache->add(rgbValue, primitiveValue);
+
+ return primitiveValue.release();
+}
+
+PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(double value, UnitTypes type)
+{
+ // Small integers are very common. Try to share them.
+ const int cachedIntegerCount = 128;
+ // Other common primitive types have UnitTypes smaller than this.
+ const int maxCachedUnitType = CSS_PX;
+ typedef RefPtr<CSSPrimitiveValue>(* IntegerValueCache)[maxCachedUnitType + 1];
+ static IntegerValueCache integerValueCache = new RefPtr<CSSPrimitiveValue>[cachedIntegerCount][maxCachedUnitType + 1];
+ if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) {
+ int intValue = static_cast<int>(value);
+ if (value == intValue) {
+ RefPtr<CSSPrimitiveValue> primitiveValue = integerValueCache[intValue][type];
+ if (!primitiveValue) {
+ primitiveValue = createUncached(value, type);
+ integerValueCache[intValue][type] = primitiveValue;
+ }
+ return primitiveValue.release();
+ }
+ }
+
+ return createUncached(value, type);
+}
+
+PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type)
+{
+ return adoptRef(new CSSPrimitiveValue(value, type));
+}
+
+static const AtomicString& valueOrPropertyName(int valueOrPropertyID)
+{
+ ASSERT_ARG(valueOrPropertyID, valueOrPropertyID >= 0);
+ ASSERT_ARG(valueOrPropertyID, valueOrPropertyID < numCSSValueKeywords || (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties));
+
+ if (valueOrPropertyID < 0)
+ return nullAtom;
+
+ if (valueOrPropertyID < numCSSValueKeywords) {
+ static AtomicString* cssValueKeywordStrings[numCSSValueKeywords];
+ if (!cssValueKeywordStrings[valueOrPropertyID])
+ cssValueKeywordStrings[valueOrPropertyID] = new AtomicString(getValueName(valueOrPropertyID));
+ return *cssValueKeywordStrings[valueOrPropertyID];
+ }
+
+ if (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties) {
+ static AtomicString* cssPropertyStrings[numCSSProperties];
+ int propertyIndex = valueOrPropertyID - firstCSSProperty;
+ if (!cssPropertyStrings[propertyIndex])
+ cssPropertyStrings[propertyIndex] = new AtomicString(getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID)));
+ return *cssPropertyStrings[propertyIndex];
+ }
+
+ return nullAtom;
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue()
+ : m_type(0)
+ , m_hasCachedCSSText(false)
+{
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue(int ident)
+ : m_type(CSS_IDENT)
+ , m_hasCachedCSSText(false)
+{
+ m_value.ident = ident;
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type)
+ : m_type(type)
+ , m_hasCachedCSSText(false)
+{
+ m_value.num = num;
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type)
+ : m_type(type)
+ , m_hasCachedCSSText(false)
+{
+ if ((m_value.string = str.impl()))
+ m_value.string->ref();
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
+ : m_type(CSS_RGBCOLOR)
+ , m_hasCachedCSSText(false)
+{
+ m_value.rgbcolor = color;
+}
+
+CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
+ : m_hasCachedCSSText(false)
+{
+ switch (length.type()) {
+ case Auto:
+ m_type = CSS_IDENT;
+ m_value.ident = CSSValueAuto;
+ break;
+ case WebCore::Fixed:
+ m_type = CSS_PX;
+ m_value.num = length.value();
+ break;
+ case Intrinsic:
+ m_type = CSS_IDENT;
+ m_value.ident = CSSValueIntrinsic;
+ break;
+ case MinIntrinsic:
+ m_type = CSS_IDENT;
+ m_value.ident = CSSValueMinIntrinsic;
+ break;
+ case Percent:
+ m_type = CSS_PERCENTAGE;
+ m_value.num = length.percent();
+ break;
+ case Relative:
+ case Static:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+void CSSPrimitiveValue::init(PassRefPtr<Counter> c)
+{
+ m_type = CSS_COUNTER;
+ m_hasCachedCSSText = false;
+ m_value.counter = c.releaseRef();
+}
+
+void CSSPrimitiveValue::init(PassRefPtr<Rect> r)
+{
+ m_type = CSS_RECT;
+ m_hasCachedCSSText = false;
+ m_value.rect = r.releaseRef();
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r)
+{
+ m_type = CSS_DASHBOARD_REGION;
+ m_hasCachedCSSText = false;
+ m_value.region = r.releaseRef();
+}
+#endif
+
+void CSSPrimitiveValue::init(PassRefPtr<Pair> p)
+{
+ m_type = CSS_PAIR;
+ m_hasCachedCSSText = false;
+ m_value.pair = p.releaseRef();
+}
+
+CSSPrimitiveValue::~CSSPrimitiveValue()
+{
+ cleanup();
+}
+
+void CSSPrimitiveValue::cleanup()
+{
+ switch (m_type) {
+ case CSS_STRING:
+ case CSS_URI:
+ case CSS_ATTR:
+ case CSS_PARSER_HEXCOLOR:
+ if (m_value.string)
+ m_value.string->deref();
+ break;
+ case CSS_COUNTER:
+ m_value.counter->deref();
+ break;
+ case CSS_RECT:
+ m_value.rect->deref();
+ break;
+ case CSS_PAIR:
+ m_value.pair->deref();
+ break;
+#if ENABLE(DASHBOARD_SUPPORT)
+ case CSS_DASHBOARD_REGION:
+ if (m_value.region)
+ m_value.region->deref();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ m_type = 0;
+ if (m_hasCachedCSSText) {
+ cssTextCache().remove(this);
+ m_hasCachedCSSText = false;
+ }
+}
+
+int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle)
+{
+ return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle));
+}
+
+int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
+{
+ return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle, multiplier));
+}
+
+// Lengths expect an int that is only 28-bits, so we have to check for a
+// different overflow.
+int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle)
+{
+ return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle));
+}
+
+int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
+{
+ return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle, multiplier));
+}
+
+short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle)
+{
+ return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle));
+}
+
+short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier)
+{
+ return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle, multiplier));
+}
+
+float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize)
+{
+ return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize));
+}
+
+float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
+{
+ return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize));
+}
+
+double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize)
+{
+ unsigned short type = primitiveType();
+
+ // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
+ // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
+ // as well as enforcing the implicit "smart minimum." In addition the CSS property text-size-adjust is used to
+ // prevent text from zooming at all. Therefore we will not apply the zoom here if we are computing font-size.
+ bool applyZoomMultiplier = !computingFontSize;
+
+ double factor = 1.0;
+ switch (type) {
+ case CSS_EMS:
+ applyZoomMultiplier = false;
+ factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
+ break;
+ case CSS_EXS:
+ // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
+ // We really need to compute EX using fontMetrics for the original specifiedSize and not use
+ // our actual constructed rendering font.
+ applyZoomMultiplier = false;
+ factor = style->font().xHeight();
+ break;
+ case CSS_REMS:
+ applyZoomMultiplier = false;
+ factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
+ break;
+ case CSS_PX:
+ break;
+ case CSS_CM:
+ factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
+ break;
+ case CSS_MM:
+ factor = cssPixelsPerInch / 25.4;
+ break;
+ case CSS_IN:
+ factor = cssPixelsPerInch;
+ break;
+ case CSS_PT:
+ factor = cssPixelsPerInch / 72.0;
+ break;
+ case CSS_PC:
+ // 1 pc == 12 pt
+ factor = cssPixelsPerInch * 12.0 / 72.0;
+ break;
+ default:
+ return -1.0;
+ }
+
+ double result = getDoubleValue() * factor;
+ if (!applyZoomMultiplier || multiplier == 1.0)
+ return result;
+
+ // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from
+ // vanishing.
+ double zoomedResult = result * multiplier;
+ if (result >= 1.0)
+ zoomedResult = max(1.0, zoomedResult);
+ return zoomedResult;
+}
+
+void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec)
+{
+ // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
+ // No other engine supports mutating style through this API. Computed style is always read-only anyway.
+ // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+}
+
+static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType)
+{
+ double factor = 1.0;
+ // FIXME: the switch can be replaced by an array of scale factors.
+ switch (unitType) {
+ // These are "canonical" units in their respective categories.
+ case CSSPrimitiveValue::CSS_PX:
+ case CSSPrimitiveValue::CSS_DEG:
+ case CSSPrimitiveValue::CSS_MS:
+ case CSSPrimitiveValue::CSS_HZ:
+ break;
+ case CSSPrimitiveValue::CSS_CM:
+ factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
+ break;
+ case CSSPrimitiveValue::CSS_MM:
+ factor = cssPixelsPerInch / 25.4;
+ break;
+ case CSSPrimitiveValue::CSS_IN:
+ factor = cssPixelsPerInch;
+ break;
+ case CSSPrimitiveValue::CSS_PT:
+ factor = cssPixelsPerInch / 72.0;
+ break;
+ case CSSPrimitiveValue::CSS_PC:
+ factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
+ break;
+ case CSSPrimitiveValue::CSS_RAD:
+ factor = 180 / piDouble;
+ break;
+ case CSSPrimitiveValue::CSS_GRAD:
+ factor = 0.9;
+ break;
+ case CSSPrimitiveValue::CSS_TURN:
+ factor = 360;
+ break;
+ case CSSPrimitiveValue::CSS_S:
+ case CSSPrimitiveValue::CSS_KHZ:
+ factor = 1000;
+ break;
+ default:
+ break;
+ }
+
+ return factor;
+}
+
+double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const
+{
+ double result = 0;
+ bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
+ if (!success) {
+ ec = INVALID_ACCESS_ERR;
+ return 0.0;
+ }
+
+ ec = 0;
+ return result;
+}
+
+double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const
+{
+ double result = 0;
+ getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result);
+ return result;
+}
+
+CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
+{
+ // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit
+ // in each category (based on unitflags).
+ switch (category) {
+ case UNumber:
+ return CSS_NUMBER;
+ case ULength:
+ return CSS_PX;
+ case UPercent:
+ return CSS_UNKNOWN; // Cannot convert between numbers and percent.
+ case UTime:
+ return CSS_MS;
+ case UAngle:
+ return CSS_DEG;
+ case UFrequency:
+ return CSS_HZ;
+ default:
+ return CSS_UNKNOWN;
+ }
+}
+
+bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const
+{
+ if (m_type < CSS_NUMBER || (m_type > CSS_DIMENSION && m_type < CSS_TURN) || requestedUnitType < CSS_NUMBER || (requestedUnitType > CSS_DIMENSION && requestedUnitType < CSS_TURN))
+ return false;
+ if (requestedUnitType == m_type || requestedUnitType == CSS_DIMENSION) {
+ *result = m_value.num;
+ return true;
+ }
+
+ UnitTypes sourceUnitType = static_cast<UnitTypes>(m_type);
+ UnitCategory sourceCategory = unitCategory(sourceUnitType);
+ ASSERT(sourceCategory != UOther);
+
+ UnitTypes targetUnitType = requestedUnitType;
+ UnitCategory targetCategory = unitCategory(targetUnitType);
+ ASSERT(targetCategory != UOther);
+
+ // Cannot convert between unrelated unit categories if one of them is not UNumber.
+ if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
+ return false;
+
+ if (targetCategory == UNumber) {
+ // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
+ targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
+ if (targetUnitType == CSS_UNKNOWN)
+ return false;
+ }
+
+ if (sourceUnitType == CSS_NUMBER) {
+ // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode.
+ sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
+ if (sourceUnitType == CSS_UNKNOWN)
+ return false;
+ }
+
+ double convertedValue = m_value.num;
+
+ // First convert the value from m_type to canonical type.
+ double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
+ convertedValue *= factor;
+
+ // Now convert from canonical type to the target unitType.
+ factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
+ convertedValue /= factor;
+
+ *result = convertedValue;
+ return true;
+}
+
+void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec)
+{
+ // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
+ // No other engine supports mutating style through this API. Computed style is always read-only anyway.
+ // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+}
+
+String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const
+{
+ ec = 0;
+ switch (m_type) {
+ case CSS_STRING:
+ case CSS_ATTR:
+ case CSS_URI:
+ return m_value.string;
+ case CSS_IDENT:
+ return valueOrPropertyName(m_value.ident);
+ default:
+ ec = INVALID_ACCESS_ERR;
+ break;
+ }
+
+ return String();
+}
+
+String CSSPrimitiveValue::getStringValue() const
+{
+ switch (m_type) {
+ case CSS_STRING:
+ case CSS_ATTR:
+ case CSS_URI:
+ return m_value.string;
+ case CSS_IDENT:
+ return valueOrPropertyName(m_value.ident);
+ default:
+ break;
+ }
+
+ return String();
+}
+
+Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const
+{
+ ec = 0;
+ if (m_type != CSS_COUNTER) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ return m_value.counter;
+}
+
+Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const
+{
+ ec = 0;
+ if (m_type != CSS_RECT) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ return m_value.rect;
+}
+
+PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const
+{
+ ec = 0;
+ if (m_type != CSS_RGBCOLOR) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ // FIMXE: This should not return a new object for each invocation.
+ return RGBColor::create(m_value.rgbcolor);
+}
+
+Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const
+{
+ ec = 0;
+ if (m_type != CSS_PAIR) {
+ ec = INVALID_ACCESS_ERR;
+ return 0;
+ }
+
+ return m_value.pair;
+}
+
+unsigned short CSSPrimitiveValue::cssValueType() const
+{
+ return CSS_PRIMITIVE_VALUE;
+}
+
+bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/)
+{
+ // FIXME
+ return false;
+}
+
+int CSSPrimitiveValue::getIdent() const
+{
+ if (m_type != CSS_IDENT)
+ return 0;
+ return m_value.ident;
+}
+
+static String formatNumber(double number)
+{
+ DecimalNumber decimal(number);
+
+ StringBuffer buffer(decimal.bufferLengthForStringDecimal());
+ unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length());
+ ASSERT_UNUSED(length, length == buffer.length());
+
+ return String::adopt(buffer);
+}
+
+String CSSPrimitiveValue::cssText() const
+{
+ // FIXME: return the original value instead of a generated one (e.g. color
+ // name if it was specified) - check what spec says about this
+
+ if (m_hasCachedCSSText) {
+ ASSERT(cssTextCache().contains(this));
+ return cssTextCache().get(this);
+ }
+
+ String text;
+ switch (m_type) {
+ case CSS_UNKNOWN:
+ // FIXME
+ break;
+ case CSS_NUMBER:
+ case CSS_PARSER_INTEGER:
+ text = formatNumber(m_value.num);
+ break;
+ case CSS_PERCENTAGE:
+ text = formatNumber(m_value.num) + "%";
+ break;
+ case CSS_EMS:
+ text = formatNumber(m_value.num) + "em";
+ break;
+ case CSS_EXS:
+ text = formatNumber(m_value.num) + "ex";
+ break;
+ case CSS_REMS:
+ text = formatNumber(m_value.num) + "rem";
+ break;
+ case CSS_PX:
+ text = formatNumber(m_value.num) + "px";
+ break;
+ case CSS_CM:
+ text = formatNumber(m_value.num) + "cm";
+ break;
+ case CSS_MM:
+ text = formatNumber(m_value.num) + "mm";
+ break;
+ case CSS_IN:
+ text = formatNumber(m_value.num) + "in";
+ break;
+ case CSS_PT:
+ text = formatNumber(m_value.num) + "pt";
+ break;
+ case CSS_PC:
+ text = formatNumber(m_value.num) + "pc";
+ break;
+ case CSS_DEG:
+ text = formatNumber(m_value.num) + "deg";
+ break;
+ case CSS_RAD:
+ text = formatNumber(m_value.num) + "rad";
+ break;
+ case CSS_GRAD:
+ text = formatNumber(m_value.num) + "grad";
+ break;
+ case CSS_MS:
+ text = formatNumber(m_value.num) + "ms";
+ break;
+ case CSS_S:
+ text = formatNumber(m_value.num) + "s";
+ break;
+ case CSS_HZ:
+ text = formatNumber(m_value.num) + "hz";
+ break;
+ case CSS_KHZ:
+ text = formatNumber(m_value.num) + "khz";
+ break;
+ case CSS_TURN:
+ text = formatNumber(m_value.num) + "turn";
+ break;
+ case CSS_DIMENSION:
+ // FIXME
+ break;
+ case CSS_STRING:
+ text = quoteCSSStringIfNeeded(m_value.string);
+ break;
+ case CSS_URI:
+ text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
+ break;
+ case CSS_IDENT:
+ text = valueOrPropertyName(m_value.ident);
+ break;
+ case CSS_ATTR: {
+ DEFINE_STATIC_LOCAL(const String, attrParen, ("attr("));
+
+ Vector<UChar> result;
+ result.reserveInitialCapacity(6 + m_value.string->length());
+
+ append(result, attrParen);
+ append(result, m_value.string);
+ result.uncheckedAppend(')');
+
+ text = String::adopt(result);
+ break;
+ }
+ case CSS_COUNTER:
+ text = "counter(";
+ text += String::number(m_value.num);
+ text += ")";
+ // FIXME: Add list-style and separator
+ break;
+ case CSS_RECT: {
+ DEFINE_STATIC_LOCAL(const String, rectParen, ("rect("));
+
+ Rect* rectVal = getRectValue();
+ Vector<UChar> result;
+ result.reserveInitialCapacity(32);
+ append(result, rectParen);
+
+ append(result, rectVal->top()->cssText());
+ result.append(' ');
+
+ append(result, rectVal->right()->cssText());
+ result.append(' ');
+
+ append(result, rectVal->bottom()->cssText());
+ result.append(' ');
+
+ append(result, rectVal->left()->cssText());
+ result.append(')');
+
+ text = String::adopt(result);
+ break;
+ }
+ case CSS_RGBCOLOR:
+ case CSS_PARSER_HEXCOLOR: {
+ DEFINE_STATIC_LOCAL(const String, commaSpace, (", "));
+ DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb("));
+ DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba("));
+
+ RGBA32 rgbColor = m_value.rgbcolor;
+ if (m_type == CSS_PARSER_HEXCOLOR)
+ Color::parseHexColor(m_value.string, rgbColor);
+ Color color(rgbColor);
+
+ Vector<UChar> result;
+ result.reserveInitialCapacity(32);
+ if (color.hasAlpha())
+ append(result, rgbaParen);
+ else
+ append(result, rgbParen);
+
+ appendNumber(result, static_cast<unsigned char>(color.red()));
+ append(result, commaSpace);
+
+ appendNumber(result, static_cast<unsigned char>(color.green()));
+ append(result, commaSpace);
+
+ appendNumber(result, static_cast<unsigned char>(color.blue()));
+ if (color.hasAlpha()) {
+ append(result, commaSpace);
+ append(result, String::number(color.alpha() / 256.0f));
+ }
+
+ result.append(')');
+ text = String::adopt(result);
+ break;
+ }
+ case CSS_PAIR:
+ text = m_value.pair->first()->cssText();
+ text += " ";
+ text += m_value.pair->second()->cssText();
+ break;
+#if ENABLE(DASHBOARD_SUPPORT)
+ case CSS_DASHBOARD_REGION:
+ for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) {
+ if (!text.isEmpty())
+ text.append(' ');
+ text += "dashboard-region(";
+ text += region->m_label;
+ if (region->m_isCircle)
+ text += " circle";
+ else if (region->m_isRectangle)
+ text += " rectangle";
+ else
+ break;
+ if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) {
+ ASSERT(region->right()->m_type == CSS_IDENT);
+ ASSERT(region->bottom()->m_type == CSS_IDENT);
+ ASSERT(region->left()->m_type == CSS_IDENT);
+ ASSERT(region->right()->getIdent() == CSSValueInvalid);
+ ASSERT(region->bottom()->getIdent() == CSSValueInvalid);
+ ASSERT(region->left()->getIdent() == CSSValueInvalid);
+ } else {
+ text.append(' ');
+ text += region->top()->cssText() + " ";
+ text += region->right()->cssText() + " ";
+ text += region->bottom()->cssText() + " ";
+ text += region->left()->cssText();
+ }
+ text += ")";
+ }
+ break;
+#endif
+ case CSS_PARSER_OPERATOR: {
+ char c = static_cast<char>(m_value.ident);
+ text = String(&c, 1U);
+ break;
+ }
+ case CSS_PARSER_IDENTIFIER:
+ text = quoteCSSStringIfNeeded(m_value.string);
+ break;
+ }
+
+ ASSERT(!cssTextCache().contains(this));
+ cssTextCache().set(this, text);
+ m_hasCachedCSSText = true;
+ return text;
+}
+
+CSSParserValue CSSPrimitiveValue::parserValue() const
+{
+ // We only have to handle a subset of types.
+ CSSParserValue value;
+ value.id = 0;
+ value.isInt = false;
+ value.unit = CSSPrimitiveValue::CSS_IDENT;
+ switch (m_type) {
+ case CSS_NUMBER:
+ case CSS_PERCENTAGE:
+ case CSS_EMS:
+ case CSS_EXS:
+ case CSS_REMS:
+ case CSS_PX:
+ case CSS_CM:
+ case CSS_MM:
+ case CSS_IN:
+ case CSS_PT:
+ case CSS_PC:
+ case CSS_DEG:
+ case CSS_RAD:
+ case CSS_GRAD:
+ case CSS_MS:
+ case CSS_S:
+ case CSS_HZ:
+ case CSS_KHZ:
+ case CSS_DIMENSION:
+ case CSS_TURN:
+ value.fValue = m_value.num;
+ value.unit = m_type;
+ break;
+ case CSS_STRING:
+ case CSS_URI:
+ case CSS_PARSER_HEXCOLOR:
+ value.string.characters = const_cast<UChar*>(m_value.string->characters());
+ value.string.length = m_value.string->length();
+ value.unit = m_type;
+ break;
+ case CSS_IDENT: {
+ value.id = m_value.ident;
+ const AtomicString& name = valueOrPropertyName(m_value.ident);
+ value.string.characters = const_cast<UChar*>(name.characters());
+ value.string.length = name.length();
+ break;
+ }
+ case CSS_PARSER_OPERATOR:
+ value.iValue = m_value.ident;
+ value.unit = CSSParserValue::Operator;
+ break;
+ case CSS_PARSER_INTEGER:
+ value.fValue = m_value.num;
+ value.unit = CSSPrimitiveValue::CSS_NUMBER;
+ value.isInt = true;
+ break;
+ case CSS_PARSER_IDENTIFIER:
+ value.string.characters = const_cast<UChar*>(m_value.string->characters());
+ value.string.length = m_value.string->length();
+ value.unit = CSSPrimitiveValue::CSS_IDENT;
+ break;
+ case CSS_UNKNOWN:
+ case CSS_ATTR:
+ case CSS_COUNTER:
+ case CSS_RECT:
+ case CSS_RGBCOLOR:
+ case CSS_PAIR:
+#if ENABLE(DASHBOARD_SUPPORT)
+ case CSS_DASHBOARD_REGION:
+#endif
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return value;
+}
+
+void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
+{
+ if (m_type == CSS_URI)
+ addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
+}
+
+} // namespace WebCore