summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/StylePropertySet.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-02-09 14:16:12 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-02-09 14:16:12 +0100
commit03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (patch)
tree52599cd0ab782b1768e23ad176f7618f98333cb6 /Source/WebCore/css/StylePropertySet.cpp
parentcd44dc59cdfc39534aef4d417e9f3c412e3be139 (diff)
downloadqtwebkit-03e12282df9aa1e1fb05a8b90f1cfc2e08764cec.tar.gz
Imported WebKit commit e09a82039aa4273ab318b71122e92d8e5f233525 (http://svn.webkit.org/repository/webkit/trunk@107223)
Diffstat (limited to 'Source/WebCore/css/StylePropertySet.cpp')
-rw-r--r--Source/WebCore/css/StylePropertySet.cpp1267
1 files changed, 1267 insertions, 0 deletions
diff --git a/Source/WebCore/css/StylePropertySet.cpp b/Source/WebCore/css/StylePropertySet.cpp
new file mode 100644
index 000000000..11ec77172
--- /dev/null
+++ b/Source/WebCore/css/StylePropertySet.cpp
@@ -0,0 +1,1267 @@
+/*
+ * (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Research In Motion Limited. 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 "StylePropertySet.h"
+
+#include "CSSImageValue.h"
+#include "CSSParser.h"
+#include "CSSPropertyLonghand.h"
+#include "CSSPropertyNames.h"
+#include "CSSRule.h"
+#include "CSSStyleSheet.h"
+#include "CSSValueKeywords.h"
+#include "CSSValueList.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "HTMLNames.h"
+#include "InspectorInstrumentation.h"
+#include "MutationObserverInterestGroup.h"
+#include "MutationRecord.h"
+#include "StyledElement.h"
+#include "WebKitMutationObserver.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class PropertySetCSSStyleDeclaration : public CSSStyleDeclaration {
+public:
+ static PassRefPtr<PropertySetCSSStyleDeclaration> create(PassRefPtr<StylePropertySet> propertySet)
+ {
+ return adoptRef(new PropertySetCSSStyleDeclaration(propertySet));
+ }
+
+private:
+ PropertySetCSSStyleDeclaration(PassRefPtr<StylePropertySet> propertySet) : m_propertySet(propertySet) { }
+
+ virtual CSSRule* parentRule() const OVERRIDE;
+ virtual unsigned length() const OVERRIDE;
+ virtual String item(unsigned index) const;
+ virtual PassRefPtr<CSSValue> getPropertyCSSValue(const String& propertyName) OVERRIDE;
+ virtual String getPropertyValue(const String& propertyName) OVERRIDE;
+ virtual String getPropertyPriority(const String& propertyName) OVERRIDE;
+ virtual String getPropertyShorthand(const String& propertyName) OVERRIDE;
+ virtual bool isPropertyImplicit(const String& propertyName) OVERRIDE;
+ virtual void setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode&) OVERRIDE;
+ virtual String removeProperty(const String& propertyName, ExceptionCode&) OVERRIDE;
+ virtual String cssText() const OVERRIDE;
+ virtual void setCssText(const String&, ExceptionCode&);
+ virtual PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) OVERRIDE;
+ virtual String getPropertyValueInternal(CSSPropertyID) OVERRIDE;
+ virtual void setPropertyInternal(CSSPropertyID, const String& value, bool important, ExceptionCode&) OVERRIDE;
+
+ virtual bool cssPropertyMatches(const CSSProperty*) const OVERRIDE;
+ virtual CSSStyleSheet* parentStyleSheet() const OVERRIDE;
+ virtual PassRefPtr<StylePropertySet> copy() const OVERRIDE;
+ virtual PassRefPtr<StylePropertySet> makeMutable() OVERRIDE;
+
+ RefPtr<StylePropertySet> m_propertySet;
+};
+
+namespace {
+
+class StyleAttributeMutationScope {
+ WTF_MAKE_NONCOPYABLE(StyleAttributeMutationScope);
+public:
+ StyleAttributeMutationScope(StylePropertySet* decl)
+ {
+ ++s_scopeCount;
+
+ if (s_scopeCount != 1) {
+ ASSERT(s_currentDecl == decl);
+ return;
+ }
+
+ ASSERT(!s_currentDecl);
+ s_currentDecl = decl;
+
+#if ENABLE(MUTATION_OBSERVERS)
+ if (!s_currentDecl->isInlineStyleDeclaration())
+ return;
+ if (!s_currentDecl->parentElement())
+ return;
+ m_mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(s_currentDecl->parentElement(), HTMLNames::styleAttr);
+ if (!m_mutationRecipients)
+ return;
+
+ AtomicString oldValue = m_mutationRecipients->isOldValueRequested() ? s_currentDecl->parentElement()->getAttribute(HTMLNames::styleAttr) : nullAtom;
+ m_mutation = MutationRecord::createAttributes(s_currentDecl->parentElement(), HTMLNames::styleAttr, oldValue);
+#endif
+ }
+
+ ~StyleAttributeMutationScope()
+ {
+ --s_scopeCount;
+ if (s_scopeCount)
+ return;
+
+#if ENABLE(MUTATION_OBSERVERS)
+ if (m_mutation && s_shouldDeliver)
+ m_mutationRecipients->enqueueMutationRecord(m_mutation);
+ s_shouldDeliver = false;
+#endif
+ if (!s_shouldNotifyInspector) {
+ s_currentDecl = 0;
+ return;
+ }
+ // We have to clear internal state before calling Inspector's code.
+ StylePropertySet* localCopyStyleDecl = s_currentDecl;
+ s_currentDecl = 0;
+ s_shouldNotifyInspector = false;
+ if (localCopyStyleDecl->isInlineStyleDeclaration() && localCopyStyleDecl->parentElement() && localCopyStyleDecl->parentElement()->document())
+ InspectorInstrumentation::didInvalidateStyleAttr(localCopyStyleDecl->parentElement()->document(), localCopyStyleDecl->parentElement());
+ }
+
+#if ENABLE(MUTATION_OBSERVERS)
+ void enqueueMutationRecord()
+ {
+ s_shouldDeliver = true;
+ }
+#endif
+
+ void didInvalidateStyleAttr()
+ {
+ ASSERT(s_currentDecl->isInlineStyleDeclaration());
+ s_shouldNotifyInspector = true;
+ }
+
+private:
+ static unsigned s_scopeCount;
+ static StylePropertySet* s_currentDecl;
+ static bool s_shouldNotifyInspector;
+#if ENABLE(MUTATION_OBSERVERS)
+ static bool s_shouldDeliver;
+
+ OwnPtr<MutationObserverInterestGroup> m_mutationRecipients;
+ RefPtr<MutationRecord> m_mutation;
+#endif
+};
+
+unsigned StyleAttributeMutationScope::s_scopeCount = 0;
+StylePropertySet* StyleAttributeMutationScope::s_currentDecl = 0;
+bool StyleAttributeMutationScope::s_shouldNotifyInspector = false;
+#if ENABLE(MUTATION_OBSERVERS)
+bool StyleAttributeMutationScope::s_shouldDeliver = false;
+#endif
+
+} // namespace
+
+StylePropertySet::StylePropertySet()
+ : m_strictParsing(false)
+ , m_parentIsElement(false)
+ , m_isInlineStyleDeclaration(false)
+ , m_parent(static_cast<CSSRule*>(0))
+{
+}
+
+StylePropertySet::StylePropertySet(CSSRule* parentRule)
+ : m_strictParsing(!parentRule || parentRule->useStrictParsing())
+ , m_parentIsElement(false)
+ , m_isInlineStyleDeclaration(false)
+ , m_parent(parentRule)
+{
+}
+
+StylePropertySet::StylePropertySet(CSSRule* parentRule, const Vector<CSSProperty>& properties)
+ : m_properties(properties)
+ , m_strictParsing(!parentRule || parentRule->useStrictParsing())
+ , m_parentIsElement(false)
+ , m_isInlineStyleDeclaration(false)
+ , m_parent(parentRule)
+{
+ m_properties.shrinkToFit();
+}
+
+StylePropertySet::StylePropertySet(CSSRule* parentRule, const CSSProperty* const * properties, int numProperties)
+ : m_strictParsing(!parentRule || parentRule->useStrictParsing())
+ , m_parentIsElement(false)
+ , m_isInlineStyleDeclaration(false)
+ , m_parent(parentRule)
+{
+ m_properties.reserveInitialCapacity(numProperties);
+ HashMap<int, bool> candidates;
+ for (int i = 0; i < numProperties; ++i) {
+ const CSSProperty *property = properties[i];
+ ASSERT(property);
+ bool important = property->isImportant();
+
+ HashMap<int, bool>::iterator it = candidates.find(property->id());
+ if (it != candidates.end()) {
+ if (!important && it->second)
+ continue;
+ removeProperty(property->id(), false, false);
+ }
+
+ m_properties.append(*property);
+ candidates.set(property->id(), important);
+ }
+}
+
+StylePropertySet::StylePropertySet(StyledElement* parentElement, bool isInlineStyle)
+ : m_strictParsing(false)
+ , m_parentIsElement(true)
+ , m_isInlineStyleDeclaration(isInlineStyle)
+ , m_parent(parentElement)
+{
+}
+
+StylePropertySet::~StylePropertySet()
+{
+}
+
+void StylePropertySet::deref()
+{
+ if (derefBase()) {
+ delete this;
+ return;
+ }
+ // StylePropertySet and CSSStyleDeclaration ref each other. When we have a declaration and
+ // our refcount drops to one we know it is the only thing keeping us alive.
+ if (m_cssStyleDeclaration && hasOneRef())
+ m_cssStyleDeclaration.clear();
+}
+
+CSSStyleSheet* StylePropertySet::contextStyleSheet() const
+{
+ if (m_parentIsElement) {
+ Document* document = m_parent.element ? m_parent.element->document() : 0;
+ return document ? document->elementSheet() : 0;
+ }
+ return m_parent.rule ? m_parent.rule->parentStyleSheet() : 0;
+}
+
+void StylePropertySet::copyPropertiesFrom(const StylePropertySet& other)
+{
+ m_properties = other.m_properties;
+}
+
+String StylePropertySet::getPropertyValue(int propertyID) const
+{
+ RefPtr<CSSValue> value = getPropertyCSSValue(propertyID);
+ if (value)
+ return value->cssText();
+
+ // 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);
+ }
+#if ENABLE(SVG)
+ case CSSPropertyMarker: {
+ RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart);
+ if (value)
+ return value->cssText();
+ }
+#endif
+ }
+ return String();
+}
+
+String StylePropertySet::borderSpacingValue(const int properties[2]) const
+{
+ RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(properties[0]);
+ RefPtr<CSSValue> verticalValue = getPropertyCSSValue(properties[1]);
+
+ if (!horizontalValue)
+ return String();
+ ASSERT(verticalValue); // By <http://www.w3.org/TR/CSS21/tables.html#separated-borders>.
+
+ String horizontalValueCSSText = horizontalValue->cssText();
+ String verticalValueCSSText = verticalValue->cssText();
+ if (horizontalValueCSSText == verticalValueCSSText)
+ return horizontalValueCSSText;
+ return horizontalValueCSSText + ' ' + verticalValueCSSText;
+}
+
+bool StylePropertySet::appendFontLonghandValueIfExplicit(int propertyId, StringBuilder& result) const
+{
+ const CSSProperty* property = findPropertyWithId(propertyId);
+ if (!property)
+ return false; // All longhands must have at least implicit values if "font" is specified.
+ if (property->isImplicit())
+ return true;
+
+ char prefix = '\0';
+ switch (propertyId) {
+ case CSSPropertyFontStyle:
+ break; // No prefix.
+ case CSSPropertyFontFamily:
+ case CSSPropertyFontVariant:
+ case CSSPropertyFontWeight:
+ prefix = ' ';
+ break;
+ case CSSPropertyLineHeight:
+ prefix = '/';
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (prefix && !result.isEmpty())
+ result.append(prefix);
+ result.append(property->value()->cssText());
+
+ return true;
+}
+
+String StylePropertySet::fontValue() const
+{
+ const CSSProperty* fontSizeProperty = findPropertyWithId(CSSPropertyFontSize);
+ if (!fontSizeProperty || fontSizeProperty->isImplicit())
+ return emptyString();
+
+ StringBuilder result;
+ bool success = true;
+ success &= appendFontLonghandValueIfExplicit(CSSPropertyFontStyle, result);
+ success &= appendFontLonghandValueIfExplicit(CSSPropertyFontVariant, result);
+ success &= appendFontLonghandValueIfExplicit(CSSPropertyFontWeight, result);
+ if (!result.isEmpty())
+ result.append(' ');
+ result.append(fontSizeProperty->value()->cssText());
+ success &= appendFontLonghandValueIfExplicit(CSSPropertyLineHeight, result);
+ success &= appendFontLonghandValueIfExplicit(CSSPropertyFontFamily, result);
+ if (!success) {
+ // An invalid "font" value has been built (should never happen, as at least implicit values
+ // for mandatory longhands are always found in the style), report empty value instead.
+ ASSERT_NOT_REACHED();
+ return emptyString();
+ }
+ return result.toString();
+}
+
+String StylePropertySet::get4Values(const int* properties) 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]);
+
+ // All 4 properties must be specified.
+ if (!topValue || !rightValue || !bottomValue || !leftValue)
+ return String();
+
+ bool showLeft = rightValue->cssText() != leftValue->cssText();
+ bool showBottom = (topValue->cssText() != bottomValue->cssText()) || showLeft;
+ bool showRight = (topValue->cssText() != rightValue->cssText()) || showBottom;
+
+ String res = topValue->cssText();
+ if (showRight)
+ res += " " + rightValue->cssText();
+ if (showBottom)
+ res += " " + bottomValue->cssText();
+ if (showLeft)
+ res += " " + leftValue->cssText();
+
+ return res;
+}
+
+String StylePropertySet::getLayeredShorthandValue(const int* properties, size_t size) const
+{
+ String res;
+
+ // 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]);
+ if (values[i]) {
+ if (values[i]->isValueList()) {
+ CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get());
+ numLayers = max(valueList->length(), numLayers);
+ } else
+ numLayers = max<size_t>(1U, numLayers);
+ }
+ }
+
+ // Now stitch the properties together. Implicit initial values are flagged as such and
+ // can safely be omitted.
+ for (size_t i = 0; i < numLayers; i++) {
+ String layerRes;
+ bool useRepeatXShorthand = false;
+ bool useRepeatYShorthand = false;
+ bool useSingleWordShorthand = false;
+ for (size_t j = 0; j < size; j++) {
+ RefPtr<CSSValue> value;
+ if (values[j]) {
+ if (values[j]->isValueList())
+ value = static_cast<CSSValueList*>(values[j].get())->item(i);
+ else {
+ value = values[j];
+
+ // Color only belongs in the last layer.
+ if (properties[j] == CSSPropertyBackgroundColor) {
+ if (i != numLayers - 1)
+ value = 0;
+ } else if (i != 0) // Other singletons only belong in the first layer.
+ value = 0;
+ }
+ }
+
+ // 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])) {
+
+ // BUG 49055: make sure the value was not reset in the layer check just above.
+ if (j < size - 1 && properties[j + 1] == CSSPropertyBackgroundRepeatY && value) {
+ RefPtr<CSSValue> yValue;
+ RefPtr<CSSValue> nextValue = values[j + 1];
+ if (nextValue->isValueList())
+ yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i);
+ else
+ yValue = nextValue;
+
+ int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent();
+ int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent();
+ if (xId != yId) {
+ if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) {
+ useRepeatXShorthand = true;
+ ++j;
+ } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) {
+ useRepeatYShorthand = true;
+ continue;
+ }
+ } else {
+ useSingleWordShorthand = true;
+ ++j;
+ }
+ }
+ }
+
+ if (value && !value->isImplicitInitialValue()) {
+ if (!layerRes.isNull())
+ layerRes += " ";
+ if (useRepeatXShorthand) {
+ useRepeatXShorthand = false;
+ layerRes += getValueName(CSSValueRepeatX);
+ } else if (useRepeatYShorthand) {
+ useRepeatYShorthand = false;
+ layerRes += getValueName(CSSValueRepeatY);
+ } else if (useSingleWordShorthand) {
+ useSingleWordShorthand = false;
+ layerRes += value->cssText();
+ } else
+ layerRes += value->cssText();
+ }
+ }
+
+ if (!layerRes.isNull()) {
+ if (!res.isNull())
+ res += ", ";
+ res += layerRes;
+ }
+ }
+
+ return res;
+}
+
+String StylePropertySet::getShorthandValue(const int* properties, size_t size) 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();
+ }
+ }
+ }
+ 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 res;
+ for (size_t i = 0; i < size; ++i) {
+ RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
+ if (!value)
+ return String();
+ String text = value->cssText();
+ if (text.isNull())
+ return String();
+ if (res.isNull())
+ res = text;
+ else if (res != text)
+ return String();
+ }
+ return res;
+}
+
+PassRefPtr<CSSValue> StylePropertySet::getPropertyCSSValue(int propertyID) const
+{
+ const CSSProperty* property = findPropertyWithId(propertyID);
+ return property ? property->value() : 0;
+}
+
+bool StylePropertySet::removeShorthandProperty(int propertyID, bool notifyChanged)
+{
+ CSSPropertyLonghand longhand = longhandForProperty(propertyID);
+ if (!longhand.length())
+ return false;
+ return removePropertiesInSet(longhand.properties(), longhand.length(), notifyChanged);
+}
+
+String StylePropertySet::removeProperty(int propertyID, bool notifyChanged, bool returnText)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ if (removeShorthandProperty(propertyID, notifyChanged)) {
+ // FIXME: Return an equivalent shorthand when possible.
+ return String();
+ }
+
+ CSSProperty* foundProperty = findPropertyWithId(propertyID);
+ if (!foundProperty)
+ return String();
+
+ String value = returnText ? foundProperty->value()->cssText() : String();
+
+ // A more efficient removal strategy would involve marking entries as empty
+ // and sweeping them when the vector grows too big.
+ m_properties.remove(foundProperty - m_properties.data());
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+
+ if (notifyChanged)
+ setNeedsStyleRecalc();
+
+ return value;
+}
+
+void StylePropertySet::setNeedsStyleRecalc()
+{
+ if (m_parentIsElement) {
+ StyledElement* element = parentElement();
+ if (!element)
+ return;
+
+ if (!m_isInlineStyleDeclaration) {
+ element->setNeedsStyleRecalc();
+ return;
+ }
+
+ element->setNeedsStyleRecalc(InlineStyleChange);
+ element->invalidateStyleAttribute();
+ StyleAttributeMutationScope(this).didInvalidateStyleAttr();
+ return;
+ }
+
+ if (CSSStyleSheet* styleSheet = contextStyleSheet()) {
+ if (Document* document = styleSheet->findDocument())
+ document->styleSelectorChanged(DeferRecalcStyle);
+ }
+}
+
+bool StylePropertySet::propertyIsImportant(int propertyID) const
+{
+ const CSSProperty* property = findPropertyWithId(propertyID);
+ if (property)
+ return property->isImportant();
+
+ CSSPropertyLonghand longhands = longhandForProperty(propertyID);
+ if (!longhands.length())
+ return false;
+
+ for (unsigned i = 0; i < longhands.length(); ++i) {
+ if (!propertyIsImportant(longhands.properties()[i]))
+ return false;
+ }
+ return true;
+}
+
+int StylePropertySet::getPropertyShorthand(int propertyID) const
+{
+ const CSSProperty* property = findPropertyWithId(propertyID);
+ return property ? property->shorthandID() : 0;
+}
+
+bool StylePropertySet::isPropertyImplicit(int propertyID) const
+{
+ const CSSProperty* property = findPropertyWithId(propertyID);
+ return property ? property->isImplicit() : false;
+}
+
+bool StylePropertySet::setProperty(int propertyID, const String& value, bool important, bool notifyChanged)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ // 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.
+ if (value.isEmpty()) {
+ removeProperty(propertyID, notifyChanged, false);
+ return true;
+ }
+
+ // 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.
+ bool success = CSSParser::parseValue(this, propertyID, value, important, useStrictParsing());
+ if (!success) {
+ // CSS DOM requires raising SYNTAX_ERR here, but this is too dangerous for compatibility,
+ // see <http://bugs.webkit.org/show_bug.cgi?id=7296>.
+ return false;
+ }
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+
+ if (notifyChanged)
+ setNeedsStyleRecalc();
+
+ return true;
+}
+
+void StylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ if (!removeShorthandProperty(property.id(), false)) {
+ CSSProperty* toReplace = slot ? slot : findPropertyWithId(property.id());
+ if (toReplace) {
+ *toReplace = property;
+ return;
+ }
+ }
+ m_properties.append(property);
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+}
+
+bool StylePropertySet::setProperty(int propertyID, int value, bool important, bool notifyChanged)
+{
+ CSSProperty property(propertyID, CSSPrimitiveValue::createIdentifier(value), important);
+ setProperty(property);
+ if (notifyChanged)
+ setNeedsStyleRecalc();
+ return true;
+}
+
+bool StylePropertySet::setProperty(int propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important, bool notifyChanged)
+{
+ CSSProperty property(propertyID, CSSPrimitiveValue::create(value, unit), important);
+ setProperty(property);
+ if (notifyChanged)
+ setNeedsStyleRecalc();
+ return true;
+}
+
+void StylePropertySet::parseDeclaration(const String& styleDeclaration)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ m_properties.clear();
+ CSSParser parser(useStrictParsing());
+ parser.parseDeclaration(this, styleDeclaration);
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+
+ setNeedsStyleRecalc();
+}
+
+void StylePropertySet::addParsedProperties(const CSSProperty* const* properties, int numProperties)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ m_properties.reserveCapacity(numProperties);
+ for (int i = 0; i < numProperties; ++i)
+ addParsedProperty(*properties[i]);
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+
+ // FIXME: This probably should have a call to setNeedsStyleRecalc() if something changed. We may also wish to add
+ // a notifyChanged argument to this function to follow the model of other functions in this class.
+}
+
+void StylePropertySet::addParsedProperty(const CSSProperty& property)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ // Only add properties that have no !important counterpart present
+ if (!propertyIsImportant(property.id()) || property.isImportant()) {
+ removeProperty(property.id(), false, false);
+ m_properties.append(property);
+ }
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+}
+
+String StylePropertySet::asText() const
+{
+ String result = "";
+
+ const CSSProperty* positionXProp = 0;
+ const CSSProperty* positionYProp = 0;
+ const CSSProperty* repeatXProp = 0;
+ const CSSProperty* repeatYProp = 0;
+
+ unsigned size = m_properties.size();
+ for (unsigned n = 0; n < size; ++n) {
+ const CSSProperty& prop = m_properties[n];
+ if (prop.id() == CSSPropertyBackgroundPositionX)
+ positionXProp = &prop;
+ else if (prop.id() == CSSPropertyBackgroundPositionY)
+ positionYProp = &prop;
+ else if (prop.id() == CSSPropertyBackgroundRepeatX)
+ repeatXProp = &prop;
+ else if (prop.id() == CSSPropertyBackgroundRepeatY)
+ repeatYProp = &prop;
+ else
+ result += prop.cssText();
+ }
+
+ // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
+ // It is required because background-position-x/y are non-standard properties and WebKit generated output
+ // 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 };
+ 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" : "") + "; ";
+ } else {
+ if (positionXProp)
+ result += positionXProp->cssText();
+ if (positionYProp)
+ result += 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 };
+ 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" : "") + "; ";
+ } else {
+ if (repeatXProp)
+ result += repeatXProp->cssText();
+ if (repeatYProp)
+ result += repeatYProp->cssText();
+ }
+
+ return result;
+}
+
+void StylePropertySet::merge(const StylePropertySet* other, bool argOverridesOnConflict)
+{
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ unsigned size = other->m_properties.size();
+ for (unsigned n = 0; n < size; ++n) {
+ const CSSProperty& toMerge = other->m_properties[n];
+ CSSProperty* old = findPropertyWithId(toMerge.id());
+ if (old) {
+ if (!argOverridesOnConflict && old->value())
+ continue;
+ setProperty(toMerge, old);
+ } else
+ m_properties.append(toMerge);
+ }
+
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+
+ // FIXME: This probably should have a call to setNeedsStyleRecalc() if something changed. We may also wish to add
+ // a notifyChanged argument to this function to follow the model of other functions in this class.
+}
+
+void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls)
+{
+ CSSStyleSheet* sheet = contextStyleSheet();
+ size_t size = m_properties.size();
+ for (size_t i = 0; i < size; ++i)
+ m_properties[i].value()->addSubresourceStyleURLs(urls, sheet);
+}
+
+// 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[] = {
+ CSSPropertyOrphans,
+ CSSPropertyOverflow, // This can be also be applied to replaced elements
+ CSSPropertyWebkitAspectRatio,
+ CSSPropertyWebkitColumnCount,
+ CSSPropertyWebkitColumnGap,
+ CSSPropertyWebkitColumnRuleColor,
+ CSSPropertyWebkitColumnRuleStyle,
+ CSSPropertyWebkitColumnRuleWidth,
+ CSSPropertyWebkitColumnBreakBefore,
+ CSSPropertyWebkitColumnBreakAfter,
+ CSSPropertyWebkitColumnBreakInside,
+ CSSPropertyWebkitColumnWidth,
+ CSSPropertyPageBreakAfter,
+ CSSPropertyPageBreakBefore,
+ CSSPropertyPageBreakInside,
+ CSSPropertyWebkitRegionBreakAfter,
+ CSSPropertyWebkitRegionBreakBefore,
+ CSSPropertyWebkitRegionBreakInside,
+ CSSPropertyTextAlign,
+ CSSPropertyTextIndent,
+ CSSPropertyWidows
+};
+
+const unsigned numBlockProperties = WTF_ARRAY_LENGTH(blockProperties);
+
+PassRefPtr<StylePropertySet> StylePropertySet::copyBlockProperties() const
+{
+ return copyPropertiesInSet(blockProperties, numBlockProperties);
+}
+
+void StylePropertySet::removeBlockProperties()
+{
+ removePropertiesInSet(blockProperties, numBlockProperties);
+}
+
+bool StylePropertySet::removePropertiesInSet(const int* set, unsigned length, bool notifyChanged)
+{
+ if (m_properties.isEmpty())
+ return false;
+
+#if ENABLE(MUTATION_OBSERVERS)
+ StyleAttributeMutationScope mutationScope(this);
+#endif
+
+ // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless.
+ HashSet<int> toRemove;
+ for (unsigned i = 0; i < length; ++i)
+ toRemove.add(set[i]);
+
+ Vector<CSSProperty, 4> newProperties;
+ newProperties.reserveInitialCapacity(m_properties.size());
+
+ unsigned size = m_properties.size();
+ for (unsigned n = 0; n < size; ++n) {
+ const CSSProperty& property = m_properties[n];
+ // Not quite sure if the isImportant test is needed but it matches the existing behavior.
+ if (!property.isImportant()) {
+ if (toRemove.contains(property.id()))
+ continue;
+ }
+ newProperties.append(property);
+ }
+
+ bool changed = newProperties.size() != m_properties.size();
+ m_properties = newProperties;
+
+ if (notifyChanged) {
+#if ENABLE(MUTATION_OBSERVERS)
+ mutationScope.enqueueMutationRecord();
+#endif
+ setNeedsStyleRecalc();
+ }
+
+ return changed;
+}
+
+const CSSProperty* StylePropertySet::findPropertyWithId(int propertyID) const
+{
+ for (int n = m_properties.size() - 1 ; n >= 0; --n) {
+ if (propertyID == m_properties[n].m_id)
+ return &m_properties[n];
+ }
+ return 0;
+}
+
+CSSProperty* StylePropertySet::findPropertyWithId(int propertyID)
+{
+ for (int n = m_properties.size() - 1 ; n >= 0; --n) {
+ if (propertyID == m_properties[n].m_id)
+ return &m_properties[n];
+ }
+ return 0;
+}
+
+bool StylePropertySet::propertyMatches(const CSSProperty* property) const
+{
+ RefPtr<CSSValue> value = getPropertyCSSValue(property->id());
+ return value && value->cssText() == property->value()->cssText();
+}
+
+void StylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
+{
+ Vector<int> propertiesToRemove;
+ size_t size = m_properties.size();
+ for (size_t i = 0; i < size; ++i) {
+ const CSSProperty& property = m_properties[i];
+ if (style->propertyMatches(&property))
+ propertiesToRemove.append(property.id());
+ }
+ // FIXME: This should use mass removal.
+ for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
+ removeProperty(propertiesToRemove[i]);
+}
+
+void StylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
+{
+ Vector<int> propertiesToRemove;
+ size_t size = m_properties.size();
+ for (size_t i = 0; i < size; ++i) {
+ const CSSProperty& property = m_properties[i];
+ if (style->cssPropertyMatches(&property))
+ propertiesToRemove.append(property.id());
+ }
+ // FIXME: This should use mass removal.
+ for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
+ removeProperty(propertiesToRemove[i]);
+}
+
+PassRefPtr<StylePropertySet> StylePropertySet::copy() const
+{
+ return adoptRef(new StylePropertySet(0, m_properties));
+}
+
+PassRefPtr<StylePropertySet> StylePropertySet::copyPropertiesInSet(const int* set, unsigned length) const
+{
+ Vector<CSSProperty> list;
+ list.reserveInitialCapacity(length);
+ for (unsigned i = 0; i < length; ++i) {
+ RefPtr<CSSValue> value = getPropertyCSSValue(set[i]);
+ if (value)
+ list.append(CSSProperty(set[i], value.release(), false));
+ }
+ return StylePropertySet::create(list);
+}
+
+CSSStyleDeclaration* StylePropertySet::ensureCSSStyleDeclaration() const
+{
+ if (!m_cssStyleDeclaration)
+ m_cssStyleDeclaration = PropertySetCSSStyleDeclaration::create(const_cast<StylePropertySet*>(this));
+ return m_cssStyleDeclaration.get();
+}
+
+unsigned PropertySetCSSStyleDeclaration::length() const
+{
+ return m_propertySet->propertyCount();
+}
+
+String PropertySetCSSStyleDeclaration::item(unsigned i) const
+{
+ if (i >= m_propertySet->propertyCount())
+ return "";
+ return getPropertyName(static_cast<CSSPropertyID>(m_propertySet->propertyAt(i).id()));
+}
+
+CSSRule* PropertySetCSSStyleDeclaration::parentRule() const
+{
+ return m_propertySet->parentRuleInternal();
+}
+
+String PropertySetCSSStyleDeclaration::cssText() const
+{
+ return m_propertySet->asText();
+}
+
+void PropertySetCSSStyleDeclaration::setCssText(const String& text, ExceptionCode& ec)
+{
+ ec = 0;
+ // FIXME: Detect syntax errors and set ec.
+ m_propertySet->parseDeclaration(text);
+}
+
+PassRefPtr<CSSValue> PropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return 0;
+ return m_propertySet->getPropertyCSSValue(propertyID);
+}
+
+String PropertySetCSSStyleDeclaration::getPropertyValue(const String &propertyName)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return String();
+ return m_propertySet->getPropertyValue(propertyID);
+}
+
+String PropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return String();
+ return m_propertySet->propertyIsImportant(propertyID) ? "important" : "";
+}
+
+String PropertySetCSSStyleDeclaration::getPropertyShorthand(const String& propertyName)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return String();
+ int shorthandID = m_propertySet->getPropertyShorthand(propertyID);
+ if (!shorthandID)
+ return String();
+ return getPropertyName(static_cast<CSSPropertyID>(shorthandID));
+}
+
+bool PropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyName)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return false;
+ return m_propertySet->isPropertyImplicit(propertyID);
+}
+
+void PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode& ec)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return;
+ bool important = priority.find("important", 0, false) != notFound;
+ ec = 0;
+ m_propertySet->setProperty(propertyID, value, important, true);
+}
+
+String PropertySetCSSStyleDeclaration::removeProperty(const String& propertyName, ExceptionCode& ec)
+{
+ int propertyID = cssPropertyID(propertyName);
+ if (!propertyID)
+ return String();
+ ec = 0;
+ return m_propertySet->removeProperty(propertyID, true, true);
+}
+
+PassRefPtr<CSSValue> PropertySetCSSStyleDeclaration::getPropertyCSSValueInternal(CSSPropertyID propertyID)
+{
+ return m_propertySet->getPropertyCSSValue(propertyID);
+}
+
+String PropertySetCSSStyleDeclaration::getPropertyValueInternal(CSSPropertyID propertyID)
+{
+ return m_propertySet->getPropertyValue(propertyID);
+}
+
+void PropertySetCSSStyleDeclaration::setPropertyInternal(CSSPropertyID propertyID, const String& value, bool important, ExceptionCode& ec)
+{
+ ec = 0;
+ m_propertySet->setProperty(propertyID, value, important, true);
+}
+
+CSSStyleSheet* PropertySetCSSStyleDeclaration::parentStyleSheet() const
+{
+ return m_propertySet->contextStyleSheet();
+}
+
+PassRefPtr<StylePropertySet> PropertySetCSSStyleDeclaration::copy() const
+{
+ return m_propertySet->copy();
+}
+
+PassRefPtr<StylePropertySet> PropertySetCSSStyleDeclaration::makeMutable()
+{
+ ASSERT(m_propertySet->m_cssStyleDeclaration == this || (!m_propertySet->m_cssStyleDeclaration && m_propertySet->hasOneRef()));
+ if (!m_propertySet->m_cssStyleDeclaration)
+ m_propertySet->m_cssStyleDeclaration = this;
+ return m_propertySet;
+}
+
+bool PropertySetCSSStyleDeclaration::cssPropertyMatches(const CSSProperty* property) const
+{
+ return m_propertySet->propertyMatches(property);
+}
+
+} // namespace WebCore