Coverage Report

Created: 2018-09-25 14:53

/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