Line data Source 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/. */
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/DeclarationBlock.h"
22 : #include "mozilla/MemoryReporting.h"
23 : #include "CSSVariableDeclarations.h"
24 : #include "nsCSSDataBlock.h"
25 : #include "nsCSSPropertyID.h"
26 : #include "nsCSSProps.h"
27 : #include "nsIStyleRule.h"
28 : #include "nsStringFwd.h"
29 : #include "nsTArray.h"
30 : #include <stdio.h>
31 :
32 : // feec07b8-3fe6-491e-90d5-cc93f853e048
33 : #define NS_CSS_DECLARATION_IMPL_CID \
34 : { 0xfeec07b8, 0x3fe6, 0x491e, \
35 : { 0x90, 0xd5, 0xcc, 0x93, 0xf8, 0x53, 0xe0, 0x48 } }
36 :
37 : class nsHTMLCSSStyleSheet;
38 :
39 : namespace mozilla {
40 : namespace css {
41 :
42 : class Rule;
43 : class Declaration;
44 :
45 : /**
46 : * ImportantStyleData is the implementation of nsIStyleRule (a source of
47 : * style data) representing the style data coming from !important rules;
48 : * the !important declarations need a separate nsIStyleRule object since
49 : * they fit at a different point in the cascade.
50 : *
51 : * ImportantStyleData is allocated only as part of a Declaration object.
52 : */
53 : class ImportantStyleData final : public nsIStyleRule
54 : {
55 : public:
56 :
57 : NS_DECL_ISUPPORTS
58 :
59 : inline ::mozilla::css::Declaration* Declaration();
60 :
61 : // nsIStyleRule interface
62 : virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
63 : virtual bool MightMapInheritedStyleData() override;
64 : virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
65 : nsCSSValue* aValue) override;
66 : #ifdef DEBUG
67 : virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
68 : #endif
69 :
70 : private:
71 3101 : ImportantStyleData() {}
72 25 : ~ImportantStyleData() {}
73 :
74 : friend class ::mozilla::css::Declaration;
75 : };
76 :
77 : // Declaration objects have unusual lifetime rules. Every declaration
78 : // begins life in an invalid state which ends when InitializeEmpty or
79 : // CompressFrom is called upon it. After that, it can be attached to
80 : // exactly one style rule, and will be destroyed when that style rule
81 : // is destroyed. A declaration becomes immutable (via a SetImmutable
82 : // call) when it is matched (put in the rule tree); after that, it must
83 : // be copied before it can be modified, which is taken care of by
84 : // |EnsureMutable|.
85 :
86 : class Declaration final : public DeclarationBlock
87 : , public nsIStyleRule
88 : {
89 : public:
90 : /**
91 : * Construct an |Declaration| that is in an invalid state (null
92 : * |mData|) and cannot be used until its |CompressFrom| method or
93 : * |InitializeEmpty| method is called.
94 : */
95 3086 : Declaration() : DeclarationBlock(StyleBackendType::Gecko) {}
96 :
97 : Declaration(const Declaration& aCopy);
98 :
99 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_DECLARATION_IMPL_CID)
100 :
101 : // If this ever becomes cycle-collected, please change the CC implementation
102 : // for StyleRule to traverse it.
103 : NS_DECL_ISUPPORTS
104 :
105 : private:
106 : ~Declaration();
107 :
108 : public:
109 :
110 : // nsIStyleRule implementation
111 : virtual void MapRuleInfoInto(nsRuleData *aRuleData) override;
112 : virtual bool MightMapInheritedStyleData() override;
113 : virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
114 : nsCSSValue* aValue) override;
115 : #ifdef DEBUG
116 : virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
117 : #endif
118 :
119 : /**
120 : * |ValueAppended| must be called to maintain this declaration's
121 : * |mOrder| whenever a property is parsed into an expanded data block
122 : * for this declaration. aProperty must not be a shorthand.
123 : */
124 : void ValueAppended(nsCSSPropertyID aProperty);
125 :
126 : void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const;
127 : void GetPropertyValueByID(nsCSSPropertyID aPropID, nsAString& aValue) const;
128 : void GetAuthoredPropertyValue(const nsAString& aProperty,
129 : nsAString& aValue) const;
130 : bool GetPropertyIsImportant(const nsAString& aProperty) const;
131 : void RemoveProperty(const nsAString& aProperty);
132 : void RemovePropertyByID(nsCSSPropertyID aProperty);
133 :
134 : bool HasProperty(nsCSSPropertyID aProperty) const;
135 :
136 20975 : bool HasImportantData() const {
137 20975 : return mImportantData || mImportantVariables;
138 : }
139 :
140 : /**
141 : * Adds a custom property declaration to this object.
142 : *
143 : * @param aName The variable name (i.e., without the "--" prefix).
144 : * @param aType The type of value the variable has.
145 : * @param aValue The value of the variable, if aType is
146 : * CSSVariableDeclarations::eTokenStream.
147 : * @param aIsImportant Whether the declaration is !important.
148 : * @param aOverrideImportant When aIsImportant is false, whether an
149 : * existing !important declaration will be overridden.
150 : */
151 : void AddVariable(const nsAString& aName,
152 : CSSVariableDeclarations::Type aType,
153 : const nsString& aValue,
154 : bool aIsImportant,
155 : bool aOverrideImportant);
156 :
157 : /**
158 : * Removes a custom property declaration from this object.
159 : *
160 : * @param aName The variable name (i.e., without the "--" prefix).
161 : */
162 : void RemoveVariable(const nsAString& aName);
163 :
164 : /**
165 : * Gets the string value for a custom property declaration of a variable
166 : * with a given name.
167 : *
168 : * @param aName The variable name (i.e., without the "--" prefix).
169 : * @param aValue Out parameter into which the variable's value will be
170 : * stored. If the value is 'initial' or 'inherit', that exact string
171 : * will be stored in aValue.
172 : */
173 : void GetVariableValue(const nsAString& aName, nsAString& aValue) const;
174 :
175 : /**
176 : * Returns whether the custom property declaration for a variable with
177 : * the given name was !important.
178 : */
179 : bool GetVariableIsImportant(const nsAString& aName) const;
180 :
181 0 : uint32_t Count() const {
182 0 : return mOrder.Length();
183 : }
184 :
185 : // Returns whether we actually had a property at aIndex
186 : bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
187 :
188 : void ToString(nsAString& aString) const;
189 :
190 0 : nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
191 0 : nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
192 :
193 2572 : void AssertNotExpanded() const {
194 2572 : MOZ_ASSERT(mData, "should only be called when not expanded");
195 2572 : }
196 :
197 : /**
198 : * Initialize this declaration as holding no data. Cannot fail.
199 : */
200 : void InitializeEmpty();
201 :
202 : /**
203 : * Transfer all of the state from |aExpandedData| into this declaration.
204 : * After calling, |aExpandedData| should be in its initial state.
205 : * Callers must make sure mOrder is updated as necessary.
206 : */
207 3118 : void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
208 3118 : MOZ_ASSERT(!mData, "oops");
209 3118 : MOZ_ASSERT(!mImportantData, "oops");
210 9354 : aExpandedData->Compress(getter_Transfers(mData),
211 6236 : getter_Transfers(mImportantData),
212 3118 : mOrder);
213 3118 : aExpandedData->AssertInitialState();
214 3118 : }
215 :
216 : /**
217 : * Transfer all of the state from this declaration into
218 : * |aExpandedData| and put this declaration temporarily into an
219 : * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
220 : * should last only during parsing. During this time only
221 : * |ValueAppended| should be called.
222 : */
223 116 : void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) {
224 116 : AssertMutable();
225 116 : aExpandedData->AssertInitialState();
226 :
227 116 : MOZ_ASSERT(mData, "oops");
228 116 : aExpandedData->Expand(mData.forget(), mImportantData.forget());
229 116 : }
230 :
231 2460 : void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
232 2460 : AssertNotExpanded();
233 2460 : MOZ_ASSERT(mImportantData || mImportantVariables,
234 : "must have important data or variables");
235 2460 : if (mImportantData) {
236 2460 : mImportantData->MapRuleInfoInto(aRuleData);
237 : }
238 2460 : if (mImportantVariables) {
239 0 : mImportantVariables->MapRuleInfoInto(aRuleData);
240 : }
241 2460 : }
242 :
243 : bool MapsImportantInheritedStyleData() const;
244 :
245 : /**
246 : * Attempt to replace the value for |aProperty| stored in this
247 : * declaration with the matching value from |aFromBlock|.
248 : * This method may only be called on a mutable declaration.
249 : * It will fail (returning false) if |aProperty| is shorthand,
250 : * is not already in this declaration, or does not have the indicated
251 : * importance level. If it returns true, it erases the value in
252 : * |aFromBlock|. |aChanged| is set to true if the declaration
253 : * changed as a result of the call, and to false otherwise.
254 : */
255 103 : bool TryReplaceValue(nsCSSPropertyID aProperty, bool aIsImportant,
256 : nsCSSExpandedDataBlock& aFromBlock,
257 : bool* aChanged)
258 : {
259 103 : AssertMutable();
260 103 : AssertNotExpanded();
261 :
262 103 : if (nsCSSProps::IsShorthand(aProperty)) {
263 1 : *aChanged = false;
264 1 : return false;
265 : }
266 102 : nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
267 : // mImportantData might be null
268 102 : if (!block) {
269 0 : *aChanged = false;
270 0 : return false;
271 : }
272 :
273 : #ifdef DEBUG
274 : {
275 102 : nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData;
276 102 : MOZ_ASSERT(!other || !other->ValueFor(aProperty) ||
277 : !block->ValueFor(aProperty),
278 : "Property both important and not?");
279 : }
280 : #endif
281 102 : return block->TryReplaceValue(aProperty, aFromBlock, aChanged);
282 : }
283 :
284 0 : bool HasNonImportantValueFor(nsCSSPropertyID aProperty) const {
285 0 : MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
286 0 : return !!mData->ValueFor(aProperty);
287 : }
288 :
289 : /**
290 : * Clear the data, in preparation for its replacement with entirely
291 : * new data by a call to |CompressFrom|.
292 : */
293 0 : void ClearData() {
294 0 : AssertMutable();
295 0 : mData = nullptr;
296 0 : mImportantData = nullptr;
297 0 : mVariables = nullptr;
298 0 : mImportantVariables = nullptr;
299 0 : mOrder.Clear();
300 0 : mVariableOrder.Clear();
301 0 : }
302 :
303 10691 : ImportantStyleData* GetImportantStyleData() {
304 10691 : if (HasImportantData()) {
305 524 : return &mImportantStyleData;
306 : }
307 10167 : return nullptr;
308 : }
309 :
310 : private:
311 : Declaration& operator=(const Declaration& aCopy) = delete;
312 : bool operator==(const Declaration& aCopy) const = delete;
313 :
314 : void GetPropertyValueInternal(nsCSSPropertyID aProperty, nsAString& aValue,
315 : nsCSSValue::Serialization aValueSerialization,
316 : bool* aIsTokenStream = nullptr) const;
317 : bool GetPropertyIsImportantByID(nsCSSPropertyID aProperty) const;
318 :
319 : static void AppendImportanceToString(bool aIsImportant, nsAString& aString);
320 : // return whether there was a value in |aValue| (i.e., it had a non-null unit)
321 : bool AppendValueToString(nsCSSPropertyID aProperty, nsAString& aResult) const;
322 : bool AppendValueToString(nsCSSPropertyID aProperty, nsAString& aResult,
323 : nsCSSValue::Serialization aValueSerialization,
324 : bool* aIsTokenStream = nullptr) const;
325 : // Helper for ToString with strange semantics regarding aValue.
326 : void AppendPropertyAndValueToString(nsCSSPropertyID aProperty,
327 : nsAString& aResult,
328 : nsAutoString& aValue,
329 : bool aValueIsTokenStream) const;
330 : // helper for ToString that serializes a custom property declaration for
331 : // a variable with the specified name
332 : void AppendVariableAndValueToString(const nsAString& aName,
333 : nsAString& aResult) const;
334 :
335 : void GetImageLayerValue(nsCSSCompressedDataBlock *data,
336 : nsAString& aValue,
337 : nsCSSValue::Serialization aSerialization,
338 : const nsCSSPropertyID aTable[]) const;
339 :
340 : void GetImageLayerPositionValue(nsCSSCompressedDataBlock *data,
341 : nsAString& aValue,
342 : nsCSSValue::Serialization aSerialization,
343 : const nsCSSPropertyID aTable[]) const;
344 :
345 : public:
346 : /**
347 : * Returns the property at the given index in the ordered list of
348 : * declarations. For custom properties, eCSSPropertyExtra_variable
349 : * is returned.
350 : */
351 0 : nsCSSPropertyID GetPropertyAt(uint32_t aIndex) const {
352 0 : uint32_t value = mOrder[aIndex];
353 0 : if (value >= eCSSProperty_COUNT) {
354 0 : return eCSSPropertyExtra_variable;
355 : }
356 0 : return nsCSSPropertyID(value);
357 : }
358 :
359 : /**
360 : * Gets the name of the custom property at the given index in the ordered
361 : * list of declarations.
362 : */
363 0 : void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const {
364 0 : MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT);
365 0 : uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT;
366 0 : aResult.Truncate();
367 0 : aResult.AppendLiteral("--");
368 0 : aResult.Append(mVariableOrder[variableIndex]);
369 0 : }
370 :
371 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
372 :
373 : private:
374 : // The order of properties in this declaration. Longhand properties are
375 : // represented by their nsCSSPropertyID value, and each custom property (--*)
376 : // is represented by a value that begins at eCSSProperty_COUNT.
377 : //
378 : // Subtracting eCSSProperty_COUNT from those values that represent custom
379 : // properties results in an index into mVariableOrder, which identifies the
380 : // specific variable the custom property declaration is for.
381 : AutoTArray<uint32_t, 8> mOrder;
382 :
383 : // variable names of custom properties found in mOrder
384 : nsTArray<nsString> mVariableOrder;
385 :
386 : // never null, except while expanded, or before the first call to
387 : // InitializeEmpty or CompressFrom.
388 : nsAutoPtr<nsCSSCompressedDataBlock> mData;
389 :
390 : // may be null
391 : nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
392 :
393 : // may be null
394 : nsAutoPtr<CSSVariableDeclarations> mVariables;
395 :
396 : // may be null
397 : nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
398 :
399 : friend class ImportantStyleData;
400 : ImportantStyleData mImportantStyleData;
401 : };
402 :
403 : inline ::mozilla::css::Declaration*
404 3549 : ImportantStyleData::Declaration()
405 : {
406 : union {
407 : char* ch; /* for pointer arithmetic */
408 : ::mozilla::css::Declaration* declaration;
409 : ImportantStyleData* importantData;
410 : } u;
411 3549 : u.importantData = this;
412 3549 : u.ch -= offsetof(::mozilla::css::Declaration, mImportantStyleData);
413 3549 : return u.declaration;
414 : }
415 :
416 : NS_DEFINE_STATIC_IID_ACCESSOR(Declaration, NS_CSS_DECLARATION_IMPL_CID)
417 :
418 : } // namespace css
419 : } // namespace mozilla
420 :
421 : #endif /* mozilla_css_Declaration_h */
|