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#pragma once
23
24#include "CSSParserContext.h"
25#include "CSSParserTokenRange.h"
26#include "CSSProperty.h"
27#include "CSSValueKeywords.h"
28#include <memory>
29#include <wtf/Function.h>
30#include <wtf/TypeCasts.h>
31#include <wtf/Vector.h>
32#include <wtf/text/WTFString.h>
33
34namespace WebCore {
35
36class CSSDeferredParser;
37class CSSStyleDeclaration;
38class CachedResource;
39class Color;
40class ImmutableStyleProperties;
41class MutableStyleProperties;
42class PropertySetCSSStyleDeclaration;
43class StyledElement;
44class StylePropertyShorthand;
45class StyleSheetContents;
46
47enum StylePropertiesType { ImmutablePropertiesType, MutablePropertiesType, DeferredPropertiesType };
48
49class StylePropertiesBase : public RefCounted<StylePropertiesBase> {
50public:
51 // Override RefCounted's deref() to ensure operator delete is called on
52 // the appropriate subclass type.
53 void deref();
54
55 StylePropertiesType type() const { return static_cast<StylePropertiesType>(m_type); }
56
57 CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
58
59protected:
60 StylePropertiesBase(CSSParserMode cssParserMode, StylePropertiesType type)
61 : m_cssParserMode(cssParserMode)
62 , m_type(type)
63 , m_arraySize(0)
64 { }
65
66 StylePropertiesBase(CSSParserMode cssParserMode, unsigned immutableArraySize)
67 : m_cssParserMode(cssParserMode)
68 , m_type(ImmutablePropertiesType)
69 , m_arraySize(immutableArraySize)
70 { }
71
72 unsigned m_cssParserMode : 3;
73 mutable unsigned m_type : 2;
74 unsigned m_arraySize : 27;
75};
76
77class StyleProperties : public StylePropertiesBase {
78 friend class PropertyReference;
79public:
80 class PropertyReference {
81 public:
82 PropertyReference(const StylePropertyMetadata& metadata, const CSSValue* value)
83 : m_metadata(metadata)
84 , m_value(value)
85 { }
86
87 CSSPropertyID id() const { return static_cast<CSSPropertyID>(m_metadata.m_propertyID); }
88 CSSPropertyID shorthandID() const { return m_metadata.shorthandID(); }
89
90 bool isImportant() const { return m_metadata.m_important; }
91 bool isInherited() const { return m_metadata.m_inherited; }
92 bool isImplicit() const { return m_metadata.m_implicit; }
93
94 String cssName() const;
95 String cssText() const;
96
97 const CSSValue* value() const { return m_value; }
98 // FIXME: We should try to remove this mutable overload.
99 CSSValue* value() { return const_cast<CSSValue*>(m_value); }
100
101 // FIXME: Remove this.
102 CSSProperty toCSSProperty() const { return CSSProperty(id(), const_cast<CSSValue*>(m_value), isImportant(), m_metadata.m_isSetFromShorthand, m_metadata.m_indexInShorthandsVector, isImplicit()); }
103
104 private:
105 const StylePropertyMetadata& m_metadata;
106 const CSSValue* m_value;
107 };
108
109 unsigned propertyCount() const;
110 bool isEmpty() const { return !propertyCount(); }
111 PropertyReference propertyAt(unsigned) const;
112
113 WEBCORE_EXPORT RefPtr<CSSValue> getPropertyCSSValue(CSSPropertyID) const;
114 WEBCORE_EXPORT String getPropertyValue(CSSPropertyID) const;
115
116 WEBCORE_EXPORT Optional<Color> propertyAsColor(CSSPropertyID) const;
117 WEBCORE_EXPORT CSSValueID propertyAsValueID(CSSPropertyID) const;
118
119 bool propertyIsImportant(CSSPropertyID) const;
120 String getPropertyShorthand(CSSPropertyID) const;
121 bool isPropertyImplicit(CSSPropertyID) const;
122
123 RefPtr<CSSValue> getCustomPropertyCSSValue(const String& propertyName) const;
124 String getCustomPropertyValue(const String& propertyName) const;
125 bool customPropertyIsImportant(const String& propertyName) const;
126
127 Ref<MutableStyleProperties> copyBlockProperties() const;
128
129 WEBCORE_EXPORT Ref<MutableStyleProperties> mutableCopy() const;
130 Ref<ImmutableStyleProperties> immutableCopyIfNeeded() const;
131
132 Ref<MutableStyleProperties> copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const;
133
134 String asText() const;
135
136 bool hasCSSOMWrapper() const;
137 bool isMutable() const { return type() == MutablePropertiesType; }
138
139 bool traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const;
140
141 static unsigned averageSizeInBytes();
142
143#ifndef NDEBUG
144 void showStyle();
145#endif
146
147 bool propertyMatches(CSSPropertyID, const CSSValue*) const;
148
149protected:
150 StyleProperties(CSSParserMode cssParserMode, StylePropertiesType type)
151 : StylePropertiesBase(cssParserMode, type)
152 { }
153
154 StyleProperties(CSSParserMode cssParserMode, unsigned immutableArraySize)
155 : StylePropertiesBase(cssParserMode, immutableArraySize)
156 { }
157
158 int findPropertyIndex(CSSPropertyID) const;
159 int findCustomPropertyIndex(const String& propertyName) const;
160
161private:
162 String getShorthandValue(const StylePropertyShorthand&) const;
163 String getCommonValue(const StylePropertyShorthand&) const;
164 String getAlignmentShorthandValue(const StylePropertyShorthand&) const;
165 String borderPropertyValue(const StylePropertyShorthand&, const StylePropertyShorthand&, const StylePropertyShorthand&) const;
166 String pageBreakPropertyValue(const StylePropertyShorthand&) const;
167 String getLayeredShorthandValue(const StylePropertyShorthand&) const;
168 String get2Values(const StylePropertyShorthand&) const;
169 String get4Values(const StylePropertyShorthand&) const;
170 String borderSpacingValue(const StylePropertyShorthand&) const;
171 String fontValue() const;
172 void appendFontLonghandValueIfExplicit(CSSPropertyID, StringBuilder& result, String& value) const;
173
174 RefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) const;
175
176 friend class PropertySetCSSStyleDeclaration;
177};
178
179class ImmutableStyleProperties final : public StyleProperties {
180public:
181 WEBCORE_EXPORT ~ImmutableStyleProperties();
182 static Ref<ImmutableStyleProperties> create(const CSSProperty* properties, unsigned count, CSSParserMode);
183
184 unsigned propertyCount() const { return m_arraySize; }
185 bool isEmpty() const { return !propertyCount(); }
186 PropertyReference propertyAt(unsigned index) const;
187
188 const CSSValue** valueArray() const;
189 const StylePropertyMetadata* metadataArray() const;
190 int findPropertyIndex(CSSPropertyID) const;
191 int findCustomPropertyIndex(const String& propertyName) const;
192
193 void* m_storage;
194
195private:
196 ImmutableStyleProperties(const CSSProperty*, unsigned count, CSSParserMode);
197};
198
199inline const CSSValue** ImmutableStyleProperties::valueArray() const
200{
201 return reinterpret_cast<const CSSValue**>(const_cast<const void**>((&(this->m_storage))));
202}
203
204inline const StylePropertyMetadata* ImmutableStyleProperties::metadataArray() const
205{
206 return reinterpret_cast_ptr<const StylePropertyMetadata*>(&reinterpret_cast_ptr<const char*>(&(this->m_storage))[m_arraySize * sizeof(CSSValue*)]);
207}
208
209class MutableStyleProperties final : public StyleProperties {
210public:
211 WEBCORE_EXPORT static Ref<MutableStyleProperties> create(CSSParserMode = HTMLQuirksMode);
212 static Ref<MutableStyleProperties> create(const CSSProperty* properties, unsigned count);
213
214 WEBCORE_EXPORT ~MutableStyleProperties();
215
216 unsigned propertyCount() const { return m_propertyVector.size(); }
217 bool isEmpty() const { return !propertyCount(); }
218 PropertyReference propertyAt(unsigned index) const;
219
220 PropertySetCSSStyleDeclaration* cssStyleDeclaration();
221
222 bool addParsedProperties(const ParsedPropertyVector&);
223 bool addParsedProperty(const CSSProperty&);
224
225 // These expand shorthand properties into multiple properties.
226 bool setProperty(CSSPropertyID, const String& value, bool important, CSSParserContext);
227 bool setProperty(CSSPropertyID, const String& value, bool important = false);
228 void setProperty(CSSPropertyID, RefPtr<CSSValue>&&, bool important = false);
229
230 // These do not. FIXME: This is too messy, we can do better.
231 bool setProperty(CSSPropertyID, CSSValueID identifier, bool important = false);
232 bool setProperty(CSSPropertyID, CSSPropertyID identifier, bool important = false);
233 bool setProperty(const CSSProperty&, CSSProperty* slot = nullptr);
234
235 bool removeProperty(CSSPropertyID, String* returnText = nullptr);
236 void removeBlockProperties();
237 bool removePropertiesInSet(const CSSPropertyID* set, unsigned length);
238
239 void mergeAndOverrideOnConflict(const StyleProperties&);
240
241 void clear();
242 bool parseDeclaration(const String& styleDeclaration, CSSParserContext);
243
244 WEBCORE_EXPORT CSSStyleDeclaration& ensureCSSStyleDeclaration();
245 CSSStyleDeclaration& ensureInlineCSSStyleDeclaration(StyledElement& parentElement);
246
247 int findPropertyIndex(CSSPropertyID) const;
248 int findCustomPropertyIndex(const String& propertyName) const;
249
250 Vector<CSSProperty, 4> m_propertyVector;
251
252 // Methods for querying and altering CSS custom properties.
253 bool setCustomProperty(const Document*, const String& propertyName, const String& value, bool important, CSSParserContext);
254 bool removeCustomProperty(const String& propertyName, String* returnText = nullptr);
255
256private:
257 explicit MutableStyleProperties(CSSParserMode);
258 explicit MutableStyleProperties(const StyleProperties&);
259 MutableStyleProperties(const CSSProperty* properties, unsigned count);
260
261 bool removeShorthandProperty(CSSPropertyID);
262 CSSProperty* findCSSPropertyWithID(CSSPropertyID);
263 CSSProperty* findCustomCSSPropertyWithName(const String&);
264 std::unique_ptr<PropertySetCSSStyleDeclaration> m_cssomWrapper;
265
266 friend class StyleProperties;
267};
268
269class DeferredStyleProperties final : public StylePropertiesBase {
270public:
271 WEBCORE_EXPORT ~DeferredStyleProperties();
272 static Ref<DeferredStyleProperties> create(const CSSParserTokenRange&, CSSDeferredParser&);
273
274 Ref<ImmutableStyleProperties> parseDeferredProperties();
275
276private:
277 DeferredStyleProperties(const CSSParserTokenRange&, CSSDeferredParser&);
278
279 Vector<CSSParserToken> m_tokens;
280 Ref<CSSDeferredParser> m_parser;
281};
282
283inline ImmutableStyleProperties::PropertyReference ImmutableStyleProperties::propertyAt(unsigned index) const
284{
285 return PropertyReference(metadataArray()[index], valueArray()[index]);
286}
287
288inline MutableStyleProperties::PropertyReference MutableStyleProperties::propertyAt(unsigned index) const
289{
290 const CSSProperty& property = m_propertyVector[index];
291 return PropertyReference(property.metadata(), property.value());
292}
293
294inline StyleProperties::PropertyReference StyleProperties::propertyAt(unsigned index) const
295{
296 if (is<MutableStyleProperties>(*this))
297 return downcast<MutableStyleProperties>(*this).propertyAt(index);
298 return downcast<ImmutableStyleProperties>(*this).propertyAt(index);
299}
300
301inline unsigned StyleProperties::propertyCount() const
302{
303 if (is<MutableStyleProperties>(*this))
304 return downcast<MutableStyleProperties>(*this).propertyCount();
305 return downcast<ImmutableStyleProperties>(*this).propertyCount();
306}
307
308inline void StylePropertiesBase::deref()
309{
310 if (!derefBase())
311 return;
312
313 if (is<MutableStyleProperties>(*this))
314 delete downcast<MutableStyleProperties>(this);
315 else if (is<ImmutableStyleProperties>(*this))
316 delete downcast<ImmutableStyleProperties>(this);
317 else
318 delete downcast<DeferredStyleProperties>(this);
319}
320
321inline int StyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
322{
323 if (is<MutableStyleProperties>(*this))
324 return downcast<MutableStyleProperties>(*this).findPropertyIndex(propertyID);
325 return downcast<ImmutableStyleProperties>(*this).findPropertyIndex(propertyID);
326}
327
328inline int StyleProperties::findCustomPropertyIndex(const String& propertyName) const
329{
330 if (is<MutableStyleProperties>(*this))
331 return downcast<MutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
332 return downcast<ImmutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
333}
334
335} // namespace WebCore
336
337SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::StyleProperties)
338 static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() != WebCore::DeferredPropertiesType; }
339SPECIALIZE_TYPE_TRAITS_END()
340
341SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MutableStyleProperties)
342 static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::MutablePropertiesType; }
343SPECIALIZE_TYPE_TRAITS_END()
344
345SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ImmutableStyleProperties)
346 static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::ImmutablePropertiesType; }
347SPECIALIZE_TYPE_TRAITS_END()
348
349SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::DeferredStyleProperties)
350 static bool isType(const WebCore::StylePropertiesBase& set) { return set.type() == WebCore::DeferredPropertiesType; }
351SPECIALIZE_TYPE_TRAITS_END()
352