Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/CSSKeyframesRule.cpp
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
#include "mozilla/dom/CSSKeyframesRule.h"
8
9
#include "mozilla/dom/CSSKeyframesRuleBinding.h"
10
#include "mozilla/dom/CSSRuleList.h"
11
#include "mozilla/ServoBindings.h"
12
13
#include <limits>
14
15
namespace mozilla {
16
namespace dom {
17
18
// -------------------------------------------
19
// CSSKeyframeList
20
//
21
22
class CSSKeyframeList : public dom::CSSRuleList
23
{
24
public:
25
  CSSKeyframeList(already_AddRefed<RawServoKeyframesRule> aRawRule,
26
                  StyleSheet* aSheet,
27
                  CSSKeyframesRule* aParentRule)
28
    : mStyleSheet(aSheet)
29
    , mParentRule(aParentRule)
30
    , mRawRule(aRawRule)
31
0
  {
32
0
    mRules.SetCount(Servo_KeyframesRule_GetCount(mRawRule));
33
0
  }
34
35
  NS_DECL_ISUPPORTS_INHERITED
36
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframeList, dom::CSSRuleList)
37
38
  void DropSheetReference()
39
0
  {
40
0
    if (!mStyleSheet) {
41
0
      return;
42
0
    }
43
0
    mStyleSheet = nullptr;
44
0
    for (css::Rule* rule : mRules) {
45
0
      if (rule) {
46
0
        rule->DropSheetReference();
47
0
      }
48
0
    }
49
0
  }
50
51
0
  StyleSheet* GetParentObject() final { return mStyleSheet; }
52
53
0
  CSSKeyframeRule* GetRule(uint32_t aIndex) {
54
0
    if (!mRules[aIndex]) {
55
0
      uint32_t line = 0, column = 0;
56
0
      RefPtr<RawServoKeyframe> rule =
57
0
        Servo_KeyframesRule_GetKeyframeAt(mRawRule, aIndex,
58
0
                                          &line, &column).Consume();
59
0
      CSSKeyframeRule* ruleObj =
60
0
        new CSSKeyframeRule(rule.forget(), mStyleSheet, mParentRule,
61
0
                            line, column);
62
0
      mRules.ReplaceObjectAt(ruleObj, aIndex);
63
0
    }
64
0
    return static_cast<CSSKeyframeRule*>(mRules[aIndex]);
65
0
  }
66
67
  CSSKeyframeRule* IndexedGetter(uint32_t aIndex, bool& aFound) final
68
0
  {
69
0
    if (aIndex >= mRules.Length()) {
70
0
      aFound = false;
71
0
      return nullptr;
72
0
    }
73
0
    aFound = true;
74
0
    return GetRule(aIndex);
75
0
  }
76
77
0
  void AppendRule() {
78
0
    mRules.AppendObject(nullptr);
79
0
  }
80
81
0
  void RemoveRule(uint32_t aIndex) {
82
0
    mRules.RemoveObjectAt(aIndex);
83
0
  }
84
85
0
  uint32_t Length() final { return mRules.Length(); }
86
87
  void DropReferences()
88
0
  {
89
0
    if (!mStyleSheet && !mParentRule) {
90
0
      return;
91
0
    }
92
0
    mStyleSheet = nullptr;
93
0
    mParentRule = nullptr;
94
0
    for (css::Rule* rule : mRules) {
95
0
      if (rule) {
96
0
        rule->DropParentRuleReference();
97
0
        rule->DropSheetReference();
98
0
      }
99
0
    }
100
0
  }
101
102
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
103
0
  {
104
0
    size_t n = aMallocSizeOf(this);
105
0
    for (const css::Rule* rule : mRules) {
106
0
      n += rule ? rule->SizeOfIncludingThis(aMallocSizeOf) : 0;
107
0
    }
108
0
    return n;
109
0
  }
110
111
private:
112
0
  virtual ~CSSKeyframeList() {
113
0
    MOZ_ASSERT(!mParentRule, "Backpointer should have been cleared");
114
0
    MOZ_ASSERT(!mStyleSheet, "Backpointer should have been cleared");
115
0
    DropAllRules();
116
0
  }
117
118
  void DropAllRules()
119
0
  {
120
0
    DropReferences();
121
0
    mRules.Clear();
122
0
    mRawRule = nullptr;
123
0
  }
124
125
  // may be nullptr when the style sheet drops the reference to us.
126
  StyleSheet* mStyleSheet = nullptr;
127
  CSSKeyframesRule* mParentRule = nullptr;
128
  RefPtr<RawServoKeyframesRule> mRawRule;
129
  nsCOMArray<css::Rule> mRules;
130
};
131
132
// QueryInterface implementation for CSSKeyframeList
133
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframeList)
134
0
NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
135
136
NS_IMPL_ADDREF_INHERITED(CSSKeyframeList, dom::CSSRuleList)
137
NS_IMPL_RELEASE_INHERITED(CSSKeyframeList, dom::CSSRuleList)
138
139
NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframeList)
140
141
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSKeyframeList)
142
0
  tmp->DropAllRules();
