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 "CSSPropertyNames.h"
25#include "core/css/CSSParserMode.h"
26#include "core/css/CSSPrimitiveValue.h"
27#include "core/css/CSSProperty.h"
28#include "core/css/CSSVariablesIterator.h"
29#include "core/css/PropertySetCSSStyleDeclaration.h"
30#include "wtf/ListHashSet.h"
31#include "wtf/Vector.h"
32#include "wtf/text/WTFString.h"
33
34namespace WebCore {
35
36class CSSRule;
37class CSSStyleDeclaration;
38class Element;
39class ImmutableStylePropertySet;
40class KURL;
41class MutableStylePropertySet;
42class StylePropertyShorthand;
43class StyleSheetContents;
44
45class StylePropertySet : public RefCounted<StylePropertySet> {
46    friend class PropertyReference;
47public:
48    // Override RefCounted's deref() to ensure operator delete is called on
49    // the appropriate subclass type.
50    void deref();
51
52    class PropertyReference {
53    public:
54        PropertyReference(const StylePropertySet& propertySet, unsigned index)
55            : m_propertySet(propertySet)
56            , m_index(index)
57        {
58        }
59
60        CSSPropertyID id() const { return static_cast<CSSPropertyID>(propertyMetadata().m_propertyID); }
61        CSSPropertyID shorthandID() const { return propertyMetadata().shorthandID(); }
62
63        bool isImportant() const { return propertyMetadata().m_important; }
64        bool isInherited() const { return propertyMetadata().m_inherited; }
65        bool isImplicit() const { return propertyMetadata().m_implicit; }
66
67        String cssName() const;
68        String cssText() const;
69
70        const CSSValue* value() const { return propertyValue(); }
71        // FIXME: We should try to remove this mutable overload.
72        CSSValue* value() { return const_cast<CSSValue*>(propertyValue()); }
73
74        // FIXME: Remove this.
75        CSSProperty toCSSProperty() const { return CSSProperty(propertyMetadata(), const_cast<CSSValue*>(propertyValue())); }
76
77        const StylePropertyMetadata& propertyMetadata() const;
78
79    private:
80        const CSSValue* propertyValue() const;
81
82        const StylePropertySet& m_propertySet;
83        unsigned m_index;
84    };
85
86    unsigned propertyCount() const;
87    bool isEmpty() const;
88    PropertyReference propertyAt(unsigned index) const { return PropertyReference(*this, index); }
89    int findPropertyIndex(CSSPropertyID) const;
90    size_t findVariableIndex(const AtomicString& name) const;
91
92    PassRefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
93    String getPropertyValue(CSSPropertyID) const;
94    unsigned variableCount() const;
95    String variableValue(const AtomicString& name) const;
96
97    bool propertyIsImportant(CSSPropertyID) const;
98    CSSPropertyID getPropertyShorthand(CSSPropertyID) const;
99    bool isPropertyImplicit(CSSPropertyID) const;
100
101    PassRefPtr<MutableStylePropertySet> copyBlockProperties() const;
102
103    CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
104
105    void addSubresourceStyleURLs(ListHashSet<KURL>&, StyleSheetContents* contextStyleSheet) const;
106
107    PassRefPtr<MutableStylePropertySet> mutableCopy() const;
108    PassRefPtr<ImmutableStylePropertySet> immutableCopyIfNeeded() const;
109
110    PassRefPtr<MutableStylePropertySet> copyPropertiesInSet(const Vector<CSSPropertyID>&) const;
111
112    String asText() const;
113
114    bool isMutable() const { return m_isMutable; }
115    bool hasCSSOMWrapper() const;
116
117    bool hasFailedOrCanceledSubresources() const;
118
119    static unsigned averageSizeInBytes();
120
121#ifndef NDEBUG
122    void showStyle();
123#endif
124
125    bool propertyMatches(CSSPropertyID, const CSSValue*) const;
126
127protected:
128
129    enum { MaxArraySize = (1 << 28) - 1 };
130
131    StylePropertySet(CSSParserMode cssParserMode)
132        : m_cssParserMode(cssParserMode)
133        , m_isMutable(true)
134        , m_arraySize(0)
135    { }
136
137    StylePropertySet(CSSParserMode cssParserMode, unsigned immutableArraySize)
138        : m_cssParserMode(cssParserMode)
139        , m_isMutable(false)
140        , m_arraySize(std::min(immutableArraySize, unsigned(MaxArraySize)))
141    { }
142
143    unsigned m_cssParserMode : 3;
144    mutable unsigned m_isMutable : 1;
145    unsigned m_arraySize : 28;
146
147    friend class PropertySetCSSStyleDeclaration;
148};
149
150class ImmutableStylePropertySet : public StylePropertySet {
151public:
152    ~ImmutableStylePropertySet();
153    static PassRefPtr<ImmutableStylePropertySet> create(const CSSProperty* properties, unsigned count, CSSParserMode);
154
155    unsigned propertyCount() const { return m_arraySize; }
156
157    const CSSValue** valueArray() const;
158    const StylePropertyMetadata* metadataArray() const;
159
160    void* m_storage;
161
162private:
163    ImmutableStylePropertySet(const CSSProperty*, unsigned count, CSSParserMode);
164};
165
166inline const CSSValue** ImmutableStylePropertySet::valueArray() const
167{
168    return reinterpret_cast<const CSSValue**>(const_cast<const void**>(&(this->m_storage)));
169}
170
171inline const StylePropertyMetadata* ImmutableStylePropertySet::metadataArray() const
172{
173    return reinterpret_cast<const StylePropertyMetadata*>(&reinterpret_cast<const char*>(&(this->m_storage))[m_arraySize * sizeof(CSSValue*)]);
174}
175
176DEFINE_TYPE_CASTS(ImmutableStylePropertySet, StylePropertySet, set, !set->isMutable(), !set.isMutable());
177
178inline ImmutableStylePropertySet* toImmutableStylePropertySet(const RefPtr<StylePropertySet>& set)
179{
180    return toImmutableStylePropertySet(set.get());
181}
182
183class MutableStylePropertySet : public StylePropertySet {
184public:
185    ~MutableStylePropertySet() { }
186    static PassRefPtr<MutableStylePropertySet> create(CSSParserMode = HTMLQuirksMode);
187    static PassRefPtr<MutableStylePropertySet> create(const CSSProperty* properties, unsigned count);
188
189    unsigned propertyCount() const { return m_propertyVector.size(); }
190    PropertySetCSSStyleDeclaration* cssStyleDeclaration();
191
192    void addParsedProperties(const Vector<CSSProperty, 256>&);
193    void addParsedProperty(const CSSProperty&);
194
195    // These expand shorthand properties into multiple properties.
196    bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
197    void setProperty(CSSPropertyID, PassRefPtr<CSSValue>, bool important = false);
198
199    // These do not. FIXME: This is too messy, we can do better.
200    bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
201    bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
202    void appendPrefixingVariantProperty(const CSSProperty&);
203    void setPrefixingVariantProperty(const CSSProperty&);
204    void setProperty(const CSSProperty&, CSSProperty* slot = 0);
205    bool setVariableValue(const AtomicString& name, const String& value, bool important = false);
206
207    bool removeProperty(CSSPropertyID, String* returnText = 0);
208    void removePrefixedOrUnprefixedProperty(CSSPropertyID);
209    void removeBlockProperties();
210    bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
211    void removeEquivalentProperties(const StylePropertySet*);
212    void removeEquivalentProperties(const CSSStyleDeclaration*);
213    bool removeVariable(const AtomicString& name);
214    bool clearVariables();
215
216    PassRefPtr<CSSVariablesIterator> variablesIterator() { return VariablesIterator::create(this); }
217
218    void mergeAndOverrideOnConflict(const StylePropertySet*);
219
220    void clear();
221    void parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet);
222
223    CSSStyleDeclaration* ensureCSSStyleDeclaration();
224    CSSStyleDeclaration* ensureInlineCSSStyleDeclaration(Element* parentElement);
225
226    Vector<CSSProperty, 4> m_propertyVector;
227
228private:
229    class VariablesIterator : public CSSVariablesIterator {
230    public:
231        virtual ~VariablesIterator() { }
232        static PassRefPtr<VariablesIterator> create(MutableStylePropertySet*);
233    private:
234        explicit VariablesIterator(MutableStylePropertySet* propertySet) : m_propertySet(propertySet) { }
235        void takeRemainingNames(Vector<AtomicString>& remainingNames) { m_remainingNames.swap(remainingNames); }
236        virtual void advance() OVERRIDE;
237        virtual bool atEnd() const OVERRIDE { return m_remainingNames.isEmpty(); }
238        virtual AtomicString name() const OVERRIDE { return m_remainingNames.last(); }
239        virtual String value() const OVERRIDE { return m_propertySet->variableValue(name()); }
240        virtual void addedVariable(const AtomicString& name) OVERRIDE;
241        virtual void removedVariable(const AtomicString& name) OVERRIDE;
242        virtual void clearedVariables() OVERRIDE;
243
244        RefPtr<MutableStylePropertySet> m_propertySet;
245        Vector<AtomicString> m_remainingNames;
246        Vector<AtomicString> m_newNames;
247    };
248
249    explicit MutableStylePropertySet(CSSParserMode);
250    explicit MutableStylePropertySet(const StylePropertySet&);
251    MutableStylePropertySet(const CSSProperty* properties, unsigned count);
252
253    bool removeShorthandProperty(CSSPropertyID);
254    CSSProperty* findCSSPropertyWithID(CSSPropertyID);
255    OwnPtr<PropertySetCSSStyleDeclaration> m_cssomWrapper;
256
257    friend class StylePropertySet;
258};
259
260DEFINE_TYPE_CASTS(MutableStylePropertySet, StylePropertySet, set, set->isMutable(), set.isMutable());
261
262inline MutableStylePropertySet* toMutableStylePropertySet(const RefPtr<StylePropertySet>& set)
263{
264    return toMutableStylePropertySet(set.get());
265}
266
267inline const StylePropertyMetadata& StylePropertySet::PropertyReference::propertyMetadata() const
268{
269    if (m_propertySet.isMutable())
270        return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).metadata();
271    return toImmutableStylePropertySet(m_propertySet).metadataArray()[m_index];
272}
273
274inline const CSSValue* StylePropertySet::PropertyReference::propertyValue() const
275{
276    if (m_propertySet.isMutable())
277        return toMutableStylePropertySet(m_propertySet).m_propertyVector.at(m_index).value();
278    return toImmutableStylePropertySet(m_propertySet).valueArray()[m_index];
279}
280
281inline unsigned StylePropertySet::propertyCount() const
282{
283    if (m_isMutable)
284        return toMutableStylePropertySet(this)->m_propertyVector.size();
285    return m_arraySize;
286}
287
288inline bool StylePropertySet::isEmpty() const
289{
290    return !propertyCount();
291}
292
293inline void StylePropertySet::deref()
294{
295    if (!derefBase())
296        return;
297
298    if (m_isMutable)
299        delete toMutableStylePropertySet(this);
300    else
301        delete toImmutableStylePropertySet(this);
302}
303
304} // namespace WebCore
305
306#endif // StylePropertySet_h
307