|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * representation of a declaration block (or style attribute) in a CSS |
|
8 * stylesheet |
|
9 */ |
|
10 |
|
11 #ifndef mozilla_css_Declaration_h |
|
12 #define mozilla_css_Declaration_h |
|
13 |
|
14 // This header is in EXPORTS because it's used in several places in content/, |
|
15 // but it's not really a public interface. |
|
16 #ifndef MOZILLA_INTERNAL_API |
|
17 #error "This file should only be included within libxul" |
|
18 #endif |
|
19 |
|
20 #include "mozilla/Attributes.h" |
|
21 #include "mozilla/MemoryReporting.h" |
|
22 #include "CSSVariableDeclarations.h" |
|
23 #include "nsCSSDataBlock.h" |
|
24 #include "nsCSSProperty.h" |
|
25 #include "nsCSSProps.h" |
|
26 #include "nsStringFwd.h" |
|
27 #include "nsTArray.h" |
|
28 #include <stdio.h> |
|
29 |
|
30 namespace mozilla { |
|
31 namespace css { |
|
32 |
|
33 // Declaration objects have unusual lifetime rules. Every declaration |
|
34 // begins life in an invalid state which ends when InitializeEmpty or |
|
35 // CompressFrom is called upon it. After that, it can be attached to |
|
36 // exactly one style rule, and will be destroyed when that style rule |
|
37 // is destroyed. A declaration becomes immutable when its style rule's |
|
38 // |RuleMatched| method is called; after that, it must be copied before |
|
39 // it can be modified, which is taken care of by |EnsureMutable|. |
|
40 |
|
41 class Declaration { |
|
42 public: |
|
43 /** |
|
44 * Construct an |Declaration| that is in an invalid state (null |
|
45 * |mData|) and cannot be used until its |CompressFrom| method or |
|
46 * |InitializeEmpty| method is called. |
|
47 */ |
|
48 Declaration(); |
|
49 |
|
50 Declaration(const Declaration& aCopy); |
|
51 |
|
52 ~Declaration(); |
|
53 |
|
54 /** |
|
55 * |ValueAppended| must be called to maintain this declaration's |
|
56 * |mOrder| whenever a property is parsed into an expanded data block |
|
57 * for this declaration. aProperty must not be a shorthand. |
|
58 */ |
|
59 void ValueAppended(nsCSSProperty aProperty); |
|
60 |
|
61 void RemoveProperty(nsCSSProperty aProperty); |
|
62 |
|
63 bool HasProperty(nsCSSProperty aProperty) const; |
|
64 |
|
65 void GetValue(nsCSSProperty aProperty, nsAString& aValue) const; |
|
66 void GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const; |
|
67 |
|
68 bool HasImportantData() const { |
|
69 return mImportantData || mImportantVariables; |
|
70 } |
|
71 bool GetValueIsImportant(nsCSSProperty aProperty) const; |
|
72 bool GetValueIsImportant(const nsAString& aProperty) const; |
|
73 |
|
74 /** |
|
75 * Adds a custom property declaration to this object. |
|
76 * |
|
77 * @param aName The variable name (i.e., without the "--" prefix). |
|
78 * @param aType The type of value the variable has. |
|
79 * @param aValue The value of the variable, if aType is |
|
80 * CSSVariableDeclarations::eTokenStream. |
|
81 * @param aIsImportant Whether the declaration is !important. |
|
82 * @param aOverrideImportant When aIsImportant is false, whether an |
|
83 * existing !important declaration will be overridden. |
|
84 */ |
|
85 void AddVariableDeclaration(const nsAString& aName, |
|
86 CSSVariableDeclarations::Type aType, |
|
87 const nsString& aValue, |
|
88 bool aIsImportant, |
|
89 bool aOverrideImportant); |
|
90 |
|
91 /** |
|
92 * Removes a custom property declaration from this object. |
|
93 * |
|
94 * @param aName The variable name (i.e., without the "--" prefix). |
|
95 */ |
|
96 void RemoveVariableDeclaration(const nsAString& aName); |
|
97 |
|
98 /** |
|
99 * Returns whether a custom property declaration for a variable with |
|
100 * a given name exists on this object. |
|
101 * |
|
102 * @param aName The variable name (i.e., without the "--" prefix). |
|
103 */ |
|
104 bool HasVariableDeclaration(const nsAString& aName) const; |
|
105 |
|
106 /** |
|
107 * Gets the string value for a custom property declaration of a variable |
|
108 * with a given name. |
|
109 * |
|
110 * @param aName The variable name (i.e., without the "--" prefix). |
|
111 * @param aValue Out parameter into which the variable's value will be |
|
112 * stored. If the value is 'initial' or 'inherit', that exact string |
|
113 * will be stored in aValue. |
|
114 */ |
|
115 void GetVariableDeclaration(const nsAString& aName, nsAString& aValue) const; |
|
116 |
|
117 /** |
|
118 * Returns whether the custom property declaration for a variable with |
|
119 * the given name was !important. |
|
120 */ |
|
121 bool GetVariableValueIsImportant(const nsAString& aName) const; |
|
122 |
|
123 uint32_t Count() const { |
|
124 return mOrder.Length(); |
|
125 } |
|
126 |
|
127 // Returns whether we actually had a property at aIndex |
|
128 bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const; |
|
129 |
|
130 void ToString(nsAString& aString) const; |
|
131 |
|
132 nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; } |
|
133 nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; } |
|
134 |
|
135 /** |
|
136 * Initialize this declaration as holding no data. Cannot fail. |
|
137 */ |
|
138 void InitializeEmpty(); |
|
139 |
|
140 /** |
|
141 * Transfer all of the state from |aExpandedData| into this declaration. |
|
142 * After calling, |aExpandedData| should be in its initial state. |
|
143 * Callers must make sure mOrder is updated as necessary. |
|
144 */ |
|
145 void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) { |
|
146 NS_ABORT_IF_FALSE(!mData, "oops"); |
|
147 NS_ABORT_IF_FALSE(!mImportantData, "oops"); |
|
148 aExpandedData->Compress(getter_Transfers(mData), |
|
149 getter_Transfers(mImportantData)); |
|
150 aExpandedData->AssertInitialState(); |
|
151 } |
|
152 |
|
153 /** |
|
154 * Transfer all of the state from this declaration into |
|
155 * |aExpandedData| and put this declaration temporarily into an |
|
156 * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that |
|
157 * should last only during parsing. During this time only |
|
158 * |ValueAppended| should be called. |
|
159 */ |
|
160 void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) { |
|
161 AssertMutable(); |
|
162 aExpandedData->AssertInitialState(); |
|
163 |
|
164 NS_ABORT_IF_FALSE(mData, "oops"); |
|
165 aExpandedData->Expand(mData.forget(), mImportantData.forget()); |
|
166 } |
|
167 |
|
168 /** |
|
169 * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style |
|
170 * rule using this declaration for storage. |
|
171 */ |
|
172 void MapNormalRuleInfoInto(nsRuleData *aRuleData) const { |
|
173 NS_ABORT_IF_FALSE(mData, "called while expanded"); |
|
174 mData->MapRuleInfoInto(aRuleData); |
|
175 if (mVariables) { |
|
176 mVariables->MapRuleInfoInto(aRuleData); |
|
177 } |
|
178 } |
|
179 void MapImportantRuleInfoInto(nsRuleData *aRuleData) const { |
|
180 NS_ABORT_IF_FALSE(mData, "called while expanded"); |
|
181 NS_ABORT_IF_FALSE(mImportantData || mImportantVariables, |
|
182 "must have important data or variables"); |
|
183 if (mImportantData) { |
|
184 mImportantData->MapRuleInfoInto(aRuleData); |
|
185 } |
|
186 if (mImportantVariables) { |
|
187 mImportantVariables->MapRuleInfoInto(aRuleData); |
|
188 } |
|
189 } |
|
190 |
|
191 /** |
|
192 * Attempt to replace the value for |aProperty| stored in this |
|
193 * declaration with the matching value from |aFromBlock|. |
|
194 * This method may only be called on a mutable declaration. |
|
195 * It will fail (returning false) if |aProperty| is shorthand, |
|
196 * is not already in this declaration, or does not have the indicated |
|
197 * importance level. If it returns true, it erases the value in |
|
198 * |aFromBlock|. |aChanged| is set to true if the declaration |
|
199 * changed as a result of the call, and to false otherwise. |
|
200 */ |
|
201 bool TryReplaceValue(nsCSSProperty aProperty, bool aIsImportant, |
|
202 nsCSSExpandedDataBlock& aFromBlock, |
|
203 bool* aChanged) |
|
204 { |
|
205 AssertMutable(); |
|
206 NS_ABORT_IF_FALSE(mData, "called while expanded"); |
|
207 |
|
208 if (nsCSSProps::IsShorthand(aProperty)) { |
|
209 *aChanged = false; |
|
210 return false; |
|
211 } |
|
212 nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData; |
|
213 // mImportantData might be null |
|
214 if (!block) { |
|
215 *aChanged = false; |
|
216 return false; |
|
217 } |
|
218 |
|
219 #ifdef DEBUG |
|
220 { |
|
221 nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData; |
|
222 NS_ABORT_IF_FALSE(!other || !other->ValueFor(aProperty) || |
|
223 !block->ValueFor(aProperty), |
|
224 "Property both important and not?"); |
|
225 } |
|
226 #endif |
|
227 return block->TryReplaceValue(aProperty, aFromBlock, aChanged); |
|
228 } |
|
229 |
|
230 bool HasNonImportantValueFor(nsCSSProperty aProperty) const { |
|
231 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), "must be longhand"); |
|
232 return !!mData->ValueFor(aProperty); |
|
233 } |
|
234 |
|
235 /** |
|
236 * Return whether |this| may be modified. |
|
237 */ |
|
238 bool IsMutable() const { |
|
239 return !mImmutable; |
|
240 } |
|
241 |
|
242 /** |
|
243 * Copy |this|, if necessary to ensure that it can be modified. |
|
244 */ |
|
245 Declaration* EnsureMutable(); |
|
246 |
|
247 /** |
|
248 * Crash if |this| cannot be modified. |
|
249 */ |
|
250 void AssertMutable() const { |
|
251 NS_ABORT_IF_FALSE(IsMutable(), "someone forgot to call EnsureMutable"); |
|
252 } |
|
253 |
|
254 /** |
|
255 * Mark this declaration as unmodifiable. It's 'const' so it can |
|
256 * be called from ToString. |
|
257 */ |
|
258 void SetImmutable() const { mImmutable = true; } |
|
259 |
|
260 /** |
|
261 * Clear the data, in preparation for its replacement with entirely |
|
262 * new data by a call to |CompressFrom|. |
|
263 */ |
|
264 void ClearData() { |
|
265 AssertMutable(); |
|
266 mData = nullptr; |
|
267 mImportantData = nullptr; |
|
268 mVariables = nullptr; |
|
269 mImportantVariables = nullptr; |
|
270 mOrder.Clear(); |
|
271 mVariableOrder.Clear(); |
|
272 } |
|
273 |
|
274 #ifdef DEBUG |
|
275 void List(FILE* out = stdout, int32_t aIndent = 0) const; |
|
276 #endif |
|
277 |
|
278 private: |
|
279 Declaration& operator=(const Declaration& aCopy) MOZ_DELETE; |
|
280 bool operator==(const Declaration& aCopy) const MOZ_DELETE; |
|
281 |
|
282 void GetValue(nsCSSProperty aProperty, nsAString& aValue, |
|
283 nsCSSValue::Serialization aValueSerialization) const; |
|
284 |
|
285 static void AppendImportanceToString(bool aIsImportant, nsAString& aString); |
|
286 // return whether there was a value in |aValue| (i.e., it had a non-null unit) |
|
287 bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const; |
|
288 bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult, |
|
289 nsCSSValue::Serialization aValueSerialization) const; |
|
290 // Helper for ToString with strange semantics regarding aValue. |
|
291 void AppendPropertyAndValueToString(nsCSSProperty aProperty, |
|
292 nsAutoString& aValue, |
|
293 nsAString& aResult) const; |
|
294 // helper for ToString that serializes a custom property declaration for |
|
295 // a variable with the specified name |
|
296 void AppendVariableAndValueToString(const nsAString& aName, |
|
297 nsAString& aResult) const; |
|
298 |
|
299 public: |
|
300 /** |
|
301 * Returns the property at the given index in the ordered list of |
|
302 * declarations. For custom properties, eCSSPropertyExtra_variable |
|
303 * is returned. |
|
304 */ |
|
305 nsCSSProperty GetPropertyAt(uint32_t aIndex) const { |
|
306 uint32_t value = mOrder[aIndex]; |
|
307 if (value >= eCSSProperty_COUNT) { |
|
308 return eCSSPropertyExtra_variable; |
|
309 } |
|
310 return nsCSSProperty(value); |
|
311 } |
|
312 |
|
313 /** |
|
314 * Gets the name of the custom property at the given index in the ordered |
|
315 * list of declarations. |
|
316 */ |
|
317 void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { |
|
318 MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); |
|
319 uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT; |
|
320 aResult.Truncate(); |
|
321 aResult.AppendLiteral("--"); |
|
322 aResult.Append(mVariableOrder[variableIndex]); |
|
323 } |
|
324 |
|
325 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
326 |
|
327 private: |
|
328 // The order of properties in this declaration. Longhand properties are |
|
329 // represented by their nsCSSProperty value, and each custom property (--*) |
|
330 // is represented by a value that begins at eCSSProperty_COUNT. |
|
331 // |
|
332 // Subtracting eCSSProperty_COUNT from those values that represent custom |
|
333 // properties results in an index into mVariableOrder, which identifies the |
|
334 // specific variable the custom property declaration is for. |
|
335 nsAutoTArray<uint32_t, 8> mOrder; |
|
336 |
|
337 // variable names of custom properties found in mOrder |
|
338 nsTArray<nsString> mVariableOrder; |
|
339 |
|
340 // never null, except while expanded, or before the first call to |
|
341 // InitializeEmpty or CompressFrom. |
|
342 nsAutoPtr<nsCSSCompressedDataBlock> mData; |
|
343 |
|
344 // may be null |
|
345 nsAutoPtr<nsCSSCompressedDataBlock> mImportantData; |
|
346 |
|
347 // may be null |
|
348 nsAutoPtr<CSSVariableDeclarations> mVariables; |
|
349 |
|
350 // may be null |
|
351 nsAutoPtr<CSSVariableDeclarations> mImportantVariables; |
|
352 |
|
353 // set by style rules when |RuleMatched| is called; |
|
354 // also by ToString (hence the 'mutable'). |
|
355 mutable bool mImmutable; |
|
356 }; |
|
357 |
|
358 } // namespace css |
|
359 } // namespace mozilla |
|
360 |
|
361 #endif /* mozilla_css_Declaration_h */ |