Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / base / nsAttrValueInlines.h
bloba058c6165447a091033eadc96374527ed4927a42
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/. */
7 #ifndef nsAttrValueInlines_h__
8 #define nsAttrValueInlines_h__
10 #include <stdint.h>
12 #include "nsAttrValue.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/ServoUtils.h"
16 #include "mozilla/dom/DOMString.h"
18 namespace mozilla {
19 class ShadowParts;
22 struct MiscContainer final {
23 using ValueType = nsAttrValue::ValueType;
25 ValueType mType;
26 // mStringBits points to either nsAtom* or mozilla::StringBuffer* and is used
27 // when mType isn't eCSSDeclaration. Note eStringBase and eAtomBase is used
28 // also to handle the type of mStringBits.
30 // Note that we use an atomic here so that we can use Compare-And-Swap
31 // to cache the serialization during the parallel servo traversal. This case
32 // (which happens when the main thread is blocked) is the only case where
33 // mStringBits is mutated off-main-thread. The Atomic needs to be
34 // ReleaseAcquire so that the pointer to the serialization does not become
35 // observable to other threads before the initialization of the pointed-to
36 // memory is also observable.
37 mozilla::Atomic<uintptr_t, mozilla::ReleaseAcquire> mStringBits;
38 union {
39 struct {
40 union {
41 int32_t mInteger;
42 nscolor mColor;
43 uint32_t mEnumValue;
44 mozilla::DeclarationBlock* mCSSDeclaration;
45 nsIURI* mURL;
46 const mozilla::AttrAtomArray* mAtomArray;
47 const mozilla::ShadowParts* mShadowParts;
48 const mozilla::SVGAnimatedIntegerPair* mSVGAnimatedIntegerPair;
49 const mozilla::SVGAnimatedLength* mSVGLength;
50 const mozilla::SVGAnimatedNumberPair* mSVGAnimatedNumberPair;
51 const mozilla::SVGAnimatedOrient* mSVGAnimatedOrient;
52 const mozilla::SVGAnimatedPreserveAspectRatio*
53 mSVGAnimatedPreserveAspectRatio;
54 const mozilla::SVGAnimatedViewBox* mSVGAnimatedViewBox;
55 const mozilla::SVGLengthList* mSVGLengthList;
56 const mozilla::SVGNumberList* mSVGNumberList;
57 const mozilla::SVGPathData* mSVGPathData;
58 const mozilla::SVGPointList* mSVGPointList;
59 const mozilla::SVGStringList* mSVGStringList;
60 const mozilla::SVGTransformList* mSVGTransformList;
62 uint32_t mRefCount : 31;
63 uint32_t mCached : 1;
64 } mValue;
65 double mDoubleValue;
68 MiscContainer() : mType(nsAttrValue::eColor), mStringBits(0) {
69 MOZ_COUNT_CTOR(MiscContainer);
70 mValue.mColor = 0;
71 mValue.mRefCount = 0;
72 mValue.mCached = 0;
75 protected:
76 // Only nsAttrValue should be able to delete us.
77 friend class nsAttrValue;
79 ~MiscContainer() {
80 if (IsRefCounted()) {
81 MOZ_ASSERT(mValue.mRefCount == 0);
82 MOZ_ASSERT(!mValue.mCached);
84 MOZ_COUNT_DTOR(MiscContainer);
87 public:
88 bool GetString(nsAString& aString) const;
90 void* GetStringOrAtomPtr(bool& aIsString) const {
91 uintptr_t bits = mStringBits;
92 aIsString =
93 nsAttrValue::ValueBaseType(mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
94 nsAttrValue::eStringBase;
95 return reinterpret_cast<void*>(bits & NS_ATTRVALUE_POINTERVALUE_MASK);
98 nsAtom* GetStoredAtom() const {
99 bool isString = false;
100 void* ptr = GetStringOrAtomPtr(isString);
101 return isString ? nullptr : static_cast<nsAtom*>(ptr);
104 mozilla::StringBuffer* GetStoredStringBuffer() const {
105 bool isString = false;
106 void* ptr = GetStringOrAtomPtr(isString);
107 return isString ? static_cast<mozilla::StringBuffer*>(ptr) : nullptr;
110 void SetStringBitsMainThread(uintptr_t aBits) {
111 // mStringBits is atomic, but the callers of this function are
112 // single-threaded so they don't have to worry about it.
113 MOZ_ASSERT(!mozilla::IsInServoTraversal());
114 MOZ_ASSERT(NS_IsMainThread());
115 mStringBits = aBits;
118 inline bool IsRefCounted() const {
119 // Nothing stops us from refcounting (and sharing) other types of
120 // MiscContainer (except eDoubleValue types) but there's no compelling
121 // reason to.
122 return mType == nsAttrValue::eAtomArray ||
123 mType == nsAttrValue::eCSSDeclaration ||
124 mType == nsAttrValue::eShadowParts;
127 inline int32_t AddRef() {
128 MOZ_ASSERT(IsRefCounted());
129 return ++mValue.mRefCount;
132 inline int32_t Release() {
133 MOZ_ASSERT(IsRefCounted());
134 return --mValue.mRefCount;
137 void Cache();
138 void Evict();
142 * Implementation of inline methods
145 inline int32_t nsAttrValue::GetIntegerValue() const {
146 MOZ_ASSERT(Type() == eInteger, "wrong type");
147 return (BaseType() == eIntegerBase) ? GetIntInternal()
148 : GetMiscContainer()->mValue.mInteger;
151 inline int16_t nsAttrValue::GetEnumValue() const {
152 MOZ_ASSERT(Type() == eEnum, "wrong type");
153 // We don't need to worry about sign extension here since we're
154 // returning an int16_t which will cut away the top bits.
155 return static_cast<int16_t>(((BaseType() == eIntegerBase)
156 ? static_cast<uint32_t>(GetIntInternal())
157 : GetMiscContainer()->mValue.mEnumValue) >>
158 NS_ATTRVALUE_ENUMTABLEINDEX_BITS);
161 inline double nsAttrValue::GetPercentValue() const {
162 MOZ_ASSERT(Type() == ePercent, "wrong type");
163 if (BaseType() == eIntegerBase) {
164 return GetIntInternal() / 100.0f;
166 return GetMiscContainer()->mDoubleValue / 100.0f;
169 inline const mozilla::AttrAtomArray* nsAttrValue::GetAtomArrayValue() const {
170 MOZ_ASSERT(Type() == eAtomArray, "wrong type");
171 return GetMiscContainer()->mValue.mAtomArray;
174 inline mozilla::DeclarationBlock* nsAttrValue::GetCSSDeclarationValue() const {
175 MOZ_ASSERT(Type() == eCSSDeclaration, "wrong type");
176 return GetMiscContainer()->mValue.mCSSDeclaration;
179 inline nsIURI* nsAttrValue::GetURLValue() const {
180 MOZ_ASSERT(Type() == eURL, "wrong type");
181 return GetMiscContainer()->mValue.mURL;
184 inline double nsAttrValue::GetDoubleValue() const {
185 MOZ_ASSERT(Type() == eDoubleValue, "wrong type");
186 return GetMiscContainer()->mDoubleValue;
189 inline bool nsAttrValue::IsSVGType(ValueType aType) const {
190 return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
193 inline bool nsAttrValue::StoresOwnData() const {
194 if (BaseType() != eOtherBase) {
195 return true;
197 ValueType t = Type();
198 return t != eCSSDeclaration && !IsSVGType(t);
201 inline void nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType) {
202 NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
203 "pointer not properly aligned, this will crash");
204 mBits = reinterpret_cast<intptr_t>(aValue) | aType;
207 inline void nsAttrValue::ResetIfSet() {
208 if (mBits) {
209 Reset();
213 inline MiscContainer* nsAttrValue::GetMiscContainer() const {
214 NS_ASSERTION(BaseType() == eOtherBase, "wrong type");
215 return static_cast<MiscContainer*>(GetPtr());
218 inline int32_t nsAttrValue::GetIntInternal() const {
219 NS_ASSERTION(BaseType() == eIntegerBase, "getting integer from non-integer");
220 // Make sure we get a signed value.
221 // Lets hope the optimizer optimizes this into a shift. Unfortunatly signed
222 // bitshift right is implementaion dependant.
223 return static_cast<int32_t>(mBits & ~NS_ATTRVALUE_INTEGERTYPE_MASK) /
224 NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER;
227 inline nsAttrValue::ValueType nsAttrValue::Type() const {
228 switch (BaseType()) {
229 case eIntegerBase: {
230 return static_cast<ValueType>(mBits & NS_ATTRVALUE_INTEGERTYPE_MASK);
232 case eOtherBase: {
233 return GetMiscContainer()->mType;
235 default: {
236 return static_cast<ValueType>(static_cast<uint16_t>(BaseType()));
241 inline nsAtom* nsAttrValue::GetAtomValue() const {
242 MOZ_ASSERT(Type() == eAtom, "wrong type");
243 return reinterpret_cast<nsAtom*>(GetPtr());
246 inline void nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const {
247 switch (Type()) {
248 case eString: {
249 if (auto* str = static_cast<mozilla::StringBuffer*>(GetPtr())) {
250 aResult.SetKnownLiveStringBuffer(
251 str, str->StorageSize() / sizeof(char16_t) - 1);
253 // else aResult is already empty
254 return;
256 case eAtom: {
257 nsAtom* atom = static_cast<nsAtom*>(GetPtr());
258 aResult.SetKnownLiveAtom(atom, mozilla::dom::DOMString::eNullNotExpected);
259 break;
261 default: {
262 ToString(aResult.AsAString());
267 inline const mozilla::ShadowParts& nsAttrValue::GetShadowPartsValue() const {
268 MOZ_ASSERT(Type() == eShadowParts);
269 return *GetMiscContainer()->mValue.mShadowParts;
272 #endif