/*
* (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;
}
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:
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->fontMetrics().xHeight();
break;
case CSS_REMS:
applyZoomMultiplier = false;
if (rootStyle)
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_NAME:
text = "counter(";
text += m_value.string;
text += ")";
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;
}
void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet)
{
if (m_type == CSS_URI)
addSubresourceURL(urls, styleSheet->completeURL(m_value.string));
}
} // namespace WebCore