Don't invalidate style unnecessarily when setting inline style cssText
[WebKit-https.git] / Source / WebCore / css / StyleProperties.h
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  * Copyright (C) 2013 Intel Corporation. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifndef StyleProperties_h
23 #define StyleProperties_h
24
25 #include "CSSParser.h"
26 #include "CSSParserMode.h"
27 #include "CSSPrimitiveValue.h"
28 #include "CSSProperty.h"
29 #include "CSSPropertyNames.h"
30 #include "CSSValueKeywords.h"
31 #include <memory>
32 #include <wtf/ListHashSet.h>
33 #include <wtf/TypeCasts.h>
34 #include <wtf/Vector.h>
35 #include <wtf/text/WTFString.h>
36
37 namespace WebCore {
38
39 class CSSStyleDeclaration;
40 class CachedResource;
41 class ImmutableStyleProperties;
42 class URL;
43 class MutableStyleProperties;
44 class PropertySetCSSStyleDeclaration;
45 class StyledElement;
46 class StylePropertyShorthand;
47 class StyleSheetContents;
48
49 class StyleProperties : public RefCounted<StyleProperties> {
50     friend class PropertyReference;
51 public:
52     // Override RefCounted's deref() to ensure operator delete is called on
53     // the appropriate subclass type.
54     void deref();
55
56     class PropertyReference {
57     public:
58         PropertyReference(const StylePropertyMetadata& metadata, const CSSValue* value)
59             : m_metadata(metadata)
60             , m_value(value)
61         { }
62
63         CSSPropertyID id() const { return static_cast<CSSPropertyID>(m_metadata.m_propertyID); }
64         CSSPropertyID shorthandID() const { return m_metadata.shorthandID(); }
65
66         bool isImportant() const { return m_metadata.m_important; }
67         bool isInherited() const { return m_metadata.m_inherited; }
68         bool isImplicit() const { return m_metadata.m_implicit; }
69
70         String cssName() const;
71         String cssText() const;
72
73         const CSSValue* value() const { return m_value; }
74         // FIXME: We should try to remove this mutable overload.
75         CSSValue* value() { return const_cast<CSSValue*>(m_value); }
76
77         // FIXME: Remove this.
78         CSSProperty toCSSProperty() const { return CSSProperty(id(), const_cast<CSSValue*>(m_value), isImportant(), m_metadata.m_isSetFromShorthand, m_metadata.m_indexInShorthandsVector, isImplicit()); }
79
80     private:
81         const StylePropertyMetadata& m_metadata;
82         const CSSValue* m_value;
83     };
84
85     unsigned propertyCount() const;
86     bool isEmpty() const { return !propertyCount(); }
87     PropertyReference propertyAt(unsigned) const;
88
89     WEBCORE_EXPORT PassRefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
90     WEBCORE_EXPORT String getPropertyValue(CSSPropertyID) const;
91     bool propertyIsImportant(CSSPropertyID) const;
92     String getPropertyShorthand(CSSPropertyID) const;
93     bool isPropertyImplicit(CSSPropertyID) const;
94
95     RefPtr<CSSValue> getCustomPropertyCSSValue(const String& propertyName) const;
96     String getCustomPropertyValue(const String& propertyName) const;
97     bool customPropertyIsImportant(const String& propertyName) const;
98
99     Ref<MutableStyleProperties> copyBlockProperties() const;
100
101     CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
102
103     void addSubresourceStyleURLs(ListHashSet<URL>&, StyleSheetContents* contextStyleSheet) const;
104
105     WEBCORE_EXPORT Ref<MutableStyleProperties> mutableCopy() const;
106     Ref<ImmutableStyleProperties> immutableCopyIfNeeded() const;
107
108     Ref<MutableStyleProperties> copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const;
109     
110     String asText() const;
111
112     bool isMutable() const { return m_isMutable; }
113     bool hasCSSOMWrapper() const;
114
115     bool traverseSubresources(const std::function<bool (const CachedResource&)>& handler) 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 protected:
126     StyleProperties(CSSParserMode cssParserMode)
127         : m_cssParserMode(cssParserMode)
128         , m_isMutable(true)
129         , m_arraySize(0)
130     { }
131
132     StyleProperties(CSSParserMode cssParserMode, unsigned immutableArraySize)
133         : m_cssParserMode(cssParserMode)
134         , m_isMutable(false)
135         , m_arraySize(immutableArraySize)
136     { }
137
138     int findPropertyIndex(CSSPropertyID) const;
139     int findCustomPropertyIndex(const String& propertyName) const;
140     
141     unsigned m_cssParserMode : 2;
142     mutable unsigned m_isMutable : 1;
143     unsigned m_arraySize : 29;
144     
145 private:
146     String getShorthandValue(const StylePropertyShorthand&) const;
147     String getCommonValue(const StylePropertyShorthand&) const;
148     enum CommonValueMode { OmitUncommonValues, ReturnNullOnUncommonValues };
149     String borderPropertyValue(CommonValueMode) const;
150     String getLayeredShorthandValue(const StylePropertyShorthand&) const;
151     String get4Values(const StylePropertyShorthand&) const;
152     String borderSpacingValue(const StylePropertyShorthand&) const;
153     String fontValue() const;
154     void appendFontLonghandValueIfExplicit(CSSPropertyID, StringBuilder& result, String& value) const;
155     
156     PassRefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) const;
157     
158     friend class PropertySetCSSStyleDeclaration;
159 };
160
161 class ImmutableStyleProperties : public StyleProperties {
162 public:
163     WEBCORE_EXPORT ~ImmutableStyleProperties();
164     static Ref<ImmutableStyleProperties> create(const CSSProperty* properties, unsigned count, CSSParserMode);
165
166     unsigned propertyCount() const { return m_arraySize; }
167     bool isEmpty() const { return !propertyCount(); }
168     PropertyReference propertyAt(unsigned index) const;
169
170     const CSSValue** valueArray() const;
171     const StylePropertyMetadata* metadataArray() const;
172     int findPropertyIndex(CSSPropertyID) const;
173     int findCustomPropertyIndex(const String& propertyName) const;
174     
175     void* m_storage;
176
177 private:
178     ImmutableStyleProperties(const CSSProperty*, unsigned count, CSSParserMode);
179 };
180
181 inline const CSSValue** ImmutableStyleProperties::valueArray() const
182 {
183     return reinterpret_cast<const CSSValue**>(const_cast<const void**>((&(this->m_storage))));
184 }
185
186 inline const StylePropertyMetadata* ImmutableStyleProperties::metadataArray() const
187 {
188     return reinterpret_cast_ptr<const StylePropertyMetadata*>(&reinterpret_cast_ptr<const char*>(&(this->m_storage))[m_arraySize * sizeof(CSSValue*)]);
189 }
190
191 class MutableStyleProperties : public StyleProperties {
192 public:
193     WEBCORE_EXPORT static Ref<MutableStyleProperties> create(CSSParserMode = CSSQuirksMode);
194     static Ref<MutableStyleProperties> create(const CSSProperty* properties, unsigned count);
195
196     WEBCORE_EXPORT ~MutableStyleProperties();
197
198     unsigned propertyCount() const { return m_propertyVector.size(); }
199     bool isEmpty() const { return !propertyCount(); }
200     PropertyReference propertyAt(unsigned index) const;
201
202     PropertySetCSSStyleDeclaration* cssStyleDeclaration();
203
204     bool addParsedProperties(const CSSParser::ParsedPropertyVector&);
205     bool addParsedProperty(const CSSProperty&);
206
207     // These expand shorthand properties into multiple properties.
208     bool setProperty(CSSPropertyID, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
209     void setProperty(CSSPropertyID, PassRefPtr<CSSValue>, bool important = false);
210
211     // These do not. FIXME: This is too messy, we can do better.
212     bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
213     bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
214     bool appendPrefixingVariantProperty(const CSSProperty&);
215     void setPrefixingVariantProperty(const CSSProperty&);
216     bool setProperty(const CSSProperty&, CSSProperty* slot = nullptr);
217
218     bool removeProperty(CSSPropertyID, String* returnText = nullptr);
219     void removePrefixedOrUnprefixedProperty(CSSPropertyID);
220     void removeBlockProperties();
221     bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
222
223     void mergeAndOverrideOnConflict(const StyleProperties&);
224
225     void clear();
226     bool parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet);
227
228     WEBCORE_EXPORT CSSStyleDeclaration* ensureCSSStyleDeclaration();
229     CSSStyleDeclaration* ensureInlineCSSStyleDeclaration(StyledElement* parentElement);
230
231     int findPropertyIndex(CSSPropertyID) const;
232     int findCustomPropertyIndex(const String& propertyName) const;
233     
234     Vector<CSSProperty, 4> m_propertyVector;
235
236     // Methods for querying and altering CSS custom properties.
237     bool setCustomProperty(const String& propertyName, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
238     bool removeCustomProperty(const String& propertyName, String* returnText = nullptr);
239
240 private:
241     explicit MutableStyleProperties(CSSParserMode);
242     explicit MutableStyleProperties(const StyleProperties&);
243     MutableStyleProperties(const CSSProperty* properties, unsigned count);
244
245     bool removeShorthandProperty(CSSPropertyID);
246     CSSProperty* findCSSPropertyWithID(CSSPropertyID);
247     CSSProperty* findCustomCSSPropertyWithName(const String&);
248     std::unique_ptr<PropertySetCSSStyleDeclaration> m_cssomWrapper;
249
250     friend class StyleProperties;
251 };
252
253 inline ImmutableStyleProperties::PropertyReference ImmutableStyleProperties::propertyAt(unsigned index) const
254 {
255     return PropertyReference(metadataArray()[index], valueArray()[index]);
256 }
257
258 inline MutableStyleProperties::PropertyReference MutableStyleProperties::propertyAt(unsigned index) const
259 {
260     const CSSProperty& property = m_propertyVector[index];
261     return PropertyReference(property.metadata(), property.value());
262 }
263
264 inline StyleProperties::PropertyReference StyleProperties::propertyAt(unsigned index) const
265 {
266     if (is<MutableStyleProperties>(*this))
267         return downcast<MutableStyleProperties>(*this).propertyAt(index);
268     return downcast<ImmutableStyleProperties>(*this).propertyAt(index);
269 }
270
271 inline unsigned StyleProperties::propertyCount() const
272 {
273     if (is<MutableStyleProperties>(*this))
274         return downcast<MutableStyleProperties>(*this).propertyCount();
275     return downcast<ImmutableStyleProperties>(*this).propertyCount();
276 }
277
278 inline void StyleProperties::deref()
279 {
280     if (!derefBase())
281         return;
282
283     if (is<MutableStyleProperties>(*this))
284         delete downcast<MutableStyleProperties>(this);
285     else
286         delete downcast<ImmutableStyleProperties>(this);
287 }
288
289 inline int StyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
290 {
291     if (is<MutableStyleProperties>(*this))
292         return downcast<MutableStyleProperties>(*this).findPropertyIndex(propertyID);
293     return downcast<ImmutableStyleProperties>(*this).findPropertyIndex(propertyID);
294 }
295
296 inline int StyleProperties::findCustomPropertyIndex(const String& propertyName) const
297 {
298     if (is<MutableStyleProperties>(*this))
299         return downcast<MutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
300     return downcast<ImmutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
301 }
302
303 } // namespace WebCore
304
305 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MutableStyleProperties)
306     static bool isType(const WebCore::StyleProperties& set) { return set.isMutable(); }
307 SPECIALIZE_TYPE_TRAITS_END()
308
309 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ImmutableStyleProperties)
310     static bool isType(const WebCore::StyleProperties& set) { return !set.isMutable(); }
311 SPECIALIZE_TYPE_TRAITS_END()
312
313 #endif // StyleProperties_h