143
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
144
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframeList,
145
0
                                                  dom::CSSRuleList)
146
0
  for (css::Rule* rule : tmp->mRules) {
147
0
    if (rule) {
148
0
      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
149
0
      cb.NoteXPCOMChild(rule);
150
0
    }
151
0
  }
152
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
153
154
// -------------------------------------------
155
// CSSKeyframesRule
156
//
157
158
CSSKeyframesRule::CSSKeyframesRule(RefPtr<RawServoKeyframesRule> aRawRule,
159
                                   StyleSheet* aSheet,
160
                                   css::Rule* aParentRule,
161
                                   uint32_t aLine,
162
                                   uint32_t aColumn)
163
  : css::Rule(aSheet, aParentRule, aLine, aColumn)
164
  , mRawRule(std::move(aRawRule))
165
0
{
166
0
}
167
168
CSSKeyframesRule::~CSSKeyframesRule()
169
0
{
170
0
  if (mKeyframeList) {
171
0
    mKeyframeList->DropReferences();
172
0
  }
173
0
}
174
175
NS_IMPL_ADDREF_INHERITED(CSSKeyframesRule, css::Rule)
176
NS_IMPL_RELEASE_INHERITED(CSSKeyframesRule, css::Rule)
177
178
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframesRule)
179
0
NS_INTERFACE_MAP_END_INHERITING(css::Rule)
180
181
NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframesRule)
182
183
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CSSKeyframesRule,
184
0
                                                css::Rule)
185
0
  if (tmp->mKeyframeList) {
186
0
    tmp->mKeyframeList->DropReferences();
187
0
    tmp->mKeyframeList = nullptr;
188
0
  }
