Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
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/. */
6 /*
7 * representation of a declaration block (or style attribute) in a CSS
8 * stylesheet
9 */
11 #ifndef mozilla_css_Declaration_h
12 #define mozilla_css_Declaration_h
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
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>
30 namespace mozilla {
31 namespace css {
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|.
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();
50 Declaration(const Declaration& aCopy);
52 ~Declaration();
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);
61 void RemoveProperty(nsCSSProperty aProperty);
63 bool HasProperty(nsCSSProperty aProperty) const;
65 void GetValue(nsCSSProperty aProperty, nsAString& aValue) const;
66 void GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const;
68 bool HasImportantData() const {
69 return mImportantData || mImportantVariables;
70 }
71 bool GetValueIsImportant(nsCSSProperty aProperty) const;
72 bool GetValueIsImportant(const nsAString& aProperty) const;
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);
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);
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;
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;
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;
123 uint32_t Count() const {
124 return mOrder.Length();
125 }
127 // Returns whether we actually had a property at aIndex
128 bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
130 void ToString(nsAString& aString) const;
132 nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
133 nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
135 /**
136 * Initialize this declaration as holding no data. Cannot fail.
137 */
138 void InitializeEmpty();
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 }
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();
164 NS_ABORT_IF_FALSE(mData, "oops");
165 aExpandedData->Expand(mData.forget(), mImportantData.forget());
166 }
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 }
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");
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 }
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 }
230 bool HasNonImportantValueFor(nsCSSProperty aProperty) const {
231 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
232 return !!mData->ValueFor(aProperty);
233 }
235 /**
236 * Return whether |this| may be modified.
237 */
238 bool IsMutable() const {
239 return !mImmutable;
240 }
242 /**
243 * Copy |this|, if necessary to ensure that it can be modified.
244 */
245 Declaration* EnsureMutable();
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 }
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; }
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 }
274 #ifdef DEBUG
275 void List(FILE* out = stdout, int32_t aIndent = 0) const;
276 #endif
278 private:
279 Declaration& operator=(const Declaration& aCopy) MOZ_DELETE;
280 bool operator==(const Declaration& aCopy) const MOZ_DELETE;
282 void GetValue(nsCSSProperty aProperty, nsAString& aValue,
283 nsCSSValue::Serialization aValueSerialization) const;
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;
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 }
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 }
325 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
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;
337 // variable names of custom properties found in mOrder
338 nsTArray<nsString> mVariableOrder;
340 // never null, except while expanded, or before the first call to
341 // InitializeEmpty or CompressFrom.
342 nsAutoPtr<nsCSSCompressedDataBlock> mData;
344 // may be null
345 nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
347 // may be null
348 nsAutoPtr<CSSVariableDeclarations> mVariables;
350 // may be null
351 nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
353 // set by style rules when |RuleMatched| is called;
354 // also by ToString (hence the 'mutable').
355 mutable bool mImmutable;
356 };
358 } // namespace css
359 } // namespace mozilla
361 #endif /* mozilla_css_Declaration_h */