/* * (C) 1999-2003 Lars Knoll (knoll@kde.org) * Copyright (C) 2004, 2005, 2006, 2008, 2012 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. */ #ifndef StylePropertySet_h #define StylePropertySet_h #include "core/CSSPropertyNames.h" #include "core/css/CSSPrimitiveValue.h" #include "core/css/CSSProperty.h" #include "core/css/PropertySetCSSStyleDeclaration.h" #include "core/css/parser/CSSParserMode.h" #include "wtf/ListHashSet.h" #include "wtf/Vector.h" #include "wtf/text/WTFString.h" namespace blink { class CSSRule; class CSSStyleDeclaration; class Element; class ImmutableStylePropertySet; class KURL; class MutableStylePropertySet; class StylePropertyShorthand; class StyleSheetContents; class StylePropertySet : public RefCountedWillBeGarbageCollectedFinalized { friend class PropertyReference; public: #if ENABLE(OILPAN) // When oilpan is enabled override the finalize method to dispatch to the subclasses' // destructor. This can be removed once the MutableStylePropertySet's OwnPtr is moved // to the heap. void finalizeGarbageCollectedObject(); #else // Override RefCounted's deref() to ensure operator delete is called on // the appropriate subclass type. void deref(); #endif class PropertyReference { public: PropertyReference(const StylePropertySet& propertySet, unsigned index) : m_propertySet(propertySet) , m_index(index) { } CSSPropertyID id() const { return static_cast(propertyMetadata().m_propertyID); } CSSPropertyID shorthandID() const { return propertyMetadata().shorthandID(); } bool isImportant() const { return propertyMetadata().m_important; } bool isInherited() const { return propertyMetadata().m_inherited; } bool isImplicit() const { return propertyMetadata().m_implicit; } String cssName() const; String cssText() const; const CSSValue* value() const { return propertyValue(); } // FIXME: We should try to remove this mutable overload. CSSValue* value() { return const_cast(propertyValue()); } // FIXME: Remove this. CSSProperty toCSSProperty() const { return CSSProperty(propertyMetadata(), const_cast(propertyValue())); } const StylePropertyMetadata& propertyMetadata() const; private: const CSSValue* propertyValue() const; const StylePropertySet& m_propertySet; unsigned m_index; }; unsigned propertyCount() const; bool isEmpty() const; PropertyReference propertyAt(unsigned index) const { return PropertyReference(*this, index); } int findPropertyIndex(CSSPropertyID) const; bool hasProperty(CSSPropertyID property) const { return findPropertyIndex(property) != -1; } PassRefPtrWillBeRawPtr getPropertyCSSValue(CSSPropertyID) const; String getPropertyValue(CSSPropertyID) const; bool propertyIsImportant(CSSPropertyID) const; CSSPropertyID getPropertyShorthand(CSSPropertyID) const; bool isPropertyImplicit(CSSPropertyID) const; PassRefPtrWillBeRawPtr copyBlockProperties() const; CSSParserMode cssParserMode() const { return static_cast(m_cssParserMode); } PassRefPtrWillBeRawPtr mutableCopy() const; PassRefPtrWillBeRawPtr immutableCopyIfNeeded() const; PassRefPtrWillBeRawPtr copyPropertiesInSet(const Vector&) const; String asText() const; bool isMutable() const { return m_isMutable; } bool hasFailedOrCanceledSubresources() const; static unsigned averageSizeInBytes(); #ifndef NDEBUG void showStyle(); #endif bool propertyMatches(CSSPropertyID, const CSSValue*) const; void trace(Visitor*); void traceAfterDispatch(Visitor*) { } protected: enum { MaxArraySize = (1 << 28) - 1 }; StylePropertySet(CSSParserMode cssParserMode) : m_cssParserMode(cssParserMode) , m_isMutable(true) , m_arraySize(0) { } StylePropertySet(CSSParserMode cssParserMode, unsigned immutableArraySize) : m_cssParserMode(cssParserMode) , m_isMutable(false) , m_arraySize(std::min(immutableArraySize, unsigned(MaxArraySize))) { } unsigned m_cssParserMode : 3; mutable unsigned m_isMutable : 1; unsigned m_arraySize : 28; friend class PropertySetCSSStyleDeclaration; }; class ImmutableStylePropertySet : public StylePropertySet { public: ~ImmutableStylePropertySet(); static PassRefPtrWillBeRawPtr create(const CSSProperty* properties, unsigned count, CSSParserMode); unsigned propertyCount() const { return m_arraySize; } const RawPtrWillBeMember* valueArray() const; const StylePropertyMetadata* metadataArray() const; int findPropertyIndex(CSSPropertyID) const; void traceAfterDispatch(Visitor*); void* operator new(std::size_t, void* location) { return location; } void* m_storage; private: ImmutableStylePropertySet(const CSSProperty*, unsigned count, CSSParserMode); }; inline const RawPtrWillBeMember* ImmutableStylePropertySet::valueArray() const { return reinterpret_cast*>(const_cast(&(this->m_storage))); } inline const StylePropertyMetadata* ImmutableStylePropertySet::metadataArray() const { return reinterpret_cast(&reinterpret_cast(&(this->m_storage))[m_arraySize * sizeof(RawPtrWillBeMember)]); } DEFINE_TYPE_CASTS(ImmutableStylePropertySet, StylePropertySet, set, !set->isMutable(), !set.isMutable()); class MutableStylePropertySet : public StylePropertySet { public: ~MutableStylePropertySet() { } static PassRefPtrWillBeRawPtr create(CSSParserMode = HTMLStandardMode); static PassRefPtrWillBeRawPtr create(const CSSProperty* properties, unsigned count); unsigned propertyCount() const { return m_propertyVector.size(); } void addParsedProperties(const WillBeHeapVector&); void addParsedProperty(const CSSProperty&); // These expand shorthand properties into multiple properties. bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0); void setProperty(CSSPropertyID, PassRefPtrWillBeRawPtr, bool important = false); // These do not. FIXME: This is too messy, we can do better. bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false); bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false); void appendPrefixingVariantProperty(const CSSProperty&); void setPrefixingVariantProperty(const CSSProperty&); void setProperty(const CSSProperty&, CSSProperty* slot = 0); bool removeProperty(CSSPropertyID, String* returnText = 0); void removePrefixedOrUnprefixedProperty(CSSPropertyID); void removeBlockProperties(); bool removePropertiesInSet(const CSSPropertyID* set, unsigned length); void removeEquivalentProperties(const StylePropertySet*); void removeEquivalentProperties(const CSSStyleDeclaration*); void mergeAndOverrideOnConflict(const StylePropertySet*); void clear(); void parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet); CSSStyleDeclaration* ensureCSSStyleDeclaration(); int findPropertyIndex(CSSPropertyID) const; void traceAfterDispatch(Visitor*); private: explicit MutableStylePropertySet(CSSParserMode); explicit MutableStylePropertySet(const StylePropertySet&); MutableStylePropertySet(const CSSProperty* properties, unsigned count); bool removeShorthandProperty(CSSPropertyID); CSSProperty* findCSSPropertyWithID(CSSPropertyID); OwnPtrWillBeMember m_cssomWrapper; friend class StylePropertySet; WillBeHeapVector m_propertyVector; }; DEFINE_TYPE_CASTS(MutableStylePropertySet, StylePropertySet, set, set->isMutable(), set.isMutable()); inline MutableStylePropertySet* toMutableStylePropertySet(const RefPtrWillBeRawPtr& set) { return toMutableStylePropertySet(set.get()); } inline MutableStylePropertySet* toMutableStylePropertySet(const Persistent& set) { return toMutableStylePropertySet(set.get()); } inline MutableStylePropertySet* toMutableStylePropertySet(const Member& set) { return toMutableStylePropertySet(set.get()); } inline const StylePropertyMetadata& StylePropertySet::PropertyReference::propertyMetadata() const { if (m_propertySet.isMutable()) return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).metadata(); return toImmutableStylePropertySet(m_propertySet).metadataArray()[m_index]; } inline const CSSValue* StylePropertySet::PropertyReference::propertyValue() const { if (m_propertySet.isMutable()) return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).value(); return toImmutableStylePropertySet(m_propertySet).valueArray()[m_index]; } inline unsigned StylePropertySet::propertyCount() const { if (m_isMutable) return toMutableStylePropertySet(this)->m_propertyVector.size(); return m_arraySize; } inline bool StylePropertySet::isEmpty() const { return !propertyCount(); } #if !ENABLE(OILPAN) inline void StylePropertySet::deref() { if (!derefBase()) return; if (m_isMutable) delete toMutableStylePropertySet(this); else delete toImmutableStylePropertySet(this); } #endif // !ENABLE(OILPAN) inline int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const { if (m_isMutable) return toMutableStylePropertySet(this)->findPropertyIndex(propertyID); return toImmutableStylePropertySet(this)->findPropertyIndex(propertyID); } } // namespace blink #endif // StylePropertySet_h