Declaration.h 14 KB

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