Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/DeclarationBlock.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
/*
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/ServoBindings.h"
17
18
#include "nsCSSPropertyID.h"
19
20
class nsHTMLCSSStyleSheet;
21
22
namespace mozilla {
23
24
namespace css {
25
class Declaration;
26
class Rule;
27
} // namespace css
28
29
class DeclarationBlock final
30
{
31
  DeclarationBlock(const DeclarationBlock& aCopy)
32
    : mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume())
33
    , mImmutable(false)
34
    , mIsDirty(false)
35
0
  {
36
0
    mContainer.mRaw = 0;
37
0
  }
38
39
public:
40
  explicit DeclarationBlock(already_AddRefed<RawServoDeclarationBlock> aRaw)
41
    : mRaw(aRaw)
42
    , mImmutable(false)
43
    , mIsDirty(false)
44
0
  {
45
0
    mContainer.mRaw = 0;
46
0
  }
47
48
  DeclarationBlock()
49
    : DeclarationBlock(Servo_DeclarationBlock_CreateEmpty().Consume())
50
0
  { }
51
52
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeclarationBlock)
53
54
  already_AddRefed<DeclarationBlock> Clone() const
55
0
  {
56
0
    return do_AddRef(new DeclarationBlock(*this));
57
0
  }
58
59
  /**
60
   * Return whether |this| may be modified.
61
   */
62
0
  bool IsMutable() const { return !mImmutable; }
63
64
  /**
65
   * Crash in debug builds if |this| cannot be modified.
66
   */
67
  void AssertMutable() const
68
0
  {
69
0
    MOZ_ASSERT(IsMutable(), "someone forgot to call EnsureMutable");
70
0
  }
71
72
  /**
73
   * Mark this declaration as unmodifiable.
74
   */
75
0
  void SetImmutable() { mImmutable = true; }
76
77
  /**
78
   * Return whether |this| has been restyled after modified.
79
   */
80
0
  bool IsDirty() const { return mIsDirty; }
81
82
  /**
83
   * Mark this declaration as dirty.
84
   */
85
0
  void SetDirty() { mIsDirty = true; }
86
87
  /**
88
   * Mark this declaration as not dirty.
89
   */
90
0
  void UnsetDirty() { mIsDirty = false; }
91
92
  /**
93
   * Copy |this|, if necessary to ensure that it can be modified.
94
   */
95
  already_AddRefed<DeclarationBlock> EnsureMutable()
96
0
  {
97
0
    if (!IsDirty()) {
98
0
      // In stylo, the old DeclarationBlock is stored in element's rule node tree
99
0
      // directly, to avoid new values replacing the DeclarationBlock in the tree
100
0
      // directly, we need to copy the old one here if we haven't yet copied.
101
0
      // As a result the new value does not replace rule node tree until traversal
102
0
      // happens.
103
0
      //
104
0
      // FIXME(emilio): This is a hack for ::first-line and transitions starting
105
0
      // due to CSSOM changes when other transitions are already running. Try
106
0
      // to simplify this setup.
107
0
      return Clone();
108
0
    }
109
0
110
0
    if (!IsMutable()) {
111
0
      return Clone();
112
0
    }
113
0
114
0
    return do_AddRef(this);
115
0
  }
116
117
  void SetOwningRule(css::Rule* aRule)
118
0
  {
119
0
    MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
120
0
               "should never overwrite one rule with another");
121
0
    mContainer.mOwningRule = aRule;
122
0
  }
123
124
  css::Rule* GetOwningRule() const
125
0
  {
126
0
    if (mContainer.mRaw & 0x1) {
127
0
      return nullptr;
128
0
    }
129
0
    return mContainer.mOwningRule;
130
0
  }
131
132
  void SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aHTMLCSSStyleSheet)
133
0
  {
134
0
    MOZ_ASSERT(!mContainer.mHTMLCSSStyleSheet || !aHTMLCSSStyleSheet,
135
0
               "should never overwrite one sheet with another");
136
0
    mContainer.mHTMLCSSStyleSheet = aHTMLCSSStyleSheet;
137
0
    if (aHTMLCSSStyleSheet) {
138
0
      mContainer.mRaw |= uintptr_t(1);
139
0
    }
140
0
  }
141
142
  nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() const
143
0
  {
144
0
    if (!(mContainer.mRaw & 0x1)) {
145
0
      return nullptr;
146
0
    }
147
0
    auto c = mContainer;
148
0
    c.mRaw &= ~uintptr_t(1);
149
0
    return c.mHTMLCSSStyleSheet;
150
0
  }
151
152
  static already_AddRefed<DeclarationBlock>
