1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/Declaration.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,361 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * representation of a declaration block (or style attribute) in a CSS 1.11 + * stylesheet 1.12 + */ 1.13 + 1.14 +#ifndef mozilla_css_Declaration_h 1.15 +#define mozilla_css_Declaration_h 1.16 + 1.17 +// This header is in EXPORTS because it's used in several places in content/, 1.18 +// but it's not really a public interface. 1.19 +#ifndef MOZILLA_INTERNAL_API 1.20 +#error "This file should only be included within libxul" 1.21 +#endif 1.22 + 1.23 +#include "mozilla/Attributes.h" 1.24 +#include "mozilla/MemoryReporting.h" 1.25 +#include "CSSVariableDeclarations.h" 1.26 +#include "nsCSSDataBlock.h" 1.27 +#include "nsCSSProperty.h" 1.28 +#include "nsCSSProps.h" 1.29 +#include "nsStringFwd.h" 1.30 +#include "nsTArray.h" 1.31 +#include <stdio.h> 1.32 + 1.33 +namespace mozilla { 1.34 +namespace css { 1.35 + 1.36 +// Declaration objects have unusual lifetime rules. Every declaration 1.37 +// begins life in an invalid state which ends when InitializeEmpty or 1.38 +// CompressFrom is called upon it. After that, it can be attached to 1.39 +// exactly one style rule, and will be destroyed when that style rule 1.40 +// is destroyed. A declaration becomes immutable when its style rule's 1.41 +// |RuleMatched| method is called; after that, it must be copied before 1.42 +// it can be modified, which is taken care of by |EnsureMutable|. 1.43 + 1.44 +class Declaration { 1.45 +public: 1.46 + /** 1.47 + * Construct an |Declaration| that is in an invalid state (null 1.48 + * |mData|) and cannot be used until its |CompressFrom| method or 1.49 + * |InitializeEmpty| method is called. 1.50 + */ 1.51 + Declaration(); 1.52 + 1.53 + Declaration(const Declaration& aCopy); 1.54 + 1.55 + ~Declaration(); 1.56 + 1.57 + /** 1.58 + * |ValueAppended| must be called to maintain this declaration's 1.59 + * |mOrder| whenever a property is parsed into an expanded data block 1.60 + * for this declaration. aProperty must not be a shorthand. 1.61 + */ 1.62 + void ValueAppended(nsCSSProperty aProperty); 1.63 + 1.64 + void RemoveProperty(nsCSSProperty aProperty); 1.65 + 1.66 + bool HasProperty(nsCSSProperty aProperty) const; 1.67 + 1.68 + void GetValue(nsCSSProperty aProperty, nsAString& aValue) const; 1.69 + void GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const; 1.70 + 1.71 + bool HasImportantData() const { 1.72 + return mImportantData || mImportantVariables; 1.73 + } 1.74 + bool GetValueIsImportant(nsCSSProperty aProperty) const; 1.75 + bool GetValueIsImportant(const nsAString& aProperty) const; 1.76 + 1.77 + /** 1.78 + * Adds a custom property declaration to this object. 1.79 + * 1.80 + * @param aName The variable name (i.e., without the "--" prefix). 1.81 + * @param aType The type of value the variable has. 1.82 + * @param aValue The value of the variable, if aType is 1.83 + * CSSVariableDeclarations::eTokenStream. 1.84 + * @param aIsImportant Whether the declaration is !important. 1.85 + * @param aOverrideImportant When aIsImportant is false, whether an 1.86 + * existing !important declaration will be overridden. 1.87 + */ 1.88 + void AddVariableDeclaration(const nsAString& aName, 1.89 + CSSVariableDeclarations::Type aType, 1.90 + const nsString& aValue, 1.91 + bool aIsImportant, 1.92 + bool aOverrideImportant); 1.93 + 1.94 + /** 1.95 + * Removes a custom property declaration from this object. 1.96 + * 1.97 + * @param aName The variable name (i.e., without the "--" prefix). 1.98 + */ 1.99 + void RemoveVariableDeclaration(const nsAString& aName); 1.100 + 1.101 + /** 1.102 + * Returns whether a custom property declaration for a variable with 1.103 + * a given name exists on this object. 1.104 + * 1.105 + * @param aName The variable name (i.e., without the "--" prefix). 1.106 + */ 1.107 + bool HasVariableDeclaration(const nsAString& aName) const; 1.108 + 1.109 + /** 1.110 + * Gets the string value for a custom property declaration of a variable 1.111 + * with a given name. 1.112 + * 1.113 + * @param aName The variable name (i.e., without the "--" prefix). 1.114 + * @param aValue Out parameter into which the variable's value will be 1.115 + * stored. If the value is 'initial' or 'inherit', that exact string 1.116 + * will be stored in aValue. 1.117 + */ 1.118 + void GetVariableDeclaration(const nsAString& aName, nsAString& aValue) const; 1.119 + 1.120 + /** 1.121 + * Returns whether the custom property declaration for a variable with 1.122 + * the given name was !important. 1.123 + */ 1.124 + bool GetVariableValueIsImportant(const nsAString& aName) const; 1.125 + 1.126 + uint32_t Count() const { 1.127 + return mOrder.Length(); 1.128 + } 1.129 + 1.130 + // Returns whether we actually had a property at aIndex 1.131 + bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const; 1.132 + 1.133 + void ToString(nsAString& aString) const; 1.134 + 1.135 + nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; } 1.136 + nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; } 1.137 + 1.138 + /** 1.139 + * Initialize this declaration as holding no data. Cannot fail. 1.140 + */ 1.141 + void InitializeEmpty(); 1.142 + 1.143 + /** 1.144 + * Transfer all of the state from |aExpandedData| into this declaration. 1.145 + * After calling, |aExpandedData| should be in its initial state. 1.146 + * Callers must make sure mOrder is updated as necessary. 1.147 + */ 1.148 + void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) { 1.149 + NS_ABORT_IF_FALSE(!mData, "oops"); 1.150 + NS_ABORT_IF_FALSE(!mImportantData, "oops"); 1.151 + aExpandedData->Compress(getter_Transfers(mData), 1.152 + getter_Transfers(mImportantData)); 1.153 + aExpandedData->AssertInitialState(); 1.154 + } 1.155 + 1.156 + /** 1.157 + * Transfer all of the state from this declaration into 1.158 + * |aExpandedData| and put this declaration temporarily into an 1.159 + * invalid state (ended by |CompressFrom| or |InitializeEmpty|) that 1.160 + * should last only during parsing. During this time only 1.161 + * |ValueAppended| should be called. 1.162 + */ 1.163 + void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) { 1.164 + AssertMutable(); 1.165 + aExpandedData->AssertInitialState(); 1.166 + 1.167 + NS_ABORT_IF_FALSE(mData, "oops"); 1.168 + aExpandedData->Expand(mData.forget(), mImportantData.forget()); 1.169 + } 1.170 + 1.171 + /** 1.172 + * Do what |nsIStyleRule::MapRuleInfoInto| needs to do for a style 1.173 + * rule using this declaration for storage. 1.174 + */ 1.175 + void MapNormalRuleInfoInto(nsRuleData *aRuleData) const { 1.176 + NS_ABORT_IF_FALSE(mData, "called while expanded"); 1.177 + mData->MapRuleInfoInto(aRuleData); 1.178 + if (mVariables) { 1.179 + mVariables->MapRuleInfoInto(aRuleData); 1.180 + } 1.181 + } 1.182 + void MapImportantRuleInfoInto(nsRuleData *aRuleData) const { 1.183 + NS_ABORT_IF_FALSE(mData, "called while expanded"); 1.184 + NS_ABORT_IF_FALSE(mImportantData || mImportantVariables, 1.185 + "must have important data or variables"); 1.186 + if (mImportantData) { 1.187 + mImportantData->MapRuleInfoInto(aRuleData); 1.188 + } 1.189 + if (mImportantVariables) { 1.190 + mImportantVariables->MapRuleInfoInto(aRuleData); 1.191 + } 1.192 + } 1.193 + 1.194 + /** 1.195 + * Attempt to replace the value for |aProperty| stored in this 1.196 + * declaration with the matching value from |aFromBlock|. 1.197 + * This method may only be called on a mutable declaration. 1.198 + * It will fail (returning false) if |aProperty| is shorthand, 1.199 + * is not already in this declaration, or does not have the indicated 1.200 + * importance level. If it returns true, it erases the value in 1.201 + * |aFromBlock|. |aChanged| is set to true if the declaration 1.202 + * changed as a result of the call, and to false otherwise. 1.203 + */ 1.204 + bool TryReplaceValue(nsCSSProperty aProperty, bool aIsImportant, 1.205 + nsCSSExpandedDataBlock& aFromBlock, 1.206 + bool* aChanged) 1.207 + { 1.208 + AssertMutable(); 1.209 + NS_ABORT_IF_FALSE(mData, "called while expanded"); 1.210 + 1.211 + if (nsCSSProps::IsShorthand(aProperty)) { 1.212 + *aChanged = false; 1.213 + return false; 1.214 + } 1.215 + nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData; 1.216 + // mImportantData might be null 1.217 + if (!block) { 1.218 + *aChanged = false; 1.219 + return false; 1.220 + } 1.221 + 1.222 +#ifdef DEBUG 1.223 + { 1.224 + nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData; 1.225 + NS_ABORT_IF_FALSE(!other || !other->ValueFor(aProperty) || 1.226 + !block->ValueFor(aProperty), 1.227 + "Property both important and not?"); 1.228 + } 1.229 +#endif 1.230 + return block->TryReplaceValue(aProperty, aFromBlock, aChanged); 1.231 + } 1.232 + 1.233 + bool HasNonImportantValueFor(nsCSSProperty aProperty) const { 1.234 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), "must be longhand"); 1.235 + return !!mData->ValueFor(aProperty); 1.236 + } 1.237 + 1.238 + /** 1.239 + * Return whether |this| may be modified. 1.240 + */ 1.241 + bool IsMutable() const { 1.242 + return !mImmutable; 1.243 + } 1.244 + 1.245 + /** 1.246 + * Copy |this|, if necessary to ensure that it can be modified. 1.247 + */ 1.248 + Declaration* EnsureMutable(); 1.249 + 1.250 + /** 1.251 + * Crash if |this| cannot be modified. 1.252 + */ 1.253 + void AssertMutable() const { 1.254 + NS_ABORT_IF_FALSE(IsMutable(), "someone forgot to call EnsureMutable"); 1.255 + } 1.256 + 1.257 + /** 1.258 + * Mark this declaration as unmodifiable. It's 'const' so it can 1.259 + * be called from ToString. 1.260 + */ 1.261 + void SetImmutable() const { mImmutable = true; } 1.262 + 1.263 + /** 1.264 + * Clear the data, in preparation for its replacement with entirely 1.265 + * new data by a call to |CompressFrom|. 1.266 + */ 1.267 + void ClearData() { 1.268 + AssertMutable(); 1.269 + mData = nullptr; 1.270 + mImportantData = nullptr; 1.271 + mVariables = nullptr; 1.272 + mImportantVariables = nullptr; 1.273 + mOrder.Clear(); 1.274 + mVariableOrder.Clear(); 1.275 + } 1.276 + 1.277 +#ifdef DEBUG 1.278 + void List(FILE* out = stdout, int32_t aIndent = 0) const; 1.279 +#endif 1.280 + 1.281 +private: 1.282 + Declaration& operator=(const Declaration& aCopy) MOZ_DELETE; 1.283 + bool operator==(const Declaration& aCopy) const MOZ_DELETE; 1.284 + 1.285 + void GetValue(nsCSSProperty aProperty, nsAString& aValue, 1.286 + nsCSSValue::Serialization aValueSerialization) const; 1.287 + 1.288 + static void AppendImportanceToString(bool aIsImportant, nsAString& aString); 1.289 + // return whether there was a value in |aValue| (i.e., it had a non-null unit) 1.290 + bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const; 1.291 + bool AppendValueToString(nsCSSProperty aProperty, nsAString& aResult, 1.292 + nsCSSValue::Serialization aValueSerialization) const; 1.293 + // Helper for ToString with strange semantics regarding aValue. 1.294 + void AppendPropertyAndValueToString(nsCSSProperty aProperty, 1.295 + nsAutoString& aValue, 1.296 + nsAString& aResult) const; 1.297 + // helper for ToString that serializes a custom property declaration for 1.298 + // a variable with the specified name 1.299 + void AppendVariableAndValueToString(const nsAString& aName, 1.300 + nsAString& aResult) const; 1.301 + 1.302 +public: 1.303 + /** 1.304 + * Returns the property at the given index in the ordered list of 1.305 + * declarations. For custom properties, eCSSPropertyExtra_variable 1.306 + * is returned. 1.307 + */ 1.308 + nsCSSProperty GetPropertyAt(uint32_t aIndex) const { 1.309 + uint32_t value = mOrder[aIndex]; 1.310 + if (value >= eCSSProperty_COUNT) { 1.311 + return eCSSPropertyExtra_variable; 1.312 + } 1.313 + return nsCSSProperty(value); 1.314 + } 1.315 + 1.316 + /** 1.317 + * Gets the name of the custom property at the given index in the ordered 1.318 + * list of declarations. 1.319 + */ 1.320 + void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { 1.321 + MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); 1.322 + uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT; 1.323 + aResult.Truncate(); 1.324 + aResult.AppendLiteral("--"); 1.325 + aResult.Append(mVariableOrder[variableIndex]); 1.326 + } 1.327 + 1.328 + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.329 + 1.330 +private: 1.331 + // The order of properties in this declaration. Longhand properties are 1.332 + // represented by their nsCSSProperty value, and each custom property (--*) 1.333 + // is represented by a value that begins at eCSSProperty_COUNT. 1.334 + // 1.335 + // Subtracting eCSSProperty_COUNT from those values that represent custom 1.336 + // properties results in an index into mVariableOrder, which identifies the 1.337 + // specific variable the custom property declaration is for. 1.338 + nsAutoTArray<uint32_t, 8> mOrder; 1.339 + 1.340 + // variable names of custom properties found in mOrder 1.341 + nsTArray<nsString> mVariableOrder; 1.342 + 1.343 + // never null, except while expanded, or before the first call to 1.344 + // InitializeEmpty or CompressFrom. 1.345 + nsAutoPtr<nsCSSCompressedDataBlock> mData; 1.346 + 1.347 + // may be null 1.348 + nsAutoPtr<nsCSSCompressedDataBlock> mImportantData; 1.349 + 1.350 + // may be null 1.351 + nsAutoPtr<CSSVariableDeclarations> mVariables; 1.352 + 1.353 + // may be null 1.354 + nsAutoPtr<CSSVariableDeclarations> mImportantVariables; 1.355 + 1.356 + // set by style rules when |RuleMatched| is called; 1.357 + // also by ToString (hence the 'mutable'). 1.358 + mutable bool mImmutable; 1.359 +}; 1.360 + 1.361 +} // namespace css 1.362 +} // namespace mozilla 1.363 + 1.364 +#endif /* mozilla_css_Declaration_h */