1/*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2008, 2012, 2013 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 "CSSParserMode.h"
25#include "CSSPrimitiveValue.h"
26#include "CSSProperty.h"
27#include "CSSPropertyNames.h"
28#include <wtf/ListHashSet.h>
29#include <wtf/Vector.h>
30#include <wtf/text/WTFString.h>
31
32namespace WebCore {
33
34class CSSRule;
35class CSSStyleDeclaration;
36class ComputedStyleExtractor;
37class ImmutableStylePropertySet;
38class KURL;
39class MutableStylePropertySet;
40class PropertySetCSSStyleDeclaration;
41class StyledElement;
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 static_cast<CSSPropertyID>(propertyMetadata().m_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    private:
78        StylePropertyMetadata propertyMetadata() const;
79        const CSSValue* propertyValue() const;
80
81        const StylePropertySet& m_propertySet;
82        unsigned m_index;
83    };
84
85    unsigned propertyCount() const;
86    bool isEmpty() const;
87    PropertyReference propertyAt(unsigned index) const { return PropertyReference(*this, index); }
88
89    PassRefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
90    String getPropertyValue(CSSPropertyID) const;
91    bool propertyIsImportant(CSSPropertyID) const;
92    String getPropertyShorthand(CSSPropertyID) const;
93    bool isPropertyImplicit(CSSPropertyID) const;
94
95    PassRefPtr<MutableStylePropertySet> copyBlockProperties() const;
96
97    CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
98
99    void addSubresourceStyleURLs(ListHashSet<KURL>&, StyleSheetContents* contextStyleSheet) const;
100
101    PassRefPtr<MutableStylePropertySet> mutableCopy() const;
102    PassRefPtr<ImmutableStylePropertySet> immutableCopyIfNeeded() const;
103
104    PassRefPtr<MutableStylePropertySet> copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const;
105
106    String asText() const;
107
108    bool isMutable() const { return m_isMutable; }
109    bool hasCSSOMWrapper() const { return m_ownsCSSOMWrapper; }
110
111    bool hasFailedOrCanceledSubresources() const;
112
113    static unsigned averageSizeInBytes();
114
115#ifndef NDEBUG
116    void showStyle();
117#endif
118
119    bool propertyMatches(CSSPropertyID, const CSSValue*) const;
120
121protected:
122    StylePropertySet(CSSParserMode cssParserMode)
123        : m_cssParserMode(cssParserMode)
124        , m_ownsCSSOMWrapper(false)
125        , m_isMutable(true)
126        , m_arraySize(0)
127    { }
128
129    StylePropertySet(CSSParserMode cssParserMode, unsigned immutableArraySize)
130        : m_cssParserMode(cssParserMode)
131        , m_ownsCSSOMWrapper(false)
132        , m_isMutable(false)
133        , m_arraySize(immutableArraySize)
134    { }
135
136    int findPropertyIndex(CSSPropertyID) const;
137
138    unsigned m_cssParserMode : 2;
139    mutable unsigned m_ownsCSSOMWrapper : 1;
140    mutable unsigned m_isMutable : 1;
141    unsigned m_arraySize : 28;
142
143private:
144    String getShorthandValue(const StylePropertyShorthand&) const;
145    String getCommonValue(const StylePropertyShorthand&) const;
146    enum CommonValueMode { OmitUncommonValues, ReturnNullOnUncommonValues };
147    String borderPropertyValue(CommonValueMode) const;
148    String getLayeredShorthandValue(const StylePropertyShorthand&) const;
149    String get4Values(const StylePropertyShorthand&) const;
150    String borderSpacingValue(const StylePropertyShorthand&) const;
151    String fontValue() const;
152    void appendFontLonghandValueIfExplicit(CSSPropertyID, StringBuilder& result, String& value) const;
153
154    friend class PropertySetCSSStyleDeclaration;
155};
156
157class ImmutableStylePropertySet : public StylePropertySet {
158public:
159    ~ImmutableStylePropertySet();
160    static PassRefPtr<ImmutableStylePropertySet> create(const CSSProperty* properties, unsigned count, CSSParserMode);
161
162    unsigned propertyCount() const { return m_arraySize; }
163
164    const CSSValue** valueArray() const;
165    const StylePropertyMetadata* metadataArray() const;
166
167    void* m_storage;
168
169private:
170    ImmutableStylePropertySet(const CSSProperty*, unsigned count, CSSParserMode);
171};
172
173inline const CSSValue** ImmutableStylePropertySet::valueArray() const
174{
175    return reinterpret_cast<const CSSValue**>(const_cast<const void**>((&static_cast<const ImmutableStylePropertySet*>(this)->m_storage)));
176}
177
178inline const StylePropertyMetadata* ImmutableStylePropertySet::metadataArray() const
179{
180    return reinterpret_cast<const StylePropertyMetadata*>(&reinterpret_cast<const char*>((&static_cast<const ImmutableStylePropertySet*>(this)->m_storage))[m_arraySize * sizeof(CSSValue*)]);
181}
182
183class MutableStylePropertySet : public StylePropertySet {
184public:
185    ~MutableStylePropertySet();
186
187    static PassRefPtr<MutableStylePropertySet> create(CSSParserMode = CSSQuirksMode);
188    static PassRefPtr<MutableStylePropertySet> create(const CSSProperty* properties, unsigned count);
189
190    MutableStylePropertySet(const StylePropertySet&);
191
192    unsigned propertyCount() const { return m_propertyVector.size(); }
193
194    PropertySetCSSStyleDeclaration* cssStyleDeclaration();
195
196    void addParsedProperties(const Vector<CSSProperty>&);
197    void addParsedProperty(const CSSProperty&);
198
199    // These expand shorthand properties into multiple properties.
200    bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
201    void setProperty(CSSPropertyID, PassRefPtr<CSSValue>, bool important = false);
202
203    // These do not. FIXME: This is too messy, we can do better.
204    bool setProperty(CSSPropertyID, int identifier, bool important = false);
205    void appendPrefixingVariantProperty(const CSSProperty&);
206    void setPrefixingVariantProperty(const CSSProperty&);
207    void setProperty(const CSSProperty&, CSSProperty* slot = 0);
208
209    bool removeProperty(CSSPropertyID, String* returnText = 0);
210    void removePrefixedOrUnprefixedProperty(CSSPropertyID);
211    void removeBlockProperties();
212    bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
213
214    // FIXME: These two can be moved to EditingStyle.cpp
215    void removeEquivalentProperties(const StylePropertySet*);
216    void removeEquivalentProperties(const ComputedStyleExtractor*);
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(StyledElement* parentElement);
225
226    Vector<CSSProperty, 4> m_propertyVector;
227
228private:
229    MutableStylePropertySet(CSSParserMode cssParserMode)
230        : StylePropertySet(cssParserMode)
231    { }
232
233    MutableStylePropertySet(const CSSProperty* properties, unsigned count);
234
235    bool removeShorthandProperty(CSSPropertyID);
236    CSSProperty* findCSSPropertyWithID(CSSPropertyID);
237};
238
239inline StylePropertyMetadata StylePropertySet::PropertyReference::propertyMetadata() const
240{
241    if (m_propertySet.isMutable())
242        return static_cast<const MutableStylePropertySet&>(m_propertySet).m_propertyVector.at(m_index).metadata();
243    return static_cast<const ImmutableStylePropertySet&>(m_propertySet).metadataArray()[m_index];
244}
245
246inline const CSSValue* StylePropertySet::PropertyReference::propertyValue() const
247{
248    if (m_propertySet.isMutable())
249        return static_cast<const MutableStylePropertySet&>(m_propertySet).m_propertyVector.at(m_index).value();
250    return static_cast<const ImmutableStylePropertySet&>(m_propertySet).valueArray()[m_index];
251}
252
253inline unsigned StylePropertySet::propertyCount() const
254{
255    if (m_isMutable)
256        return static_cast<const MutableStylePropertySet*>(this)->m_propertyVector.size();
257    return m_arraySize;
258}
259
260inline bool StylePropertySet::isEmpty() const
261{
262    return !propertyCount();
263}
264
265inline void StylePropertySet::deref()
266{
267    if (!derefBase())
268        return;
269
270    if (m_isMutable)
271        delete static_cast<MutableStylePropertySet*>(this);
272    else
273        delete static_cast<ImmutableStylePropertySet*>(this);
274}
275
276} // namespace WebCore
277
278#endif // StylePropertySet_h
279