diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
commit | 2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch) | |
tree | 988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/css/StylePropertySet.cpp | |
parent | dd91e772430dc294e3bf478c119ef8d43c0a3358 (diff) | |
download | qtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz |
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/css/StylePropertySet.cpp')
-rw-r--r-- | Source/WebCore/css/StylePropertySet.cpp | 705 |
1 files changed, 397 insertions, 308 deletions
diff --git a/Source/WebCore/css/StylePropertySet.cpp b/Source/WebCore/css/StylePropertySet.cpp index 65452ec3b..a5c8806ba 100644 --- a/Source/WebCore/css/StylePropertySet.cpp +++ b/Source/WebCore/css/StylePropertySet.cpp @@ -23,13 +23,13 @@ #include "StylePropertySet.h" #include "CSSParser.h" -#include "CSSPropertyLonghand.h" -#include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "CSSValueList.h" #include "CSSValuePool.h" #include "Document.h" #include "PropertySetCSSStyleDeclaration.h" +#include "StylePropertyShorthand.h" +#include <wtf/BitVector.h> #include <wtf/text/StringBuilder.h> using namespace std; @@ -43,23 +43,23 @@ static PropertySetCSSOMWrapperMap& propertySetCSSOMWrapperMap() return propertySetCSSOMWrapperMapInstance; } -StylePropertySet::StylePropertySet() - : m_strictParsing(false) - , m_hasCSSOMWrapper(false) +StylePropertySet::StylePropertySet(CSSParserMode cssParserMode) + : m_cssParserMode(cssParserMode) + , m_ownsCSSOMWrapper(false) { } StylePropertySet::StylePropertySet(const Vector<CSSProperty>& properties) : m_properties(properties) - , m_strictParsing(true) - , m_hasCSSOMWrapper(false) + , m_cssParserMode(CSSStrictMode) + , m_ownsCSSOMWrapper(false) { m_properties.shrinkToFit(); } -StylePropertySet::StylePropertySet(const CSSProperty* properties, int numProperties, bool useStrictParsing) - : m_strictParsing(useStrictParsing) - , m_hasCSSOMWrapper(false) +StylePropertySet::StylePropertySet(const CSSProperty* properties, int numProperties, CSSParserMode cssParserMode) + : m_cssParserMode(cssParserMode) + , m_ownsCSSOMWrapper(false) { // FIXME: This logic belongs in CSSParser. @@ -81,10 +81,18 @@ StylePropertySet::StylePropertySet(const CSSProperty* properties, int numPropert } } +StylePropertySet::StylePropertySet(const StylePropertySet& o) + : RefCounted<StylePropertySet>() + , m_properties(o.m_properties) + , m_cssParserMode(o.m_cssParserMode) + , m_ownsCSSOMWrapper(false) +{ +} + StylePropertySet::~StylePropertySet() { - ASSERT(!m_hasCSSOMWrapper || propertySetCSSOMWrapperMap().contains(this)); - if (m_hasCSSOMWrapper) + ASSERT(!m_ownsCSSOMWrapper || propertySetCSSOMWrapperMap().contains(this)); + if (m_ownsCSSOMWrapper) propertySetCSSOMWrapperMap().remove(this); } @@ -93,7 +101,7 @@ void StylePropertySet::copyPropertiesFrom(const StylePropertySet& other) m_properties = other.m_properties; } -String StylePropertySet::getPropertyValue(int propertyID) const +String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const { RefPtr<CSSValue> value = getPropertyCSSValue(propertyID); if (value) @@ -101,177 +109,83 @@ String StylePropertySet::getPropertyValue(int propertyID) const // Shorthand and 4-values properties switch (propertyID) { - case CSSPropertyBorderSpacing: { - const int properties[2] = { CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyWebkitBorderVerticalSpacing }; - return borderSpacingValue(properties); - } - case CSSPropertyBackgroundPosition: { - // FIXME: Is this correct? The code in cssparser.cpp is confusing - const int properties[2] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyBackgroundRepeat: { - const int properties[2] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyBackground: { - const int properties[9] = { CSSPropertyBackgroundColor, - CSSPropertyBackgroundImage, - CSSPropertyBackgroundRepeatX, - CSSPropertyBackgroundRepeatY, - CSSPropertyBackgroundAttachment, - CSSPropertyBackgroundPositionX, - CSSPropertyBackgroundPositionY, - CSSPropertyBackgroundClip, - CSSPropertyBackgroundOrigin }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyBorder: { - const int properties[3][4] = {{ CSSPropertyBorderTopWidth, - CSSPropertyBorderRightWidth, - CSSPropertyBorderBottomWidth, - CSSPropertyBorderLeftWidth }, - { CSSPropertyBorderTopStyle, - CSSPropertyBorderRightStyle, - CSSPropertyBorderBottomStyle, - CSSPropertyBorderLeftStyle }, - { CSSPropertyBorderTopColor, - CSSPropertyBorderRightColor, - CSSPropertyBorderBottomColor, - CSSPropertyBorderLeftColor }}; - String res; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { - String value = getCommonValue(properties[i]); - if (!value.isNull()) { - if (!res.isNull()) - res += " "; - res += value; - } - } - return res; - } - case CSSPropertyBorderTop: { - const int properties[3] = { CSSPropertyBorderTopWidth, CSSPropertyBorderTopStyle, - CSSPropertyBorderTopColor}; - return getShorthandValue(properties); - } - case CSSPropertyBorderRight: { - const int properties[3] = { CSSPropertyBorderRightWidth, CSSPropertyBorderRightStyle, - CSSPropertyBorderRightColor}; - return getShorthandValue(properties); - } - case CSSPropertyBorderBottom: { - const int properties[3] = { CSSPropertyBorderBottomWidth, CSSPropertyBorderBottomStyle, - CSSPropertyBorderBottomColor}; - return getShorthandValue(properties); - } - case CSSPropertyBorderLeft: { - const int properties[3] = { CSSPropertyBorderLeftWidth, CSSPropertyBorderLeftStyle, - CSSPropertyBorderLeftColor}; - return getShorthandValue(properties); - } - case CSSPropertyOutline: { - const int properties[3] = { CSSPropertyOutlineWidth, CSSPropertyOutlineStyle, - CSSPropertyOutlineColor }; - return getShorthandValue(properties); - } - case CSSPropertyBorderColor: { - const int properties[4] = { CSSPropertyBorderTopColor, CSSPropertyBorderRightColor, - CSSPropertyBorderBottomColor, CSSPropertyBorderLeftColor }; - return get4Values(properties); - } - case CSSPropertyBorderWidth: { - const int properties[4] = { CSSPropertyBorderTopWidth, CSSPropertyBorderRightWidth, - CSSPropertyBorderBottomWidth, CSSPropertyBorderLeftWidth }; - return get4Values(properties); - } - case CSSPropertyBorderStyle: { - const int properties[4] = { CSSPropertyBorderTopStyle, CSSPropertyBorderRightStyle, - CSSPropertyBorderBottomStyle, CSSPropertyBorderLeftStyle }; - return get4Values(properties); - } - case CSSPropertyWebkitFlexFlow: { - const int properties[] = { CSSPropertyWebkitFlexDirection, CSSPropertyWebkitFlexWrap }; - return getShorthandValue(properties); - } - case CSSPropertyFont: - return fontValue(); - case CSSPropertyMargin: { - const int properties[4] = { CSSPropertyMarginTop, CSSPropertyMarginRight, - CSSPropertyMarginBottom, CSSPropertyMarginLeft }; - return get4Values(properties); - } - case CSSPropertyOverflow: { - const int properties[2] = { CSSPropertyOverflowX, CSSPropertyOverflowY }; - return getCommonValue(properties); - } - case CSSPropertyPadding: { - const int properties[4] = { CSSPropertyPaddingTop, CSSPropertyPaddingRight, - CSSPropertyPaddingBottom, CSSPropertyPaddingLeft }; - return get4Values(properties); - } - case CSSPropertyListStyle: { - const int properties[3] = { CSSPropertyListStyleType, CSSPropertyListStylePosition, - CSSPropertyListStyleImage }; - return getShorthandValue(properties); - } - case CSSPropertyWebkitMaskPosition: { - // FIXME: Is this correct? The code in cssparser.cpp is confusing - const int properties[2] = { CSSPropertyWebkitMaskPositionX, CSSPropertyWebkitMaskPositionY }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyWebkitMaskRepeat: { - const int properties[2] = { CSSPropertyWebkitMaskRepeatX, CSSPropertyWebkitMaskRepeatY }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyWebkitMask: { - const int properties[] = { CSSPropertyWebkitMaskImage, CSSPropertyWebkitMaskRepeat, - CSSPropertyWebkitMaskAttachment, CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskClip, - CSSPropertyWebkitMaskOrigin }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyWebkitTransformOrigin: { - const int properties[3] = { CSSPropertyWebkitTransformOriginX, - CSSPropertyWebkitTransformOriginY, - CSSPropertyWebkitTransformOriginZ }; - return getShorthandValue(properties); - } - case CSSPropertyWebkitTransition: { - const int properties[4] = { CSSPropertyWebkitTransitionProperty, CSSPropertyWebkitTransitionDuration, - CSSPropertyWebkitTransitionTimingFunction, CSSPropertyWebkitTransitionDelay }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyWebkitAnimation: { - const int properties[7] = { CSSPropertyWebkitAnimationName, CSSPropertyWebkitAnimationDuration, - CSSPropertyWebkitAnimationTimingFunction, CSSPropertyWebkitAnimationDelay, - CSSPropertyWebkitAnimationIterationCount, CSSPropertyWebkitAnimationDirection, - CSSPropertyWebkitAnimationFillMode }; - return getLayeredShorthandValue(properties); - } - case CSSPropertyWebkitWrap: { - const int properties[3] = { CSSPropertyWebkitWrapFlow, CSSPropertyWebkitWrapMargin, - CSSPropertyWebkitWrapPadding }; - return getShorthandValue(properties); - } + case CSSPropertyBorderSpacing: + return borderSpacingValue(borderSpacingShorthand()); + case CSSPropertyBackgroundPosition: + return getLayeredShorthandValue(backgroundPositionShorthand()); + case CSSPropertyBackgroundRepeat: + return getLayeredShorthandValue(backgroundRepeatShorthand()); + case CSSPropertyBackground: + return getLayeredShorthandValue(backgroundShorthand()); + case CSSPropertyBorder: + return borderPropertyValue(OmitUncommonValues); + case CSSPropertyBorderTop: + return getShorthandValue(borderTopShorthand()); + case CSSPropertyBorderRight: + return getShorthandValue(borderRightShorthand()); + case CSSPropertyBorderBottom: + return getShorthandValue(borderBottomShorthand()); + case CSSPropertyBorderLeft: + return getShorthandValue(borderLeftShorthand()); + case CSSPropertyOutline: + return getShorthandValue(outlineShorthand()); + case CSSPropertyBorderColor: + return get4Values(borderColorShorthand()); + case CSSPropertyBorderWidth: + return get4Values(borderWidthShorthand()); + case CSSPropertyBorderStyle: + return get4Values(borderStyleShorthand()); + case CSSPropertyWebkitFlexFlow: + return getShorthandValue(webkitFlexFlowShorthand()); + case CSSPropertyFont: + return fontValue(); + case CSSPropertyMargin: + return get4Values(marginShorthand()); + case CSSPropertyOverflow: + return getCommonValue(overflowShorthand()); + case CSSPropertyPadding: + return get4Values(paddingShorthand()); + case CSSPropertyListStyle: + return getShorthandValue(listStyleShorthand()); + case CSSPropertyWebkitMaskPosition: + return getLayeredShorthandValue(webkitMaskPositionShorthand()); + case CSSPropertyWebkitMaskRepeat: + return getLayeredShorthandValue(webkitMaskRepeatShorthand()); + case CSSPropertyWebkitMask: + return getLayeredShorthandValue(webkitMaskShorthand()); + case CSSPropertyWebkitTransformOrigin: + return getShorthandValue(webkitTransformOriginShorthand()); + case CSSPropertyWebkitTransition: + return getLayeredShorthandValue(webkitTransitionShorthand()); + case CSSPropertyWebkitAnimation: + return getLayeredShorthandValue(webkitAnimationShorthand()); + case CSSPropertyWebkitWrap: + return getShorthandValue(webkitWrapShorthand()); #if ENABLE(SVG) - case CSSPropertyMarker: { - RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart); - if (value) - return value->cssText(); - } + case CSSPropertyMarker: { + RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart); + if (value) + return value->cssText(); + return String(); + } #endif + case CSSPropertyBorderRadius: + return get4Values(borderRadiusShorthand()); + default: + return String(); } - return String(); } -String StylePropertySet::borderSpacingValue(const int properties[2]) const +String StylePropertySet::borderSpacingValue(const StylePropertyShorthand& shorthand) const { - RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(properties[0]); - RefPtr<CSSValue> verticalValue = getPropertyCSSValue(properties[1]); + RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(shorthand.properties()[0]); + RefPtr<CSSValue> verticalValue = getPropertyCSSValue(shorthand.properties()[1]); - if (!horizontalValue) + // While standard border-spacing property does not allow specifying border-spacing-vertical without + // specifying border-spacing-horizontal <http://www.w3.org/TR/CSS21/tables.html#separated-borders>, + // -webkit-border-spacing-vertical can be set without -webkit-border-spacing-horizontal. + if (!horizontalValue || !verticalValue) return String(); - ASSERT(verticalValue); // By <http://www.w3.org/TR/CSS21/tables.html#separated-borders>. String horizontalValueCSSText = horizontalValue->cssText(); String verticalValueCSSText = verticalValue->cssText(); @@ -280,7 +194,7 @@ String StylePropertySet::borderSpacingValue(const int properties[2]) const return horizontalValueCSSText + ' ' + verticalValueCSSText; } -bool StylePropertySet::appendFontLonghandValueIfExplicit(int propertyId, StringBuilder& result) const +bool StylePropertySet::appendFontLonghandValueIfExplicit(CSSPropertyID propertyId, StringBuilder& result) const { const CSSProperty* property = findPropertyWithId(propertyId); if (!property) @@ -336,43 +250,48 @@ String StylePropertySet::fontValue() const return result.toString(); } -String StylePropertySet::get4Values(const int* properties) const +String StylePropertySet::get4Values(const StylePropertyShorthand& shorthand) const { // Assume the properties are in the usual order top, right, bottom, left. - RefPtr<CSSValue> topValue = getPropertyCSSValue(properties[0]); - RefPtr<CSSValue> rightValue = getPropertyCSSValue(properties[1]); - RefPtr<CSSValue> bottomValue = getPropertyCSSValue(properties[2]); - RefPtr<CSSValue> leftValue = getPropertyCSSValue(properties[3]); + const CSSProperty* top = findPropertyWithId(shorthand.properties()[0]); + const CSSProperty* right = findPropertyWithId(shorthand.properties()[1]); + const CSSProperty* bottom = findPropertyWithId(shorthand.properties()[2]); + const CSSProperty* left = findPropertyWithId(shorthand.properties()[3]); // All 4 properties must be specified. - if (!topValue || !rightValue || !bottomValue || !leftValue) + if (!top || !top->value() || !right || !right->value() || !bottom || !bottom->value() || !left || !left->value()) + return String(); + if (top->value()->isInitialValue() || right->value()->isInitialValue() || bottom->value()->isInitialValue() || left->value()->isInitialValue()) + return String(); + if (top->isImportant() != right->isImportant() || right->isImportant() != bottom->isImportant() || bottom->isImportant() != left->isImportant()) return String(); - bool showLeft = rightValue->cssText() != leftValue->cssText(); - bool showBottom = (topValue->cssText() != bottomValue->cssText()) || showLeft; - bool showRight = (topValue->cssText() != rightValue->cssText()) || showBottom; + bool showLeft = right->value()->cssText() != left->value()->cssText(); + bool showBottom = (top->value()->cssText() != bottom->value()->cssText()) || showLeft; + bool showRight = (top->value()->cssText() != right->value()->cssText()) || showBottom; - String res = topValue->cssText(); + String res = top->value()->cssText(); if (showRight) - res += " " + rightValue->cssText(); + res += " " + right->value()->cssText(); if (showBottom) - res += " " + bottomValue->cssText(); + res += " " + bottom->value()->cssText(); if (showLeft) - res += " " + leftValue->cssText(); + res += " " + left->value()->cssText(); return res; } -String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t size) const +String StylePropertySet::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const { String res; + const unsigned size = shorthand.length(); // Begin by collecting the properties into an array. Vector< RefPtr<CSSValue> > values(size); size_t numLayers = 0; - for (size_t i = 0; i < size; ++i) { - values[i] = getPropertyCSSValue(properties[i]); + for (unsigned i = 0; i < size; ++i) { + values[i] = getPropertyCSSValue(shorthand.properties()[i]); if (values[i]) { if (values[i]->isValueList()) { CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get()); @@ -389,7 +308,7 @@ String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t bool useRepeatXShorthand = false; bool useRepeatYShorthand = false; bool useSingleWordShorthand = false; - for (size_t j = 0; j < size; j++) { + for (unsigned j = 0; j < size; j++) { RefPtr<CSSValue> value; if (values[j]) { if (values[j]->isValueList()) @@ -398,7 +317,7 @@ String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t value = values[j]; // Color only belongs in the last layer. - if (properties[j] == CSSPropertyBackgroundColor) { + if (shorthand.properties()[j] == CSSPropertyBackgroundColor) { if (i != numLayers - 1) value = 0; } else if (i != 0) // Other singletons only belong in the first layer. @@ -409,10 +328,10 @@ String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t // We need to report background-repeat as it was written in the CSS. If the property is implicit, // then it was written with only one value. Here we figure out which value that was so we can // report back correctly. - if (properties[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(properties[j])) { + if (shorthand.properties()[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(shorthand.properties()[j])) { // BUG 49055: make sure the value was not reset in the layer check just above. - if (j < size - 1 && properties[j + 1] == CSSPropertyBackgroundRepeatY && value) { + if (j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyBackgroundRepeatY && value) { RefPtr<CSSValue> yValue; RefPtr<CSSValue> nextValue = values[j + 1]; if (nextValue->isValueList()) @@ -460,33 +379,35 @@ String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t res += layerRes; } } - return res; } -String StylePropertySet::getShorthandValue(const int* properties, size_t size) const +String StylePropertySet::getShorthandValue(const StylePropertyShorthand& shorthand) const { String res; - for (size_t i = 0; i < size; ++i) { - if (!isPropertyImplicit(properties[i])) { - RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]); - // FIXME: provide default value if !value - if (value) { - if (!res.isNull()) - res += " "; - res += value->cssText(); - } + for (unsigned i = 0; i < shorthand.length(); ++i) { + if (!isPropertyImplicit(shorthand.properties()[i])) { + RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); + if (!value) + return String(); + if (value->isInitialValue()) + continue; + if (!res.isNull()) + res += " "; + res += value->cssText(); } } return res; } // only returns a non-null value if all properties have the same, non-null value -String StylePropertySet::getCommonValue(const int* properties, size_t size) const +String StylePropertySet::getCommonValue(const StylePropertyShorthand& shorthand) const { String res; - for (size_t i = 0; i < size; ++i) { - RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]); + bool lastPropertyWasImportant = false; + for (unsigned i = 0; i < shorthand.length(); ++i) { + RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); + // FIXME: CSSInitialValue::cssText should generate the right value. if (!value) return String(); String text = value->cssText(); @@ -496,25 +417,51 @@ String StylePropertySet::getCommonValue(const int* properties, size_t size) cons res = text; else if (res != text) return String(); + + bool currentPropertyIsImportant = propertyIsImportant(shorthand.properties()[i]); + if (i && lastPropertyWasImportant != currentPropertyIsImportant) + return String(); + lastPropertyWasImportant = currentPropertyIsImportant; } return res; } -PassRefPtr<CSSValue> StylePropertySet::getPropertyCSSValue(int propertyID) const +String StylePropertySet::borderPropertyValue(CommonValueMode valueMode) const +{ + const StylePropertyShorthand properties[3] = { borderWidthShorthand(), borderStyleShorthand(), borderColorShorthand() }; + StringBuilder result; + for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { + String value = getCommonValue(properties[i]); + if (value.isNull()) { + if (valueMode == ReturnNullOnUncommonValues) + return String(); + ASSERT(valueMode == OmitUncommonValues); + continue; + } + if (value == "initial") + continue; + if (!result.isEmpty()) + result.append(' '); + result.append(value); + } + return result.isEmpty() ? String() : result.toString(); +} + +PassRefPtr<CSSValue> StylePropertySet::getPropertyCSSValue(CSSPropertyID propertyID) const { const CSSProperty* property = findPropertyWithId(propertyID); return property ? property->value() : 0; } -bool StylePropertySet::removeShorthandProperty(int propertyID) +bool StylePropertySet::removeShorthandProperty(CSSPropertyID propertyID) { - CSSPropertyLonghand longhand = longhandForProperty(propertyID); - if (!longhand.length()) + StylePropertyShorthand shorthand = shorthandForProperty(propertyID); + if (!shorthand.length()) return false; - return removePropertiesInSet(longhand.properties(), longhand.length()); + return removePropertiesInSet(shorthand.properties(), shorthand.length()); } -bool StylePropertySet::removeProperty(int propertyID, String* returnText) +bool StylePropertySet::removeProperty(CSSPropertyID propertyID, String* returnText) { if (removeShorthandProperty(propertyID)) { // FIXME: Return an equivalent shorthand when possible. @@ -540,36 +487,36 @@ bool StylePropertySet::removeProperty(int propertyID, String* returnText) return true; } -bool StylePropertySet::propertyIsImportant(int propertyID) const +bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const { const CSSProperty* property = findPropertyWithId(propertyID); if (property) return property->isImportant(); - CSSPropertyLonghand longhands = longhandForProperty(propertyID); - if (!longhands.length()) + StylePropertyShorthand shorthand = shorthandForProperty(propertyID); + if (!shorthand.length()) return false; - for (unsigned i = 0; i < longhands.length(); ++i) { - if (!propertyIsImportant(longhands.properties()[i])) + for (unsigned i = 0; i < shorthand.length(); ++i) { + if (!propertyIsImportant(shorthand.properties()[i])) return false; } return true; } -int StylePropertySet::getPropertyShorthand(int propertyID) const +CSSPropertyID StylePropertySet::getPropertyShorthand(CSSPropertyID propertyID) const { const CSSProperty* property = findPropertyWithId(propertyID); - return property ? property->shorthandID() : 0; + return property ? property->shorthandID() : CSSPropertyInvalid; } -bool StylePropertySet::isPropertyImplicit(int propertyID) const +bool StylePropertySet::isPropertyImplicit(CSSPropertyID propertyID) const { const CSSProperty* property = findPropertyWithId(propertyID); return property ? property->isImplicit() : false; } -bool StylePropertySet::setProperty(int propertyID, const String& value, bool important, CSSStyleSheet* contextStyleSheet) +bool StylePropertySet::setProperty(CSSPropertyID propertyID, const String& value, bool important, StyleSheetInternal* contextStyleSheet) { // Setting the value to an empty string just removes the property in both IE and Gecko. // Setting it to null seems to produce less consistent results, but we treat it just the same. @@ -580,22 +527,22 @@ bool StylePropertySet::setProperty(int propertyID, const String& value, bool imp // When replacing an existing property value, this moves the property to the end of the list. // Firefox preserves the position, and MSIE moves the property to the beginning. - return CSSParser::parseValue(this, propertyID, value, important, useStrictParsing(), contextStyleSheet); + return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet); } -void StylePropertySet::setProperty(int propertyID, PassRefPtr<CSSValue> prpValue, bool important) +void StylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtr<CSSValue> prpValue, bool important) { - CSSPropertyLonghand longhand = longhandForProperty(propertyID); - if (!longhand.length()) { + StylePropertyShorthand shorthand = shorthandForProperty(propertyID); + if (!shorthand.length()) { setProperty(CSSProperty(propertyID, prpValue, important)); return; } - removePropertiesInSet(longhand.properties(), longhand.length()); + removePropertiesInSet(shorthand.properties(), shorthand.length()); RefPtr<CSSValue> value = prpValue; - for (unsigned i = 0; i < longhand.length(); ++i) - m_properties.append(CSSProperty(longhand.properties()[i], value, important)); + for (unsigned i = 0; i < shorthand.length(); ++i) + m_properties.append(CSSProperty(shorthand.properties()[i], value, important)); } void StylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot) @@ -610,22 +557,22 @@ void StylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slo m_properties.append(property); } -bool StylePropertySet::setProperty(int propertyID, int identifier, bool important, CSSStyleSheet* contextStyleSheet) +bool StylePropertySet::setProperty(CSSPropertyID propertyID, int identifier, bool important) { - RefPtr<CSSPrimitiveValue> value; - if (Document* document = contextStyleSheet ? contextStyleSheet->findDocument() : 0) - value = document->cssValuePool()->createIdentifierValue(identifier); - else - value = CSSPrimitiveValue::createIdentifier(identifier); - - setProperty(CSSProperty(propertyID, value.release(), important)); + setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); return true; } -void StylePropertySet::parseDeclaration(const String& styleDeclaration, CSSStyleSheet* contextStyleSheet) +void StylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetInternal* contextStyleSheet) { m_properties.clear(); - CSSParser parser(useStrictParsing()); + + CSSParserContext context(cssParserMode()); + if (contextStyleSheet) { + context = contextStyleSheet->parserContext(); + context.mode = cssParserMode(); + } + CSSParser parser(context); parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet); } @@ -639,34 +586,181 @@ void StylePropertySet::addParsedProperties(const CSSProperty* properties, int nu void StylePropertySet::addParsedProperty(const CSSProperty& property) { // Only add properties that have no !important counterpart present - if (!propertyIsImportant(property.id()) || property.isImportant()) { - removeProperty(property.id()); - m_properties.append(property); - } + if (!propertyIsImportant(property.id()) || property.isImportant()) + setProperty(property); } String StylePropertySet::asText() const { - String result = ""; + StringBuilder result; const CSSProperty* positionXProp = 0; const CSSProperty* positionYProp = 0; const CSSProperty* repeatXProp = 0; const CSSProperty* repeatYProp = 0; + // FIXME: Stack-allocate the buffer for these BitVectors. + BitVector shorthandPropertyUsed; + BitVector shorthandPropertyAppeared; + unsigned size = m_properties.size(); for (unsigned n = 0; n < size; ++n) { const CSSProperty& prop = m_properties[n]; - if (prop.id() == CSSPropertyBackgroundPositionX) + CSSPropertyID propertyID = prop.id(); + CSSPropertyID shorthandPropertyID = CSSPropertyInvalid; + CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid; + String value; + + switch (propertyID) { + case CSSPropertyBackgroundPositionX: positionXProp = ∝ - else if (prop.id() == CSSPropertyBackgroundPositionY) + continue; + case CSSPropertyBackgroundPositionY: positionYProp = ∝ - else if (prop.id() == CSSPropertyBackgroundRepeatX) + continue; + case CSSPropertyBackgroundRepeatX: repeatXProp = ∝ - else if (prop.id() == CSSPropertyBackgroundRepeatY) + continue; + case CSSPropertyBackgroundRepeatY: repeatYProp = ∝ - else - result += prop.cssText(); + continue; + case CSSPropertyBorderTopWidth: + case CSSPropertyBorderRightWidth: + case CSSPropertyBorderBottomWidth: + case CSSPropertyBorderLeftWidth: + if (!borderFallbackShorthandProperty) + borderFallbackShorthandProperty = CSSPropertyBorderWidth; + case CSSPropertyBorderTopStyle: + case CSSPropertyBorderRightStyle: + case CSSPropertyBorderBottomStyle: + case CSSPropertyBorderLeftStyle: + if (!borderFallbackShorthandProperty) + borderFallbackShorthandProperty = CSSPropertyBorderStyle; + case CSSPropertyBorderTopColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + if (!borderFallbackShorthandProperty) + borderFallbackShorthandProperty = CSSPropertyBorderColor; + + // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified. + if (!shorthandPropertyAppeared.get(CSSPropertyBorder - firstCSSProperty)) { + value = borderPropertyValue(ReturnNullOnUncommonValues); + if (value.isNull()) + shorthandPropertyAppeared.ensureSizeAndSet(CSSPropertyBorder - firstCSSProperty, numCSSProperties); + else + shorthandPropertyID = CSSPropertyBorder; + } else if (shorthandPropertyUsed.get(CSSPropertyBorder - firstCSSProperty)) + shorthandPropertyID = CSSPropertyBorder; + if (!shorthandPropertyID) + shorthandPropertyID = borderFallbackShorthandProperty; + break; + case CSSPropertyWebkitBorderHorizontalSpacing: + case CSSPropertyWebkitBorderVerticalSpacing: + shorthandPropertyID = CSSPropertyBorderSpacing; + break; + case CSSPropertyFontFamily: + case CSSPropertyLineHeight: + case CSSPropertyFontSize: + case CSSPropertyFontStyle: + case CSSPropertyFontVariant: + case CSSPropertyFontWeight: + // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing. + break; + case CSSPropertyListStyleType: + case CSSPropertyListStylePosition: + case CSSPropertyListStyleImage: + shorthandPropertyID = CSSPropertyListStyle; + break; + case CSSPropertyMarginTop: + case CSSPropertyMarginRight: + case CSSPropertyMarginBottom: + case CSSPropertyMarginLeft: + shorthandPropertyID = CSSPropertyMargin; + break; + case CSSPropertyOutlineWidth: + case CSSPropertyOutlineStyle: + case CSSPropertyOutlineColor: + shorthandPropertyID = CSSPropertyOutline; + break; + case CSSPropertyOverflowX: + case CSSPropertyOverflowY: + shorthandPropertyID = CSSPropertyOverflow; + break; + case CSSPropertyPaddingTop: + case CSSPropertyPaddingRight: + case CSSPropertyPaddingBottom: + case CSSPropertyPaddingLeft: + shorthandPropertyID = CSSPropertyPadding; + break; + case CSSPropertyWebkitAnimationName: + case CSSPropertyWebkitAnimationDuration: + case CSSPropertyWebkitAnimationTimingFunction: + case CSSPropertyWebkitAnimationDelay: + case CSSPropertyWebkitAnimationIterationCount: + case CSSPropertyWebkitAnimationDirection: + case CSSPropertyWebkitAnimationFillMode: + shorthandPropertyID = CSSPropertyWebkitAnimation; + break; + case CSSPropertyWebkitFlexDirection: + case CSSPropertyWebkitFlexWrap: + shorthandPropertyID = CSSPropertyWebkitFlexFlow; + break; + case CSSPropertyWebkitMaskPositionX: + case CSSPropertyWebkitMaskPositionY: + case CSSPropertyWebkitMaskRepeatX: + case CSSPropertyWebkitMaskRepeatY: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskRepeat: + case CSSPropertyWebkitMaskAttachment: + case CSSPropertyWebkitMaskPosition: + case CSSPropertyWebkitMaskClip: + case CSSPropertyWebkitMaskOrigin: + shorthandPropertyID = CSSPropertyWebkitMask; + break; + case CSSPropertyWebkitTransformOriginX: + case CSSPropertyWebkitTransformOriginY: + case CSSPropertyWebkitTransformOriginZ: + shorthandPropertyID = CSSPropertyWebkitTransformOrigin; + break; + case CSSPropertyWebkitTransitionProperty: + case CSSPropertyWebkitTransitionDuration: + case CSSPropertyWebkitTransitionTimingFunction: + case CSSPropertyWebkitTransitionDelay: + shorthandPropertyID = CSSPropertyWebkitTransition; + break; + case CSSPropertyWebkitWrapFlow: + case CSSPropertyWebkitWrapMargin: + case CSSPropertyWebkitWrapPadding: + shorthandPropertyID = CSSPropertyWebkitWrap; + break; + default: + break; + } + + unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty; + if (shorthandPropertyID) { + if (shorthandPropertyUsed.get(shortPropertyIndex)) + continue; + if (!shorthandPropertyAppeared.get(shortPropertyIndex) && value.isNull()) + value = getPropertyValue(shorthandPropertyID); + shorthandPropertyAppeared.ensureSizeAndSet(shortPropertyIndex, numCSSProperties); + } + + if (!value.isNull()) { + propertyID = shorthandPropertyID; + shorthandPropertyUsed.ensureSizeAndSet(shortPropertyIndex, numCSSProperties); + } else + value = prop.value()->cssText(); + + if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID)) + continue; + + result.append(getPropertyName(propertyID)); + result.append(": "); + result.append(value); + result.append(prop.isImportant() ? " !important" : ""); + result.append("; "); } // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output. @@ -674,37 +768,45 @@ String StylePropertySet::asText() const // would not work in Firefox (<rdar://problem/5143183>) // It would be a better solution if background-position was CSS_PAIR. if (positionXProp && positionYProp && positionXProp->isImportant() == positionYProp->isImportant()) { - String positionValue; - const int properties[2] = { CSSPropertyBackgroundPositionX, CSSPropertyBackgroundPositionY }; + result.append("background-position: "); if (positionXProp->value()->isValueList() || positionYProp->value()->isValueList()) - positionValue = getLayeredShorthandValue(properties); - else - positionValue = positionXProp->value()->cssText() + " " + positionYProp->value()->cssText(); - result += "background-position: " + positionValue + (positionXProp->isImportant() ? " !important" : "") + "; "; + result.append(getLayeredShorthandValue(backgroundPositionShorthand())); + else { + result.append(positionXProp->value()->cssText()); + result.append(" "); + result.append(positionYProp->value()->cssText()); + } + if (positionXProp->isImportant()) + result.append(" !important"); + result.append("; "); } else { if (positionXProp) - result += positionXProp->cssText(); + result.append(positionXProp->cssText()); if (positionYProp) - result += positionYProp->cssText(); + result.append(positionYProp->cssText()); } // FIXME: We need to do the same for background-repeat. if (repeatXProp && repeatYProp && repeatXProp->isImportant() == repeatYProp->isImportant()) { - String repeatValue; - const int repeatProperties[2] = { CSSPropertyBackgroundRepeatX, CSSPropertyBackgroundRepeatY }; + result.append("background-repeat: "); if (repeatXProp->value()->isValueList() || repeatYProp->value()->isValueList()) - repeatValue = getLayeredShorthandValue(repeatProperties); - else - repeatValue = repeatXProp->value()->cssText() + " " + repeatYProp->value()->cssText(); - result += "background-repeat: " + repeatValue + (repeatXProp->isImportant() ? " !important" : "") + "; "; + result.append(getLayeredShorthandValue(backgroundRepeatShorthand())); + else { + result.append(repeatXProp->value()->cssText()); + result.append(" "); + result.append(repeatYProp->value()->cssText()); + } + if (repeatXProp->isImportant()) + result.append(" !important"); + result.append("; "); } else { if (repeatXProp) - result += repeatXProp->cssText(); + result.append(repeatXProp->cssText()); if (repeatYProp) - result += repeatYProp->cssText(); + result.append(repeatYProp->cssText()); } - return result; + return result.toString(); } void StylePropertySet::merge(const StylePropertySet* other, bool argOverridesOnConflict) @@ -722,7 +824,7 @@ void StylePropertySet::merge(const StylePropertySet* other, bool argOverridesOnC } } -void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, CSSStyleSheet* contextStyleSheet) +void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetInternal* contextStyleSheet) { size_t size = m_properties.size(); for (size_t i = 0; i < size; ++i) @@ -731,7 +833,7 @@ void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, CSSStyle // This is the list of properties we want to copy in the copyBlockProperties() function. // It is the list of CSS properties that apply specially to block-level elements. -static const int blockProperties[] = { +static const CSSPropertyID blockProperties[] = { CSSPropertyOrphans, CSSPropertyOverflow, // This can be also be applied to replaced elements CSSPropertyWebkitAspectRatio, @@ -767,13 +869,13 @@ void StylePropertySet::removeBlockProperties() removePropertiesInSet(blockProperties, numBlockProperties); } -bool StylePropertySet::removePropertiesInSet(const int* set, unsigned length) +bool StylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length) { if (m_properties.isEmpty()) return false; // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless. - HashSet<int> toRemove; + HashSet<CSSPropertyID> toRemove; for (unsigned i = 0; i < length; ++i) toRemove.add(set[i]); @@ -796,19 +898,19 @@ bool StylePropertySet::removePropertiesInSet(const int* set, unsigned length) return changed; } -const CSSProperty* StylePropertySet::findPropertyWithId(int propertyID) const +const CSSProperty* StylePropertySet::findPropertyWithId(CSSPropertyID propertyID) const { for (int n = m_properties.size() - 1 ; n >= 0; --n) { - if (propertyID == m_properties[n].m_id) + if (propertyID == m_properties[n].id()) return &m_properties[n]; } return 0; } -CSSProperty* StylePropertySet::findPropertyWithId(int propertyID) +CSSProperty* StylePropertySet::findPropertyWithId(CSSPropertyID propertyID) { for (int n = m_properties.size() - 1 ; n >= 0; --n) { - if (propertyID == m_properties[n].m_id) + if (propertyID == m_properties[n].id()) return &m_properties[n]; } return 0; @@ -822,7 +924,7 @@ bool StylePropertySet::propertyMatches(const CSSProperty* property) const void StylePropertySet::removeEquivalentProperties(const StylePropertySet* style) { - Vector<int> propertiesToRemove; + Vector<CSSPropertyID> propertiesToRemove; size_t size = m_properties.size(); for (size_t i = 0; i < size; ++i) { const CSSProperty& property = m_properties[i]; @@ -836,7 +938,7 @@ void StylePropertySet::removeEquivalentProperties(const StylePropertySet* style) void StylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style) { - Vector<int> propertiesToRemove; + Vector<CSSPropertyID> propertiesToRemove; size_t size = m_properties.size(); for (size_t i = 0; i < size; ++i) { const CSSProperty& property = m_properties[i]; @@ -850,10 +952,10 @@ void StylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* sty PassRefPtr<StylePropertySet> StylePropertySet::copy() const { - return adoptRef(new StylePropertySet(m_properties)); + return adoptRef(new StylePropertySet(*this)); } -PassRefPtr<StylePropertySet> StylePropertySet::copyPropertiesInSet(const int* set, unsigned length) const +PassRefPtr<StylePropertySet> StylePropertySet::copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const { Vector<CSSProperty> list; list.reserveInitialCapacity(length); @@ -867,57 +969,44 @@ PassRefPtr<StylePropertySet> StylePropertySet::copyPropertiesInSet(const int* se CSSStyleDeclaration* StylePropertySet::ensureCSSStyleDeclaration() const { - if (m_hasCSSOMWrapper) { + if (m_ownsCSSOMWrapper) { ASSERT(!static_cast<CSSStyleDeclaration*>(propertySetCSSOMWrapperMap().get(this))->parentRule()); ASSERT(!propertySetCSSOMWrapperMap().get(this)->parentElement()); return propertySetCSSOMWrapperMap().get(this); } - m_hasCSSOMWrapper = true; + m_ownsCSSOMWrapper = true; PropertySetCSSStyleDeclaration* cssomWrapper = new PropertySetCSSStyleDeclaration(const_cast<StylePropertySet*>(this)); propertySetCSSOMWrapperMap().add(this, adoptPtr(cssomWrapper)); return cssomWrapper; } -CSSStyleDeclaration* StylePropertySet::ensureRuleCSSStyleDeclaration(const CSSRule* parentRule) const -{ - if (m_hasCSSOMWrapper) { - ASSERT(static_cast<CSSStyleDeclaration*>(propertySetCSSOMWrapperMap().get(this))->parentRule() == parentRule); - return propertySetCSSOMWrapperMap().get(this); - } - m_hasCSSOMWrapper = true; - PropertySetCSSStyleDeclaration* cssomWrapper = new RuleCSSStyleDeclaration(const_cast<StylePropertySet*>(this), const_cast<CSSRule*>(parentRule)); - propertySetCSSOMWrapperMap().add(this, adoptPtr(cssomWrapper)); - return cssomWrapper; -} - CSSStyleDeclaration* StylePropertySet::ensureInlineCSSStyleDeclaration(const StyledElement* parentElement) const { - if (m_hasCSSOMWrapper) { + if (m_ownsCSSOMWrapper) { ASSERT(propertySetCSSOMWrapperMap().get(this)->parentElement() == parentElement); return propertySetCSSOMWrapperMap().get(this); } - m_hasCSSOMWrapper = true; + m_ownsCSSOMWrapper = true; PropertySetCSSStyleDeclaration* cssomWrapper = new InlineCSSStyleDeclaration(const_cast<StylePropertySet*>(this), const_cast<StyledElement*>(parentElement)); propertySetCSSOMWrapperMap().add(this, adoptPtr(cssomWrapper)); return cssomWrapper; } -void StylePropertySet::clearParentRule(CSSRule* rule) -{ - if (!m_hasCSSOMWrapper) - return; - ASSERT_UNUSED(rule, static_cast<CSSStyleDeclaration*>(propertySetCSSOMWrapperMap().get(this))->parentRule() == rule); - propertySetCSSOMWrapperMap().get(this)->clearParentRule(); -} - void StylePropertySet::clearParentElement(StyledElement* element) { - if (!m_hasCSSOMWrapper) + if (!m_ownsCSSOMWrapper) return; ASSERT_UNUSED(element, propertySetCSSOMWrapperMap().get(this)->parentElement() == element); propertySetCSSOMWrapperMap().get(this)->clearParentElement(); } +unsigned StylePropertySet::averageSizeInBytes() +{ + // Please update this if the storage scheme changes so that this longer reflects the actual size. + return sizeof(StylePropertySet); +} + +// See the function above if you need to update this. class SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> { Vector<CSSProperty, 4> properties; unsigned bitfield; |