1/*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2008, 2012 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifndef StylePropertySet_h
22#define StylePropertySet_h
23
24#include "core/CSSPropertyNames.h"
25#include "core/css/CSSPrimitiveValue.h"
26#include "core/css/CSSProperty.h"
27#include "core/css/PropertySetCSSStyleDeclaration.h"
28#include "core/css/parser/CSSParserMode.h"
29#include "wtf/ListHashSet.h"
30#include "wtf/Vector.h"
31#include "wtf/text/WTFString.h"
32
33namespace blink {
34
35class CSSStyleDeclaration;
36class ImmutableStylePropertySet;
37class MutableStylePropertySet;
38class StyleSheetContents;
39
40class StylePropertySet : public RefCountedWillBeGarbageCollectedFinalized<StylePropertySet> {
41    friend class PropertyReference;
42public:
43
44#if ENABLE(OILPAN)
45    // When oilpan is enabled override the finalize method to dispatch to the subclasses'
46    // destructor. This can be removed once the MutableStylePropertySet's OwnPtr is moved
47    // to the heap.
48    void finalizeGarbageCollectedObject();
49#else
50    // Override RefCounted's deref() to ensure operator delete is called on
51    // the appropriate subclass type.
52    void deref();
53#endif
54
55    class PropertyReference {
56    public:
57        PropertyReference(const StylePropertySet& propertySet, unsigned index)
58            : m_propertySet(propertySet)
59            , m_index(index)
60        {
61        }
62
63        CSSPropertyID id() const { return static_cast<CSSPropertyID>(propertyMetadata().m_propertyID); }
64        CSSPropertyID shorthandID() const { return propertyMetadata().shorthandID(); }
65
66        bool isImportant() const { return propertyMetadata().m_important; }
67        bool isInherited() const { return propertyMetadata().m_inherited; }
68        bool isImplicit() const { return propertyMetadata().m_implicit; }
69
70        String cssName() const;
71        String cssText() const;
72
73        const CSSValue* value() const { return propertyValue(); }
74        // FIXME: We should try to remove this mutable overload.
75        CSSValue* value() { return const_cast<CSSValue*>(propertyValue()); }
76
77        // FIXME: Remove this.
78        CSSProperty toCSSProperty() const { return CSSProperty(propertyMetadata(), const_cast<CSSValue*>(propertyValue())); }
79
80        const StylePropertyMetadata& propertyMetadata() const;
81
82    private:
83        const CSSValue* propertyValue() const;
84
85        const StylePropertySet& m_propertySet;
86        unsigned m_index;
87    };
88
89    unsigned propertyCount() const;
90    bool isEmpty() const;
91    PropertyReference propertyAt(unsigned index) const { return PropertyReference(*this, index); }
92    int findPropertyIndex(CSSPropertyID) const;
93    bool hasProperty(CSSPropertyID property) const { return findPropertyIndex(property) != -1; }
94
95    PassRefPtrWillBeRawPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
96    String getPropertyValue(CSSPropertyID) const;
97
98    bool propertyIsImportant(CSSPropertyID) const;
99    CSSPropertyID getPropertyShorthand(CSSPropertyID) const;
100    bool isPropertyImplicit(CSSPropertyID) const;
101
102    PassRefPtrWillBeRawPtr<MutableStylePropertySet> copyBlockProperties() const;
103
104    CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
105
106    PassRefPtrWillBeRawPtr<MutableStylePropertySet> mutableCopy() const;
107    PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> immutableCopyIfNeeded() const;
108
109    PassRefPtrWillBeRawPtr<MutableStylePropertySet> copyPropertiesInSet(const Vector<CSSPropertyID>&) const;
110
111    String asText() const;
112
113    bool isMutable() const { return m_isMutable; }
114
115    bool hasFailedOrCanceledSubresources() const;
116
117    static unsigned averageSizeInBytes();
118
119#ifndef NDEBUG
120    void showStyle();
121#endif
122
123    bool propertyMatches(CSSPropertyID, const CSSValue*) const;
124
125    void trace(Visitor*);
126    void traceAfterDispatch(Visitor*) { }
127
128protected:
129
130    enum { MaxArraySize = (1 << 28) - 1 };
131
132    StylePropertySet(CSSParserMode cssParserMode)
133        : m_cssParserMode(cssParserMode)
134        , m_isMutable(true)
135        , m_arraySize(0)
136    { }
137
138    StylePropertySet(CSSParserMode cssParserMode, unsigned immutableArraySize)
139        : m_cssParserMode(cssParserMode)
140        , m_isMutable(false)
141        , m_arraySize(std::min(immutableArraySize, unsigned(MaxArraySize)))
142    { }
143
144    unsigned m_cssParserMode : 3;
145    mutable unsigned m_isMutable : 1;
146    unsigned m_arraySize : 28;
147
148    friend class PropertySetCSSStyleDeclaration;
149};
150
151class ImmutableStylePropertySet : public StylePropertySet {
152public:
153    ~ImmutableStylePropertySet();
154    static PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> create(const CSSProperty* properties, unsigned count, CSSParserMode);
155
156    unsigned propertyCount() const { return m_arraySize; }
157
158    const RawPtrWillBeMember<CSSValue>* valueArray() const;
159    const StylePropertyMetadata* metadataArray() const;
160    int findPropertyIndex(CSSPropertyID) const;
161
162    void traceAfterDispatch(Visitor*);
163
164    void* operator new(std::size_t, void* location)
165    {
166        return location;
167    }
168
169    void* m_storage;
170
171private:
172    ImmutableStylePropertySet(const CSSProperty*, unsigned count, CSSParserMode);
173};
174
175inline const RawPtrWillBeMember<CSSValue>* ImmutableStylePropertySet::valueArray() const
176{
177    return reinterpret_cast<const RawPtrWillBeMember<CSSValue>*>(const_cast<const void**>(&(this->m_storage)));
178}
179
180inline const StylePropertyMetadata* ImmutableStylePropertySet::metadataArray() const
181{
182    return reinterpret_cast<const StylePropertyMetadata*>(&reinterpret_cast<const char*>(&(this->m_storage))[m_arraySize * sizeof(RawPtrWillBeMember<CSSValue>)]);
183}
184
185DEFINE_TYPE_CASTS(ImmutableStylePropertySet, StylePropertySet, set, !set->isMutable(), !set.isMutable());
186
187class MutableStylePropertySet : public StylePropertySet {
188public:
189    ~MutableStylePropertySet() { }
190    static PassRefPtrWillBeRawPtr<MutableStylePropertySet> create(CSSParserMode = HTMLQuirksMode);
191    static PassRefPtrWillBeRawPtr<MutableStylePropertySet> create(const CSSProperty* properties, unsigned count);
192
193    unsigned propertyCount() const { return m_propertyVector.size(); }
194
195    void addParsedProperties(const WillBeHeapVector<CSSProperty, 256>&);
196    void addParsedProperty(const CSSProperty&);
197
198    // These expand shorthand properties into multiple properties.
199    bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
200    void setProperty(CSSPropertyID, PassRefPtrWillBeRawPtr<CSSValue>, bool important = false);
201
202    // These do not. FIXME: This is too messy, we can do better.
203    bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
204    void appendPrefixingVariantProperty(const CSSProperty&);
205    void setPrefixingVariantProperty(const CSSProperty&);
206    void setProperty(const CSSProperty&, CSSProperty* slot = 0);
207
208    bool removeProperty(CSSPropertyID, String* returnText = 0);
209    void removePrefixedOrUnprefixedProperty(CSSPropertyID);
210    void removeBlockProperties();
211    bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
212    void removeEquivalentProperties(const StylePropertySet*);
213    void removeEquivalentProperties(const CSSStyleDeclaration*);
214
215    void mergeAndOverrideOnConflict(const StylePropertySet*);
216
217    void clear();
218    void parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet);
219
220    CSSStyleDeclaration* ensureCSSStyleDeclaration();
221    int findPropertyIndex(CSSPropertyID) const;
222
223    void traceAfterDispatch(Visitor*);
224
225private:
226    explicit MutableStylePropertySet(CSSParserMode);
227    explicit MutableStylePropertySet(const StylePropertySet&);
228    MutableStylePropertySet(const CSSProperty* properties, unsigned count);
229
230    bool removeShorthandProperty(CSSPropertyID);
231    CSSProperty* findCSSPropertyWithID(CSSPropertyID);
232    OwnPtrWillBeMember<PropertySetCSSStyleDeclaration> m_cssomWrapper;
233
234    friend class StylePropertySet;
235
236    WillBeHeapVector<CSSProperty, 4> m_propertyVector;
237};
238
239DEFINE_TYPE_CASTS(MutableStylePropertySet, StylePropertySet, set, set->isMutable(), set.isMutable());
240
241inline MutableStylePropertySet* toMutableStylePropertySet(const RefPtrWillBeRawPtr<StylePropertySet>& set)
242{
243    return toMutableStylePropertySet(set.get());
244}
245
246inline MutableStylePropertySet* toMutableStylePropertySet(const Persistent<StylePropertySet>& set)
247{
248    return toMutableStylePropertySet(set.get());
249}
250
251inline MutableStylePropertySet* toMutableStylePropertySet(const Member<StylePropertySet>& set)
252{
253    return toMutableStylePropertySet(set.get());
254}
255
256inline const StylePropertyMetadata& StylePropertySet::PropertyReference::propertyMetadata() const
257{
258    if (m_propertySet.isMutable())
259        return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).metadata();
260    return toImmutableStylePropertySet(m_propertySet).metadataArray()[m_index];
261}
262
263inline const CSSValue* StylePropertySet::PropertyReference::propertyValue() const
264{
265    if (m_propertySet.isMutable())
266        return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).value();
267    return toImmutableStylePropertySet(m_propertySet).valueArray()[m_index];
268}
269
270inline unsigned StylePropertySet::propertyCount() const
271{
272    if (m_isMutable)
273        return toMutableStylePropertySet(this)->m_propertyVector.size();
274    return m_arraySize;
275}
276
277inline bool StylePropertySet::isEmpty() const
278{
279    return !propertyCount();
280}
281
282#if !ENABLE(OILPAN)
283inline void StylePropertySet::deref()
284{
285    if (!derefBase())
286        return;
287
288    if (m_isMutable)
289        delete toMutableStylePropertySet(this);
290    else
291        delete toImmutableStylePropertySet(this);
292}
293#endif // !ENABLE(OILPAN)
294
295inline int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
296{
297    if (m_isMutable)
298        return toMutableStylePropertySet(this)->findPropertyIndex(propertyID);
299    return toImmutableStylePropertySet(this)->findPropertyIndex(propertyID);
300}
301
302} // namespace blink
303
304#endif // StylePropertySet_h
305