no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / style / CSSKeyframesRule.cpp
blob89fe1da32f45aeb8c0c27a5b696704f3a66dd5cd
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 #include "mozilla/dom/CSSKeyframesRule.h"
9 #include "mozilla/dom/CSSKeyframesRuleBinding.h"
10 #include "mozilla/dom/CSSRuleList.h"
11 #include "mozilla/ServoBindings.h"
12 #include "nsCOMArray.h"
14 #include <limits>
16 namespace mozilla::dom {
18 // -------------------------------------------
19 // CSSKeyframeList
22 class CSSKeyframeList : public dom::CSSRuleList {
23 public:
24 CSSKeyframeList(already_AddRefed<StyleLockedKeyframesRule> aRawRule,
25 StyleSheet* aSheet, CSSKeyframesRule* aParentRule)
26 : mStyleSheet(aSheet), mParentRule(aParentRule), mRawRule(aRawRule) {
27 mRules.SetCount(Servo_KeyframesRule_GetCount(mRawRule));
30 NS_DECL_ISUPPORTS_INHERITED
31 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframeList, dom::CSSRuleList)
33 void SetRawAfterClone(RefPtr<StyleLockedKeyframesRule> aRaw) {
34 mRawRule = std::move(aRaw);
35 uint32_t index = 0;
36 for (css::Rule* rule : mRules) {
37 if (rule) {
38 uint32_t line = 0, column = 0;
39 RefPtr<StyleLockedKeyframe> keyframe =
40 Servo_KeyframesRule_GetKeyframeAt(mRawRule, index, &line, &column)
41 .Consume();
42 static_cast<CSSKeyframeRule*>(rule)->SetRawAfterClone(
43 std::move(keyframe));
45 index++;
49 void DropSheetReference() {
50 if (!mStyleSheet) {
51 return;
53 mStyleSheet = nullptr;
54 for (css::Rule* rule : mRules) {
55 if (rule) {
56 rule->DropSheetReference();
61 StyleSheet* GetParentObject() final { return mStyleSheet; }
63 CSSKeyframeRule* GetRule(uint32_t aIndex) {
64 if (!mRules[aIndex]) {
65 uint32_t line = 0, column = 0;
66 RefPtr<StyleLockedKeyframe> rule =
67 Servo_KeyframesRule_GetKeyframeAt(mRawRule, aIndex, &line, &column)
68 .Consume();
69 CSSKeyframeRule* ruleObj = new CSSKeyframeRule(rule.forget(), mStyleSheet,
70 mParentRule, line, column);
71 mRules.ReplaceObjectAt(ruleObj, aIndex);
73 return static_cast<CSSKeyframeRule*>(mRules[aIndex]);
76 CSSKeyframeRule* IndexedGetter(uint32_t aIndex, bool& aFound) final {
77 if (aIndex >= mRules.Length()) {
78 aFound = false;
79 return nullptr;
81 aFound = true;
82 return GetRule(aIndex);
85 void AppendRule() {
86 MOZ_ASSERT(!mParentRule->IsReadOnly());
87 mRules.AppendObject(nullptr);
90 void RemoveRule(uint32_t aIndex) {
91 MOZ_ASSERT(!mParentRule->IsReadOnly());
93 if (aIndex >= mRules.Length()) {
94 return;
96 if (css::Rule* child = mRules[aIndex]) {
97 child->DropReferences();
99 mRules.RemoveObjectAt(aIndex);
102 uint32_t Length() final { return mRules.Length(); }
104 void DropReferences() {
105 if (!mStyleSheet && !mParentRule) {
106 return;
108 mStyleSheet = nullptr;
109 mParentRule = nullptr;
110 for (css::Rule* rule : mRules) {
111 if (rule) {
112 rule->DropParentRuleReference();
113 rule->DropSheetReference();
118 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
119 size_t n = aMallocSizeOf(this);
120 for (const css::Rule* rule : mRules) {
121 n += rule ? rule->SizeOfIncludingThis(aMallocSizeOf) : 0;
123 return n;
126 private:
127 virtual ~CSSKeyframeList() {
128 MOZ_ASSERT(!mParentRule, "Backpointer should have been cleared");
129 MOZ_ASSERT(!mStyleSheet, "Backpointer should have been cleared");
130 DropAllRules();
133 void DropAllRules() {
134 DropReferences();
135 mRules.Clear();
136 mRawRule = nullptr;
139 // may be nullptr when the style sheet drops the reference to us.
140 StyleSheet* mStyleSheet = nullptr;
141 CSSKeyframesRule* mParentRule = nullptr;
142 RefPtr<StyleLockedKeyframesRule> mRawRule;
143 nsCOMArray<css::Rule> mRules;
146 // QueryInterface implementation for CSSKeyframeList
147 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframeList)
148 NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
150 NS_IMPL_ADDREF_INHERITED(CSSKeyframeList, dom::CSSRuleList)
151 NS_IMPL_RELEASE_INHERITED(CSSKeyframeList, dom::CSSRuleList)
153 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframeList)
155 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSKeyframeList)
156 tmp->DropAllRules();
157 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframeList,
159 dom::CSSRuleList)
160 for (css::Rule* rule : tmp->mRules) {
161 if (rule) {
162 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
163 cb.NoteXPCOMChild(rule);
166 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
168 // -------------------------------------------
169 // CSSKeyframesRule
172 CSSKeyframesRule::CSSKeyframesRule(RefPtr<StyleLockedKeyframesRule> aRawRule,
173 StyleSheet* aSheet, css::Rule* aParentRule,
174 uint32_t aLine, uint32_t aColumn)
175 : css::Rule(aSheet, aParentRule, aLine, aColumn),
176 mRawRule(std::move(aRawRule)) {}
178 CSSKeyframesRule::~CSSKeyframesRule() {
179 if (mKeyframeList) {
180 mKeyframeList->DropReferences();
184 NS_IMPL_ADDREF_INHERITED(CSSKeyframesRule, css::Rule)
185 NS_IMPL_RELEASE_INHERITED(CSSKeyframesRule, css::Rule)
187 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframesRule)
188 NS_INTERFACE_MAP_END_INHERITING(css::Rule)
190 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframesRule)
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CSSKeyframesRule, css::Rule)
193 if (tmp->mKeyframeList) {
194 tmp->mKeyframeList->DropReferences();
195 tmp->mKeyframeList = nullptr;
197 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframesRule, Rule)
200 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mKeyframeList)
201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
203 /* virtual */
204 bool CSSKeyframesRule::IsCCLeaf() const {
205 // If we don't have rule list constructed, we are a leaf.
206 return Rule::IsCCLeaf() && !mKeyframeList;
209 StyleCssRuleType CSSKeyframesRule::Type() const {
210 return StyleCssRuleType::Keyframes;
213 void CSSKeyframesRule::SetRawAfterClone(RefPtr<StyleLockedKeyframesRule> aRaw) {
214 mRawRule = std::move(aRaw);
215 if (mKeyframeList) {
216 mKeyframeList->SetRawAfterClone(mRawRule);
220 #ifdef DEBUG
221 /* virtual */
222 void CSSKeyframesRule::List(FILE* out, int32_t aIndent) const {
223 nsAutoCString str;
224 for (int32_t i = 0; i < aIndent; i++) {
225 str.AppendLiteral(" ");
227 Servo_KeyframesRule_Debug(mRawRule, &str);
228 fprintf_stderr(out, "%s\n", str.get());
230 #endif
232 /* virtual */
233 void CSSKeyframesRule::DropSheetReference() {
234 if (mKeyframeList) {
235 mKeyframeList->DropSheetReference();
237 css::Rule::DropSheetReference();
240 static const uint32_t kRuleNotFound = std::numeric_limits<uint32_t>::max();
242 uint32_t CSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey) {
243 NS_ConvertUTF16toUTF8 key(aKey);
244 return Servo_KeyframesRule_FindRule(mRawRule, &key);
247 template <typename Func>
248 nsresult CSSKeyframesRule::UpdateRule(Func aCallback) {
249 if (IsReadOnly()) {
250 return NS_OK;
253 StyleSheet* sheet = GetStyleSheet();
254 if (sheet) {
255 sheet->WillDirty();
258 aCallback();
260 if (sheet) {
261 sheet->RuleChanged(this, StyleRuleChangeKind::Generic);
264 return NS_OK;
267 void CSSKeyframesRule::GetName(nsAString& aName) const {
268 nsAtom* name = Servo_KeyframesRule_GetName(mRawRule);
269 aName = nsDependentAtomString(name);
272 void CSSKeyframesRule::SetName(const nsAString& aName) {
273 RefPtr<nsAtom> name = NS_Atomize(aName);
274 nsAtom* oldName = Servo_KeyframesRule_GetName(mRawRule);
275 if (name == oldName) {
276 return;
279 UpdateRule([this, &name]() {
280 Servo_KeyframesRule_SetName(mRawRule, name.forget().take());
284 void CSSKeyframesRule::AppendRule(const nsAString& aRule) {
285 StyleSheet* sheet = GetStyleSheet();
286 if (!sheet) {
287 // We cannot parse the rule if we don't have a stylesheet.
288 return;
291 NS_ConvertUTF16toUTF8 rule(aRule);
292 UpdateRule([this, sheet, &rule]() {
293 bool parsedOk =
294 Servo_KeyframesRule_AppendRule(mRawRule, sheet->RawContents(), &rule);
295 if (parsedOk && mKeyframeList) {
296 mKeyframeList->AppendRule();
301 void CSSKeyframesRule::DeleteRule(const nsAString& aKey) {
302 auto index = FindRuleIndexForKey(aKey);
303 if (index == kRuleNotFound) {
304 return;
307 UpdateRule([this, index]() {
308 Servo_KeyframesRule_DeleteRule(mRawRule, index);
309 if (mKeyframeList) {
310 mKeyframeList->RemoveRule(index);
315 /* virtual */
316 void CSSKeyframesRule::GetCssText(nsACString& aCssText) const {
317 Servo_KeyframesRule_GetCssText(mRawRule, &aCssText);
320 /* virtual */ dom::CSSRuleList* CSSKeyframesRule::CssRules() {
321 return EnsureRules();
324 /* virtual */ dom::CSSKeyframeRule* CSSKeyframesRule::IndexedGetter(
325 uint32_t aIndex, bool& aFound) {
326 return EnsureRules()->IndexedGetter(aIndex, aFound);
329 /* virtual */ uint32_t CSSKeyframesRule::Length() {
330 return EnsureRules()->Length();
333 /* virtual */ dom::CSSKeyframeRule* CSSKeyframesRule::FindRule(
334 const nsAString& aKey) {
335 auto index = FindRuleIndexForKey(aKey);
336 if (index != kRuleNotFound) {
337 return EnsureRules()->GetRule(index);
339 return nullptr;
342 /* virtual */
343 size_t CSSKeyframesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
344 size_t n = aMallocSizeOf(this);
345 if (mKeyframeList) {
346 n += mKeyframeList->SizeOfIncludingThis(aMallocSizeOf);
348 return n;
351 /* virtual */
352 JSObject* CSSKeyframesRule::WrapObject(JSContext* aCx,
353 JS::Handle<JSObject*> aGivenProto) {
354 return CSSKeyframesRule_Binding::Wrap(aCx, this, aGivenProto);
357 dom::CSSKeyframeList* CSSKeyframesRule::EnsureRules() {
358 if (!mKeyframeList) {
359 mKeyframeList = new CSSKeyframeList(do_AddRef(mRawRule), mSheet, this);
361 return mKeyframeList;
364 } // namespace mozilla::dom