1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * representation of a declaration block in a CSS stylesheet, or of 9 * a style attribute 10 */ 11 12 #ifndef mozilla_DeclarationBlock_h 13 #define mozilla_DeclarationBlock_h 14 15 #include "mozilla/Atomics.h" 16 #include "mozilla/ServoUtils.h" 17 #include "mozilla/StyleBackendType.h" 18 19 #include "nsCSSPropertyID.h" 20 21 class nsHTMLCSSStyleSheet; 22 23 namespace mozilla { 24 25 class ServoDeclarationBlock; 26 27 namespace css { 28 class Declaration; 29 class Rule; 30 } // namespace css 31 32 class DeclarationBlock { 33 protected: DeclarationBlock(StyleBackendType aType)34 explicit DeclarationBlock(StyleBackendType aType) 35 : mImmutable(false), mType(aType), mIsDirty(false) { 36 mContainer.mRaw = 0; 37 } 38 DeclarationBlock(const DeclarationBlock & aCopy)39 DeclarationBlock(const DeclarationBlock& aCopy) 40 : DeclarationBlock(aCopy.mType) {} 41 42 public: 43 MOZ_DECL_STYLO_METHODS(css::Declaration, ServoDeclarationBlock) 44 45 inline MozExternalRefCountType AddRef(); 46 inline MozExternalRefCountType Release(); 47 48 inline already_AddRefed<DeclarationBlock> Clone() const; 49 50 /** 51 * Return whether |this| may be modified. 52 */ IsMutable()53 bool IsMutable() const { return !mImmutable; } 54 55 /** 56 * Crash if |this| cannot be modified. 57 */ AssertMutable()58 void AssertMutable() const { 59 MOZ_ASSERT(IsMutable(), "someone forgot to call EnsureMutable"); 60 } 61 62 /** 63 * Mark this declaration as unmodifiable. It's 'const' so it can 64 * be called from ToString. 65 */ SetImmutable()66 void SetImmutable() { mImmutable = true; } 67 68 /** 69 * Return whether |this| has been restyled after modified. 70 */ IsDirty()71 bool IsDirty() const { return mIsDirty; } 72 73 /** 74 * Mark this declaration as dirty. 75 */ SetDirty()76 void SetDirty() { mIsDirty = true; } 77 78 /** 79 * Mark this declaration as not dirty. 80 */ UnsetDirty()81 void UnsetDirty() { mIsDirty = false; } 82 83 /** 84 * Copy |this|, if necessary to ensure that it can be modified. 85 */ 86 inline already_AddRefed<DeclarationBlock> EnsureMutable(); 87 SetOwningRule(css::Rule * aRule)88 void SetOwningRule(css::Rule* aRule) { 89 MOZ_ASSERT(!mContainer.mOwningRule || !aRule, 90 "should never overwrite one rule with another"); 91 mContainer.mOwningRule = aRule; 92 } 93 GetOwningRule()94 css::Rule* GetOwningRule() const { 95 if (mContainer.mRaw & 0x1) { 96 return nullptr; 97 } 98 return mContainer.mOwningRule; 99 } 100 SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet * aHTMLCSSStyleSheet)101 void SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aHTMLCSSStyleSheet) { 102 MOZ_ASSERT(!mContainer.mHTMLCSSStyleSheet || !aHTMLCSSStyleSheet, 103 "should never overwrite one sheet with another"); 104 mContainer.mHTMLCSSStyleSheet = aHTMLCSSStyleSheet; 105 if (aHTMLCSSStyleSheet) { 106 mContainer.mRaw |= uintptr_t(1); 107 } 108 } 109 GetHTMLCSSStyleSheet()110 nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() const { 111 if (!(mContainer.mRaw & 0x1)) { 112 return nullptr; 113 } 114 auto c = mContainer; 115 c.mRaw &= ~uintptr_t(1); 116 return c.mHTMLCSSStyleSheet; 117 } 118 119 inline void ToString(nsAString& aString) const; 120 121 inline uint32_t Count() const; 122 inline bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const; 123 124 inline void GetPropertyValue(const nsAString& aProperty, 125 nsAString& aValue) const; 126 inline void GetPropertyValueByID(nsCSSPropertyID aPropID, 127 nsAString& aValue) const; 128 inline bool GetPropertyIsImportant(const nsAString& aProperty) const; 129 // Returns whether the property was removed. 130 inline bool RemoveProperty(const nsAString& aProperty); 131 // Returns whether the property was removed. 132 inline bool RemovePropertyByID(nsCSSPropertyID aProperty); 133 134 private: 135 union { 136 // We only ever have one of these since we have an 137 // nsHTMLCSSStyleSheet only for style attributes, and style 138 // attributes never have an owning rule. 139 140 // It's an nsHTMLCSSStyleSheet if the low bit is set. 141 142 uintptr_t mRaw; 143 144 // The style rule that owns this declaration. May be null. 145 css::Rule* mOwningRule; 146 147 // The nsHTMLCSSStyleSheet that is responsible for this declaration. 148 // Only non-null for style attributes. 149 nsHTMLCSSStyleSheet* mHTMLCSSStyleSheet; 150 } mContainer; 151 152 // set when declaration put in the rule tree; 153 bool mImmutable; 154 155 const StyleBackendType mType; 156 157 // True if this declaration has not been restyled after modified. 158 // 159 // Since we can clear this flag from style worker threads, we use an Atomic. 160 // 161 // Note that although a single DeclarationBlock can be shared between 162 // different rule nodes (due to the style="" attribute cache), whenever a 163 // DeclarationBlock has its mIsDirty flag set to true, we always clone it to 164 // a unique object first. So when we clear this flag during Servo traversal, 165 // we know that we are clearing it on a DeclarationBlock that has a single 166 // reference, and there is no problem with another user of the same 167 // DeclarationBlock thinking that it is not dirty. 168 Atomic<bool, MemoryOrdering::Relaxed> mIsDirty; 169 }; 170 171 } // namespace mozilla 172 173 #endif // mozilla_DeclarationBlock_h 174