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
34 namespace WebCore {
35
36 class CSSRule;
37 class CSSStyleDeclaration;
38 class Element;
39 class ImmutableStylePropertySet;
40 class KURL;
41 class MutableStylePropertySet;
42 class StylePropertyShorthand;
43 class StyleSheetContents;
44
45 class StylePropertySet : public RefCounted<StylePropertySet> {
46 friend class PropertyReference;
47 public:
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:
PropertyReference(const StylePropertySet & propertySet,unsigned index)54 PropertyReference(const StylePropertySet& propertySet, unsigned index)
55 : m_propertySet(propertySet)
56 , m_index(index)
57 {
58 }
59
id()60 CSSPropertyID id() const { return static_cast<CSSPropertyID>(propertyMetadata().m_propertyID); }
shorthandID()61 CSSPropertyID shorthandID() const { return propertyMetadata().shorthandID(); }
62
isImportant()63 bool isImportant() const { return propertyMetadata().m_important; }
isInherited()64 bool isInherited() const { return propertyMetadata().m_inherited; }
isImplicit()65 bool isImplicit() const { return propertyMetadata().m_implicit; }
66
67 String cssName() const;
68 String cssText() const;
69
value()70 const CSSValue* value() const { return propertyValue(); }
71 // FIXME: We should try to remove this mutable overload.
value()72 CSSValue* value() { return const_cast<CSSValue*>(propertyValue()); }
73
74 // FIXME: Remove this.
toCSSProperty()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;
propertyAt(unsigned index)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
cssParserMode()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
isMutable()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
127 protected:
128
129 enum { MaxArraySize = (1 << 28) - 1 };
130
StylePropertySet(CSSParserMode cssParserMode)131 StylePropertySet(CSSParserMode cssParserMode)
132 : m_cssParserMode(cssParserMode)
133 , m_isMutable(true)
134 , m_arraySize(0)
135 { }
136
StylePropertySet(CSSParserMode cssParserMode,unsigned immutableArraySize)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
150 class ImmutableStylePropertySet : public StylePropertySet {
151 public:
152 ~ImmutableStylePropertySet();
153 static PassRefPtr<ImmutableStylePropertySet> create(const CSSProperty* properties, unsigned count, CSSParserMode);
154
propertyCount()155 unsigned propertyCount() const { return m_arraySize; }
156
157 const CSSValue** valueArray() const;
158 const StylePropertyMetadata* metadataArray() const;
159
160 void* m_storage;
161
162 private:
163 ImmutableStylePropertySet(const CSSProperty*, unsigned count, CSSParserMode);
164 };
165
valueArray()166 inline const CSSValue** ImmutableStylePropertySet::valueArray() const
167 {
168 return reinterpret_cast<const CSSValue**>(const_cast<const void**>(&(this->m_storage)));
169 }
170
metadataArray()171 inline 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
176 DEFINE_TYPE_CASTS(ImmutableStylePropertySet, StylePropertySet, set, !set->isMutable(), !set.isMutable());
177
toImmutableStylePropertySet(const RefPtr<StylePropertySet> & set)178 inline ImmutableStylePropertySet* toImmutableStylePropertySet(const RefPtr<StylePropertySet>& set)
179 {
180 return toImmutableStylePropertySet(set.get());
181 }
182
183 class MutableStylePropertySet : public StylePropertySet {
184 public:
~MutableStylePropertySet()185 ~MutableStylePropertySet() { }
186 static PassRefPtr<MutableStylePropertySet> create(CSSParserMode = HTMLQuirksMode);
187 static PassRefPtr<MutableStylePropertySet> create(const CSSProperty* properties, unsigned count);
188
propertyCount()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
variablesIterator()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
228 private:
229 class VariablesIterator : public CSSVariablesIterator {
230 public:
~VariablesIterator()231 virtual ~VariablesIterator() { }
232 static PassRefPtr<VariablesIterator> create(MutableStylePropertySet*);
233 private:
VariablesIterator(MutableStylePropertySet * propertySet)234 explicit VariablesIterator(MutableStylePropertySet* propertySet) : m_propertySet(propertySet) { }
takeRemainingNames(Vector<AtomicString> & remainingNames)235 void takeRemainingNames(Vector<AtomicString>& remainingNames) { m_remainingNames.swap(remainingNames); }
236 virtual void advance() OVERRIDE;
atEnd()237 virtual bool atEnd() const OVERRIDE { return m_remainingNames.isEmpty(); }
name()238 virtual AtomicString name() const OVERRIDE { return m_remainingNames.last(); }
value()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
260 DEFINE_TYPE_CASTS(MutableStylePropertySet, StylePropertySet, set, set->isMutable(), set.isMutable());
261
toMutableStylePropertySet(const RefPtr<StylePropertySet> & set)262 inline MutableStylePropertySet* toMutableStylePropertySet(const RefPtr<StylePropertySet>& set)
263 {
264 return toMutableStylePropertySet(set.get());
265 }
266
propertyMetadata()267 inline 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
propertyValue()274 inline 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
propertyCount()281 inline unsigned StylePropertySet::propertyCount() const
282 {
283 if (m_isMutable)
284 return toMutableStylePropertySet(this)->m_propertyVector.size();
285 return m_arraySize;
286 }
287
isEmpty()288 inline bool StylePropertySet::isEmpty() const
289 {
290 return !propertyCount();
291 }
292
deref()293 inline 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