/src/mozilla-central/dom/base/nsAttrValueInlines.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef nsAttrValueInlines_h__ |
8 | | #define nsAttrValueInlines_h__ |
9 | | |
10 | | #include <stdint.h> |
11 | | |
12 | | #include "nsAttrValue.h" |
13 | | #include "mozilla/Atomics.h" |
14 | | #include "mozilla/Attributes.h" |
15 | | #include "mozilla/ServoUtils.h" |
16 | | |
17 | | struct MiscContainer; |
18 | | |
19 | | struct MiscContainer final |
20 | | { |
21 | | typedef nsAttrValue::ValueType ValueType; |
22 | | |
23 | | ValueType mType; |
24 | | // mStringBits points to either nsAtom* or nsStringBuffer* and is used when |
25 | | // mType isn't eCSSDeclaration. |
26 | | // Note eStringBase and eAtomBase is used also to handle the type of |
27 | | // mStringBits. |
28 | | // |
29 | | // Note that we use an atomic here so that we can use Compare-And-Swap |
30 | | // to cache the serialization during the parallel servo traversal. This case |
31 | | // (which happens when the main thread is blocked) is the only case where |
32 | | // mStringBits is mutated off-main-thread. The Atomic needs to be |
33 | | // ReleaseAcquire so that the pointer to the serialization does not become |
34 | | // observable to other threads before the initialization of the pointed-to |
35 | | // memory is also observable. |
36 | | mozilla::Atomic<uintptr_t, mozilla::ReleaseAcquire> mStringBits; |
37 | | union { |
38 | | struct { |
39 | | union { |
40 | | int32_t mInteger; |
41 | | nscolor mColor; |
42 | | uint32_t mEnumValue; |
43 | | int32_t mPercent; |
44 | | mozilla::DeclarationBlock* mCSSDeclaration; |
45 | | nsIURI* mURL; |
46 | | mozilla::AtomArray* mAtomArray; |
47 | | nsIntMargin* mIntMargin; |
48 | | const nsSVGAngle* mSVGAngle; |
49 | | const nsSVGIntegerPair* mSVGIntegerPair; |
50 | | const nsSVGLength2* mSVGLength; |
51 | | const mozilla::SVGLengthList* mSVGLengthList; |
52 | | const mozilla::SVGNumberList* mSVGNumberList; |
53 | | const nsSVGNumberPair* mSVGNumberPair; |
54 | | const mozilla::SVGPathData* mSVGPathData; |
55 | | const mozilla::SVGPointList* mSVGPointList; |
56 | | const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio; |
57 | | const mozilla::SVGStringList* mSVGStringList; |
58 | | const mozilla::SVGTransformList* mSVGTransformList; |
59 | | const nsSVGViewBox* mSVGViewBox; |
60 | | }; |
61 | | uint32_t mRefCount : 31; |
62 | | uint32_t mCached : 1; |
63 | | } mValue; |
64 | | double mDoubleValue; |
65 | | }; |
66 | | |
67 | | MiscContainer() |
68 | | : mType(nsAttrValue::eColor), |
69 | | mStringBits(0) |
70 | 0 | { |
71 | 0 | MOZ_COUNT_CTOR(MiscContainer); |
72 | 0 | mValue.mColor = 0; |
73 | 0 | mValue.mRefCount = 0; |
74 | 0 | mValue.mCached = 0; |
75 | 0 | } |
76 | | |
77 | | protected: |
78 | | // Only nsAttrValue should be able to delete us. |
79 | | friend class nsAttrValue; |
80 | | |
81 | | ~MiscContainer() |
82 | 0 | { |
83 | 0 | if (IsRefCounted()) { |
84 | 0 | MOZ_ASSERT(mValue.mRefCount == 0); |
85 | 0 | MOZ_ASSERT(!mValue.mCached); |
86 | 0 | } |
87 | 0 | MOZ_COUNT_DTOR(MiscContainer); |
88 | 0 | } |
89 | | |
90 | | public: |
91 | | bool GetString(nsAString& aString) const; |
92 | | |
93 | | void SetStringBitsMainThread(uintptr_t aBits) |
94 | 0 | { |
95 | 0 | // mStringBits is atomic, but the callers of this function are |
96 | 0 | // single-threaded so they don't have to worry about it. |
97 | 0 | MOZ_ASSERT(!mozilla::IsInServoTraversal()); |
98 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
99 | 0 | mStringBits = aBits; |
100 | 0 | } |
101 | | |
102 | | inline bool IsRefCounted() const |
103 | 0 | { |
104 | 0 | // Nothing stops us from refcounting (and sharing) other types of |
105 | 0 | // MiscContainer (except eDoubleValue types) but there's no compelling |
106 | 0 | // reason to. |
107 | 0 | return mType == nsAttrValue::eCSSDeclaration; |
108 | 0 | } |
109 | | |
110 | 0 | inline int32_t AddRef() { |
111 | 0 | MOZ_ASSERT(IsRefCounted()); |
112 | 0 | return ++mValue.mRefCount; |
113 | 0 | } |
114 | | |
115 | 0 | inline int32_t Release() { |
116 | 0 | MOZ_ASSERT(IsRefCounted()); |
117 | 0 | return --mValue.mRefCount; |
118 | 0 | } |
119 | | |
120 | | void Cache(); |
121 | | void Evict(); |
122 | | }; |
123 | | |
124 | | /** |
125 | | * Implementation of inline methods |
126 | | */ |
127 | | |
128 | | inline int32_t |
129 | | nsAttrValue::GetIntegerValue() const |
130 | 0 | { |
131 | 0 | MOZ_ASSERT(Type() == eInteger, "wrong type"); |
132 | 0 | return (BaseType() == eIntegerBase) |
133 | 0 | ? GetIntInternal() |
134 | 0 | : GetMiscContainer()->mValue.mInteger; |
135 | 0 | } |
136 | | |
137 | | inline int16_t |
138 | | nsAttrValue::GetEnumValue() const |
139 | 0 | { |
140 | 0 | MOZ_ASSERT(Type() == eEnum, "wrong type"); |
141 | 0 | // We don't need to worry about sign extension here since we're |
142 | 0 | // returning an int16_t which will cut away the top bits. |
143 | 0 | return static_cast<int16_t>(( |
144 | 0 | (BaseType() == eIntegerBase) |
145 | 0 | ? static_cast<uint32_t>(GetIntInternal()) |
146 | 0 | : GetMiscContainer()->mValue.mEnumValue) |
147 | 0 | >> NS_ATTRVALUE_ENUMTABLEINDEX_BITS); |
148 | 0 | } |
149 | | |
150 | | inline float |
151 | | nsAttrValue::GetPercentValue() const |
152 | 0 | { |
153 | 0 | MOZ_ASSERT(Type() == ePercent, "wrong type"); |
154 | 0 | return ((BaseType() == eIntegerBase) |
155 | 0 | ? GetIntInternal() |
156 | 0 | : GetMiscContainer()->mValue.mPercent) |
157 | 0 | / 100.0f; |
158 | 0 | } |
159 | | |
160 | | inline mozilla::AtomArray* |
161 | | nsAttrValue::GetAtomArrayValue() const |
162 | 0 | { |
163 | 0 | MOZ_ASSERT(Type() == eAtomArray, "wrong type"); |
164 | 0 | return GetMiscContainer()->mValue.mAtomArray; |
165 | 0 | } |
166 | | |
167 | | inline mozilla::DeclarationBlock* |
168 | | nsAttrValue::GetCSSDeclarationValue() const |
169 | 0 | { |
170 | 0 | MOZ_ASSERT(Type() == eCSSDeclaration, "wrong type"); |
171 | 0 | return GetMiscContainer()->mValue.mCSSDeclaration; |
172 | 0 | } |
173 | | |
174 | | inline nsIURI* |
175 | | nsAttrValue::GetURLValue() const |
176 | 0 | { |
177 | 0 | MOZ_ASSERT(Type() == eURL, "wrong type"); |
178 | 0 | return GetMiscContainer()->mValue.mURL; |
179 | 0 | } |
180 | | |
181 | | inline double |
182 | | nsAttrValue::GetDoubleValue() const |
183 | 0 | { |
184 | 0 | MOZ_ASSERT(Type() == eDoubleValue, "wrong type"); |
185 | 0 | return GetMiscContainer()->mDoubleValue; |
186 | 0 | } |
187 | | |
188 | | inline bool |
189 | | nsAttrValue::GetIntMarginValue(nsIntMargin& aMargin) const |
190 | 0 | { |
191 | 0 | MOZ_ASSERT(Type() == eIntMarginValue, "wrong type"); |
192 | 0 | nsIntMargin* m = GetMiscContainer()->mValue.mIntMargin; |
193 | 0 | if (!m) |
194 | 0 | return false; |
195 | 0 | aMargin = *m; |
196 | 0 | return true; |
197 | 0 | } |
198 | | |
199 | | inline bool |
200 | | nsAttrValue::IsSVGType(ValueType aType) const |
201 | 0 | { |
202 | 0 | return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd; |
203 | 0 | } |
204 | | |
205 | | inline bool |
206 | | nsAttrValue::StoresOwnData() const |
207 | 0 | { |
208 | 0 | if (BaseType() != eOtherBase) { |
209 | 0 | return true; |
210 | 0 | } |
211 | 0 | ValueType t = Type(); |
212 | 0 | return t != eCSSDeclaration && !IsSVGType(t); |
213 | 0 | } |
214 | | |
215 | | inline void |
216 | | nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType) |
217 | 0 | { |
218 | 0 | NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK), |
219 | 0 | "pointer not properly aligned, this will crash"); |
220 | 0 | mBits = reinterpret_cast<intptr_t>(aValue) | aType; |
221 | 0 | } |
222 | | |
223 | | inline void |
224 | | nsAttrValue::ResetIfSet() |
225 | 0 | { |
226 | 0 | if (mBits) { |
227 | 0 | Reset(); |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | | inline MiscContainer* |
232 | | nsAttrValue::GetMiscContainer() const |
233 | 0 | { |
234 | 0 | NS_ASSERTION(BaseType() == eOtherBase, "wrong type"); |
235 | 0 | return static_cast<MiscContainer*>(GetPtr()); |
236 | 0 | } |
237 | | |
238 | | inline int32_t |
239 | | nsAttrValue::GetIntInternal() const |
240 | 0 | { |
241 | 0 | NS_ASSERTION(BaseType() == eIntegerBase, |
242 | 0 | "getting integer from non-integer"); |
243 | 0 | // Make sure we get a signed value. |
244 | 0 | // Lets hope the optimizer optimizes this into a shift. Unfortunatly signed |
245 | 0 | // bitshift right is implementaion dependant. |
246 | 0 | return static_cast<int32_t>(mBits & ~NS_ATTRVALUE_INTEGERTYPE_MASK) / |
247 | 0 | NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER; |
248 | 0 | } |
249 | | |
250 | | inline nsAttrValue::ValueType |
251 | | nsAttrValue::Type() const |
252 | 0 | { |
253 | 0 | switch (BaseType()) { |
254 | 0 | case eIntegerBase: |
255 | 0 | { |
256 | 0 | return static_cast<ValueType>(mBits & NS_ATTRVALUE_INTEGERTYPE_MASK); |
257 | 0 | } |
258 | 0 | case eOtherBase: |
259 | 0 | { |
260 | 0 | return GetMiscContainer()->mType; |
261 | 0 | } |
262 | 0 | default: |
263 | 0 | { |
264 | 0 | return static_cast<ValueType>(static_cast<uint16_t>(BaseType())); |
265 | 0 | } |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | | inline nsAtom* |
270 | | nsAttrValue::GetAtomValue() const |
271 | 0 | { |
272 | 0 | MOZ_ASSERT(Type() == eAtom, "wrong type"); |
273 | 0 | return reinterpret_cast<nsAtom*>(GetPtr()); |
274 | 0 | } |
275 | | |
276 | | inline void |
277 | | nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const |
278 | 0 | { |
279 | 0 | switch (Type()) { |
280 | 0 | case eString: |
281 | 0 | { |
282 | 0 | nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); |
283 | 0 | if (str) { |
284 | 0 | aResult.SetKnownLiveStringBuffer( |
285 | 0 | str, str->StorageSize()/sizeof(char16_t) - 1); |
286 | 0 | } |
287 | 0 | // else aResult is already empty |
288 | 0 | return; |
289 | 0 | } |
290 | 0 | case eAtom: |
291 | 0 | { |
292 | 0 | nsAtom *atom = static_cast<nsAtom*>(GetPtr()); |
293 | 0 | aResult.SetKnownLiveAtom(atom, mozilla::dom::DOMString::eNullNotExpected); |
294 | 0 | break; |
295 | 0 | } |
296 | 0 | default: |
297 | 0 | { |
298 | 0 | ToString(aResult.AsAString()); |
299 | 0 | } |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | #endif |