/* * (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 "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 #include #if ENABLE(DASHBOARD_SUPPORT) #include "DashboardRegion.h" #endif using namespace WTF; namespace WebCore { // 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. PassRefPtr CSSPrimitiveValue::createIdentifier(int ident) { static RefPtr* identValueCache = new RefPtr[numCSSValueKeywords]; if (ident >= 0 && ident < numCSSValueKeywords) { RefPtr primitiveValue = identValueCache[ident]; if (!primitiveValue) { primitiveValue = adoptRef(new CSSPrimitiveValue(ident)); identValueCache[ident] = primitiveValue; } return primitiveValue.release(); } return adoptRef(new CSSPrimitiveValue(ident)); } PassRefPtr CSSPrimitiveValue::createColor(unsigned rgbValue) { typedef HashMap > ColorValueCache; static ColorValueCache* colorValueCache = new ColorValueCache; // These are the empty and deleted values of the hash table. if (rgbValue == Color::transparent) { static CSSPrimitiveValue* colorTransparent = new CSSPrimitiveValue(CSSValueTransparent); return colorTransparent; } if (rgbValue == Color::white) { static CSSPrimitiveValue* colorWhite = new CSSPrimitiveValue(Color::white); return colorWhite; } RefPtr primitiveValue = colorValueCache->get(rgbValue); if (primitiveValue) return primitiveValue.release(); primitiveValue = adoptRef(new CSSPrimitiveValue(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::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(* IntegerValueCache)[maxCachedUnitType + 1]; static IntegerValueCache integerValueCache = new RefPtr[cachedIntegerCount][maxCachedUnitType + 1]; if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) { int intValue = static_cast(value); if (value == intValue) { RefPtr primitiveValue = integerValueCache[intValue][type]; if (!primitiveValue) { primitiveValue = adoptRef(new CSSPrimitiveValue(value, type)); integerValueCache[intValue][type] = primitiveValue; } return primitiveValue.release(); } } return adoptRef(new CSSPrimitiveValue(value, type)); } PassRefPtr 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(valueOrPropertyID))); return *cssPropertyStrings[propertyIndex]; } return nullAtom; } // "ident" from the CSS tokenizer, minus backslash-escape sequences static bool isCSSTokenizerIdentifier(const String& string) { const UChar* p = string.characters(); const UChar* end = p + string.length(); // -? if (p != end && p[0] == '-') ++p; // {nmstart} if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0]))) return false; ++p; // {nmchar}* for (; p != end; ++p) { if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0]))) return false; } return true; } // "url" from the CSS tokenizer, minus backslash-escape sequences static bool isCSSTokenizerURL(const String& string) { const UChar* p = string.characters(); const UChar* end = p + string.length(); for (; p != end; ++p) { UChar c = p[0]; switch (c) { case '!': case '#': case '$': case '%': case '&': break; default: if (c < '*') return false; if (c <= '~') break; if (c < 128) return false; } } return true; } // We use single quotes for now because markup.cpp uses double quotes. static String quoteString(const String& string) { // FIXME: Also need to escape characters like '\n'. String s = string; s.replace('\\', "\\\\"); s.replace('\'', "\\'"); return "'" + s + "'"; } static String quoteStringIfNeeded(const String& string) { return isCSSTokenizerIdentifier(string) ? string : quoteString(string); } static String quoteURLIfNeeded(const String& string) { return isCSSTokenizerURL(string) ? string : quoteString(string); } CSSPrimitiveValue::CSSPrimitiveValue() : m_type(0) { } CSSPrimitiveValue::CSSPrimitiveValue(int ident) : m_type(CSS_IDENT) { m_value.ident = ident; } CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) : m_type(type) { m_value.num = num; } CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) : m_type(type) { if ((m_value.string = str.impl())) m_value.string->ref(); } CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) : m_type(CSS_RGBCOLOR) { m_value.rgbcolor = color; } CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) { 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 c) { m_type = CSS_COUNTER; m_value.counter = c.releaseRef(); } void CSSPrimitiveValue::init(PassRefPtr r) { m_type = CSS_RECT; m_value.rect = r.releaseRef(); } #if ENABLE(DASHBOARD_SUPPORT) void CSSPrimitiveValue::init(PassRefPtr r) { m_type = CSS_DASHBOARD_REGION; m_value.region = r.releaseRef(); } #endif void CSSPrimitiveValue::init(PassRefPtr p) { m_type = CSS_PAIR; 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_VARIABLE_FUNCTION_SYNTAX: 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; } int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle) { double result = computeLengthDouble(style, rootStyle); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > INT_MAX || result < INT_MIN) return 0; return static_cast(result); } int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier) { double result = computeLengthDouble(style, rootStyle, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > INT_MAX || result < INT_MIN) return 0; return static_cast(result); } const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int // 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) { double result = computeLengthDouble(style, rootStyle); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > intMaxForLength || result < intMinForLength) return 0; return static_cast(result); } // 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, double multiplier) { double result = computeLengthDouble(style, rootStyle, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > intMaxForLength || result < intMinForLength) return 0; return static_cast(result); } short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle) { double result = computeLengthDouble(style, rootStyle); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > SHRT_MAX || result < SHRT_MIN) return 0; return static_cast(result); } short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier) { double result = computeLengthDouble(style, rootStyle, multiplier); // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We // need to go ahead and round if we're really close to the next integer value. result += result < 0 ? -0.01 : +0.01; if (result > SHRT_MAX || result < SHRT_MIN) return 0; return static_cast(result); } float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize) { return static_cast(computeLengthDouble(style, rootStyle, 1.0, computingFontSize)); } float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) { return static_cast(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 unitType, double floatValue, ExceptionCode& ec) { ec = 0; // FIXME: check if property supports this type if (m_type > CSS_DIMENSION) { ec = SYNTAX_ERR; return; } cleanup(); //if(m_type > CSS_DIMENSION) throw DOMException(INVALID_ACCESS_ERR); m_value.num = floatValue; m_type = unitType; } static double scaleFactorForConversion(unsigned short unitType) { double factor = 1.0; switch (unitType) { case CSSPrimitiveValue::CSS_PX: 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; default: break; } return factor; } double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) { ec = 0; if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) { ec = INVALID_ACCESS_ERR; return 0.0; } if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC) return m_value.num; double convertedValue = m_value.num; // First convert the value from m_type into CSSPixels double factor = scaleFactorForConversion(m_type); convertedValue *= factor; // Now convert from CSSPixels to the specified unitType factor = scaleFactorForConversion(unitType); convertedValue /= factor; return convertedValue; } double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) { if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) return 0; if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC) return m_value.num; double convertedValue = m_value.num; // First convert the value from m_type into CSSPixels double factor = scaleFactorForConversion(m_type); convertedValue *= factor; // Now convert from CSSPixels to the specified unitType factor = scaleFactorForConversion(unitType); convertedValue /= factor; return convertedValue; } void CSSPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode& ec) { ec = 0; //if(m_type < CSS_STRING) throw DOMException(INVALID_ACCESS_ERR); //if(m_type > CSS_ATTR) throw DOMException(INVALID_ACCESS_ERR); if (m_type < CSS_STRING || m_type > CSS_ATTR) { ec = SYNTAX_ERR; return; } cleanup(); if (stringType != CSS_IDENT) { m_value.string = stringValue.impl(); m_value.string->ref(); m_type = stringType; } // FIXME: parse ident } String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const { ec = 0; switch (m_type) { case CSS_STRING: case CSS_ATTR: case CSS_URI: case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 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: case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 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 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() { if (m_type != CSS_IDENT) return 0; return m_value.ident; } 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 String text; switch (m_type) { case CSS_UNKNOWN: // FIXME break; case CSS_NUMBER: case CSS_PARSER_INTEGER: text = String::number(m_value.num); break; case CSS_PERCENTAGE: text = String::format("%.6lg%%", m_value.num); break; case CSS_EMS: text = String::format("%.6lgem", m_value.num); break; case CSS_EXS: text = String::format("%.6lgex", m_value.num); break; case CSS_REMS: text = String::format("%.6lgrem", m_value.num); break; case CSS_PX: text = String::format("%.6lgpx", m_value.num); break; case CSS_CM: text = String::format("%.6lgcm", m_value.num); break; case CSS_MM: text = String::format("%.6lgmm", m_value.num); break; case CSS_IN: text = String::format("%.6lgin", m_value.num); break; case CSS_PT: text = String::format("%.6lgpt", m_value.num); break; case CSS_PC: text = String::format("%.6lgpc", m_value.num); break; case CSS_DEG: text = String::format("%.6lgdeg", m_value.num); break; case CSS_RAD: text = String::format("%.6lgrad", m_value.num); break; case CSS_GRAD: text = String::format("%.6lggrad", m_value.num); break; case CSS_MS: text = String::format("%.6lgms", m_value.num); break; case CSS_S: text = String::format("%.6lgs", m_value.num); break; case CSS_HZ: text = String::format("%.6lghz", m_value.num); break; case CSS_KHZ: text = String::format("%.6lgkhz", m_value.num); break; case CSS_TURN: text = String::format("%.6lgturn", m_value.num); break; case CSS_DIMENSION: // FIXME break; case CSS_STRING: text = quoteStringIfNeeded(m_value.string); break; case CSS_URI: text = "url(" + quoteURLIfNeeded(m_value.string) + ")"; break; case CSS_IDENT: text = valueOrPropertyName(m_value.ident); break; case CSS_ATTR: { DEFINE_STATIC_LOCAL(const String, attrParen, ("attr(")); Vector result; result.reserveInitialCapacity(6 + m_value.string->length()); append(result, attrParen); append(result, m_value.string); result.uncheckedAppend(')'); return String::adopt(result); } 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 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(')'); return String::adopt(result); } 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 result; result.reserveInitialCapacity(32); if (color.hasAlpha()) append(result, rgbaParen); else append(result, rgbParen); appendNumber(result, static_cast(color.red())); append(result, commaSpace); appendNumber(result, static_cast(color.green())); append(result, commaSpace); appendNumber(result, static_cast(color.blue())); if (color.hasAlpha()) { append(result, commaSpace); append(result, String::number(static_cast(color.alpha()) / 256.0f)); } result.append(')'); return String::adopt(result); } 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_VARIABLE_FUNCTION_SYNTAX: text = "-webkit-var("; text += m_value.string; text += ")"; break; case CSS_PARSER_OPERATOR: { char c = static_cast(m_value.ident); text = String(&c, 1U); break; } case CSS_PARSER_IDENTIFIER: text = quoteStringIfNeeded(m_value.string); break; } 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_VARIABLE_FUNCTION_SYNTAX: case CSS_PARSER_HEXCOLOR: value.string.characters = const_cast(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(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(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& urls, const CSSStyleSheet* styleSheet) { if (m_type == CSS_URI) addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); } } // namespace WebCore