189
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
190
191
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframesRule, Rule)
192
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mKeyframeList)
193
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
194
195
/* virtual */ bool
196
CSSKeyframesRule::IsCCLeaf() const
197
0
{
198
0
  // If we don't have rule list constructed, we are a leaf.
199
0
  return Rule::IsCCLeaf() && !mKeyframeList;
200
0
}
201
202
#ifdef DEBUG
203
/* virtual */ void
204
CSSKeyframesRule::List(FILE* out, int32_t aIndent) const
205
{
206
  nsAutoCString str;
207
  for (int32_t i = 0; i < aIndent; i++) {
208
    str.AppendLiteral("  ");
209
  }
210
  Servo_KeyframesRule_Debug(mRawRule, &str);
211
  fprintf_stderr(out, "%s\n", str.get());
212
}
213
#endif
214
215
/* virtual */ void
216
CSSKeyframesRule::DropSheetReference()
217
0
{
218
0
  if (mKeyframeList) {
219
0
    mKeyframeList->DropSheetReference();
220
0
  }
221
0
  css::Rule::DropSheetReference();
222
0
}
223
224
static const uint32_t kRuleNotFound = std::numeric_limits<uint32_t>::max();
225
226
uint32_t
227
CSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey)
228
0
{
229
0
  NS_ConvertUTF16toUTF8 key(aKey);
230
0
  return Servo_KeyframesRule_FindRule(mRawRule, &key);
231
0
}
232
233
template<typename Func>
234
void
235
CSSKeyframesRule::UpdateRule(Func aCallback)
236
0
{
237
0
  aCallback();
238
0
  if (StyleSheet* sheet = GetStyleSheet()) {
239
0
    sheet->RuleChanged(this);
240
0
  }
241
0
}
Unexecuted instantiation: Unified_cpp_layout_style0.cpp:void mozilla::dom::CSSKeyframesRule::UpdateRule<mozilla::dom::CSSKeyframesRule::SetName(nsTSubstring<char16_t> const&)::$_1>(mozilla::dom::CSSKeyframesRule::SetName(nsTSubstring<char16_t> const&)::$_1)
Unexecuted instantiation: Unified_cpp_layout_style0.cpp:void mozilla::dom::CSSKeyframesRule::UpdateRule<mozilla::dom::CSSKeyframesRule::AppendRule(nsTSubstring<char16_t> const&)::$_2>(mozilla::dom::CSSKeyframesRule::AppendRule(nsTSubstring<char16_t> const&)::$_2)
Unexecuted instantiation: Unified_cpp_layout_style0.cpp:void mozilla::dom::CSSKeyframesRule::UpdateRule<mozilla::dom::CSSKeyframesRule::DeleteRule(nsTSubstring<char16_t> const&)::$_3>(mozilla::dom::CSSKeyframesRule::DeleteRule(nsTSubstring<char16_t> const&)::$_3)
242
243
void
244
CSSKeyframesRule::GetName(nsAString& aName) const
245
0
{
246
0
  nsAtom* name = Servo_KeyframesRule_GetName(mRawRule);
247
0
  aName = nsDependentAtomString(name);
248
0
}
249
250
void
251
CSSKeyframesRule::SetName(const nsAString& aName)
252
0
{
253
0
  RefPtr<nsAtom> name = NS_Atomize(aName);
254
0
  nsAtom* oldName = Servo_KeyframesRule_GetName(mRawRule);
255
0
  if (name == oldName) {
256
0
    return;
257
0
  }
258
0
259
0
  UpdateRule([this, &name]() {
260
0
    Servo_KeyframesRule_SetName(mRawRule, name.forget().take());
261
0
  });
262
0
}
263
264
void
265
CSSKeyframesRule::AppendRule(const nsAString& aRule)
266
0
{
267
0
  StyleSheet* sheet = GetStyleSheet();
268
0
  if (!sheet) {
269
0
    // We cannot parse the rule if we don't have a stylesheet.
270
0
    return;
271
0
  }
272
0
273
0
  NS_ConvertUTF16toUTF8 rule(aRule);
274
0
  UpdateRule([this, sheet, &rule]() {
275
0
    bool parsedOk = Servo_KeyframesRule_AppendRule(
276
0
      mRawRule, sheet->RawContents(), &rule);
277
0
    if (parsedOk && mKeyframeList) {
278
0
      mKeyframeList->AppendRule();
279
0
    }
280
0
  });
281
0
}
282
283
void
284
CSSKeyframesRule::DeleteRule(const nsAString& aKey)
285
0
{
286
0
  auto index = FindRuleIndexForKey(aKey);
287
0
  if (index == kRuleNotFound) {
288
0
    return;
289
0
  }
290
0
291
0
  UpdateRule([this, index]() {
292
0
    Servo_KeyframesRule_DeleteRule(mRawRule, index);
293
0
    if (mKeyframeList) {
294
0
      mKeyframeList->RemoveRule(index);
295
0
    }
296
0
  });
297
0
}
298
299
/* virtual */ void
300
CSSKeyframesRule::GetCssText(nsAString& aCssText) const
301
0
{
302
0
  Servo_KeyframesRule_GetCssText(mRawRule, &aCssText);
303
0
}
304
305
/* virtual */ dom::CSSRuleList*
306
CSSKeyframesRule::CssRules()
307
0
{
308
0
  if (!mKeyframeList) {
309
0
    mKeyframeList = new CSSKeyframeList(do_AddRef(mRawRule), mSheet, this);
310
0
  }
311
0
  return mKeyframeList;
312
0
}
313
314
/* virtual */ dom::CSSKeyframeRule*
315
CSSKeyframesRule::FindRule(const nsAString& aKey)
316
0
{
317
0
  auto index = FindRuleIndexForKey(aKey);
318
0
  if (index != kRuleNotFound) {
319
0
    // Construct mKeyframeList but ignore the result.
320
0
    CssRules();
321
0
    return mKeyframeList->GetRule(index);
322
0
  }
323
0
  return nullptr;
324
0
}
325
326
/* virtual */ size_t
327
CSSKeyframesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
328
0
{
329
0
  size_t n = aMallocSizeOf(this);
330
0
  if (mKeyframeList) {
331
0
    n += mKeyframeList->SizeOfIncludingThis(aMallocSizeOf);
332
0
  }
333
0
  return n;
334
0
}
335
336
/* virtual */ JSObject*
337
CSSKeyframesRule::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
338
0
{
339
0
  return CSSKeyframesRule_Binding::Wrap(aCx, this, aGivenProto);
340
0
}
341
342
} // namespace dom
343
} // namespace mozilla