153
  FromCssText(const nsAString& aCssText, URLExtraData* aExtraData,
154
              nsCompatibility aMode, css::Loader* aLoader);
155
156
0
  RawServoDeclarationBlock* Raw() const { return mRaw; }
157
  RawServoDeclarationBlock* const* RefRaw() const
158
0
  {
159
0
    static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
160
0
                  sizeof(RawServoDeclarationBlock*),
161
0
                  "RefPtr should just be a pointer");
162
0
    return reinterpret_cast<RawServoDeclarationBlock* const*>(&mRaw);
163
0
  }
164
165
  const RawServoDeclarationBlockStrong* RefRawStrong() const
166
0
  {
167
0
    static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
168
0
                  sizeof(RawServoDeclarationBlock*),
169
0
                  "RefPtr should just be a pointer");
170
0
    static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
171
0
                  sizeof(RawServoDeclarationBlockStrong),
172
0
                  "RawServoDeclarationBlockStrong should be the same as RefPtr");
173
0
    return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&mRaw);
174
0
  }
175
176
  void ToString(nsAString& aResult) const
177
0
  {
178
0
    Servo_DeclarationBlock_GetCssText(mRaw, &aResult);
179
0
  }
180
181
  uint32_t Count() const
182
0
  {
183
0
    return Servo_DeclarationBlock_Count(mRaw);
184
0
  }
185
186
  bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
187
0
  {
188
0
    aReturn.Truncate();
189
0
    return Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aReturn);
190
0
  }
191
192
  void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const
193
0
  {
194
0
    NS_ConvertUTF16toUTF8 property(aProperty);
195
0
    Servo_DeclarationBlock_GetPropertyValue(mRaw, &property, &aValue);
196
0
  }
197
198
  void GetPropertyValueByID(nsCSSPropertyID aPropID, nsAString& aValue) const
199
0
  {
200
0
    Servo_DeclarationBlock_GetPropertyValueById(mRaw, aPropID, &aValue);
201
0
  }
202
203
  bool GetPropertyIsImportant(const nsAString& aProperty) const
204
0
  {
205
0
    NS_ConvertUTF16toUTF8 property(aProperty);
206
0
    return Servo_DeclarationBlock_GetPropertyIsImportant(mRaw, &property);
207
0
  }
208
209
  // Returns whether the property was removed.
210
  bool RemoveProperty(const nsAString& aProperty,
211
                      DeclarationBlockMutationClosure aClosure = { })
212
0
  {
213
0
    AssertMutable();
214
0
    NS_ConvertUTF16toUTF8 property(aProperty);
215
0
    return Servo_DeclarationBlock_RemoveProperty(mRaw, &property, aClosure);
216
0
  }
217
218
  // Returns whether the property was removed.
219
  bool RemovePropertyByID(nsCSSPropertyID aProperty,
220
                          DeclarationBlockMutationClosure aClosure = { })
221
0
  {
222
0
    AssertMutable();
223
0
    return Servo_DeclarationBlock_RemovePropertyById(mRaw, aProperty, aClosure);
224
0
  }
225
226
private:
227
0
  ~DeclarationBlock() = default;
228
  union {
229
    // We only ever have one of these since we have an
230
    // nsHTMLCSSStyleSheet only for style attributes, and style
231
    // attributes never have an owning rule.
232
233
    // It's an nsHTMLCSSStyleSheet if the low bit is set.
234
235
    uintptr_t mRaw;
236
237
    // The style rule that owns this declaration.  May be null.
238
    css::Rule* mOwningRule;
239
240
    // The nsHTMLCSSStyleSheet that is responsible for this declaration.
241
    // Only non-null for style attributes.
242
    nsHTMLCSSStyleSheet* mHTMLCSSStyleSheet;
243
  } mContainer;
244
245
  RefPtr<RawServoDeclarationBlock> mRaw;
246
247
  // set when declaration put in the rule tree;
248
  bool mImmutable;
249
250
  // True if this declaration has not been restyled after modified.
251
  //
252
  // Since we can clear this flag from style worker threads, we use an Atomic.
253
  //
254
  // Note that although a single DeclarationBlock can be shared between
255
  // different rule nodes (due to the style="" attribute cache), whenever a
256
  // DeclarationBlock has its mIsDirty flag set to true, we always clone it to
257
  // a unique object first. So when we clear this flag during Servo traversal,
258
  // we know that we are clearing it on a DeclarationBlock that has a single
259
  // reference, and there is no problem with another user of the same
260
  // DeclarationBlock thinking that it is not dirty.
261
  Atomic<bool, MemoryOrdering::Relaxed> mIsDirty;
262
};
263
264
} // namespace mozilla
265
266
#endif // mozilla_DeclarationBlock_h