Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / layout / style / CSSKeyframesRule.cpp
blob5a73700d41d7f17e4cd1f4abf736874ec71479a7
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 {
17 namespace dom {
19 // -------------------------------------------
20 // CSSKeyframeList
23 class CSSKeyframeList : public dom::CSSRuleList {
24 public:
25 CSSKeyframeList(already_AddRefed<RawServoKeyframesRule> aRawRule,
26 StyleSheet* aSheet, CSSKeyframesRule* aParentRule)
27 : mStyleSheet(aSheet), mParentRule(aParentRule), mRawRule(aRawRule) {
28 mRules.SetCount(Servo_KeyframesRule_GetCount(mRawRule));
31 NS_DECL_ISUPPORTS_INHERITED
32 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSKeyframeList, dom::CSSRuleList)
34 void DropSheetReference() {
35 if (!mStyleSheet) {
36 return;
38 mStyleSheet = nullptr;
39 for (css::Rule* rule : mRules) {
40 if (rule) {
41 rule->DropSheetReference();
46 StyleSheet* GetParentObject() final { return mStyleSheet; }
48 CSSKeyframeRule* GetRule(uint32_t aIndex) {
49 if (!mRules[aIndex]) {
50 uint32_t line = 0, column = 0;
51 RefPtr<RawServoKeyframe> rule =
52 Servo_KeyframesRule_GetKeyframeAt(mRawRule, aIndex, &line, &column)
53 .Consume();
54 CSSKeyframeRule* ruleObj = new CSSKeyframeRule(rule.forget(), mStyleSheet,
55 mParentRule, line, column);
56 mRules.ReplaceObjectAt(ruleObj, aIndex);
58 return static_cast<CSSKeyframeRule*>(mRules[aIndex]);
61 CSSKeyframeRule* IndexedGetter(uint32_t aIndex, bool& aFound) final {
62 if (aIndex >= mRules.Length()) {
63 aFound = false;
64 return nullptr;
66 aFound = true;
67 return GetRule(aIndex);
70 void AppendRule() {
71 MOZ_ASSERT(!mParentRule->IsReadOnly());
72 mRules.AppendObject(nullptr);
75 void RemoveRule(uint32_t aIndex) {
76 MOZ_ASSERT(!mParentRule->IsReadOnly());
78 if (aIndex >= mRules.Length()) {
79 return;
81 if (css::Rule* child = mRules[aIndex]) {
82 child->DropReferences();
84 mRules.RemoveObjectAt(aIndex);
87 uint32_t Length() final { return mRules.Length(); }
89 void DropReferences() {
90 if (!mStyleSheet && !mParentRule) {
91 return;
93 mStyleSheet = nullptr;
94 mParentRule = nullptr;
95 for (css::Rule* rule : mRules) {
96 if (rule) {
97 rule->DropParentRuleReference();
98 rule->DropSheetReference();
103 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
104 size_t n = aMallocSizeOf(this);
105 for (const css::Rule* rule : mRules) {
106 n += rule ? rule->SizeOfIncludingThis(aMallocSizeOf) : 0;
108 return n;
111 private:
112 virtual ~CSSKeyframeList() {
113 MOZ_ASSERT(!mParentRule, "Backpointer should have been cleared");
114 MOZ_ASSERT(!mStyleSheet, "Backpointer should have been cleared");
115 DropAllRules();
118 void DropAllRules() {
119 DropReferences();
120 mRules.Clear();
121 mRawRule = nullptr;
124 // may be nullptr when the style sheet drops the reference to us.
125 StyleSheet* mStyleSheet = nullptr;
126 CSSKeyframesRule* mParentRule = nullptr;
127 RefPtr<RawServoKeyframesRule> mRawRule;
128 nsCOMArray<css::Rule> mRules;
131 // QueryInterface implementation for CSSKeyframeList
132 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframeList)
133 NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
135 NS_IMPL_ADDREF_INHERITED(CSSKeyframeList, dom::CSSRuleList)
136 NS_IMPL_RELEASE_INHERITED(CSSKeyframeList, dom::CSSRuleList)
138 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframeList)
140 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSKeyframeList)
141 tmp->DropAllRules();
142 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframeList,
144 dom::CSSRuleList)
145 for (css::Rule* rule : tmp->mRules) {
146 if (rule) {
147 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
148 cb.NoteXPCOMChild(rule);
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
153 // -------------------------------------------
154 // CSSKeyframesRule
157 CSSKeyframesRule::CSSKeyframesRule(RefPtr<RawServoKeyframesRule> aRawRule,
158 StyleSheet* aSheet, css::Rule* aParentRule,
159 uint32_t aLine, uint32_t aColumn)
160 : css::Rule(aSheet, aParentRule, aLine, aColumn),
161 mRawRule(std::move(aRawRule)) {}
163 CSSKeyframesRule::~CSSKeyframesRule() {
164 if (mKeyframeList) {
165 mKeyframeList->DropReferences();
169 NS_IMPL_ADDREF_INHERITED(CSSKeyframesRule, css::Rule)
170 NS_IMPL_RELEASE_INHERITED(CSSKeyframesRule, css::Rule)
172 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframesRule)
173 NS_INTERFACE_MAP_END_INHERITING(css::Rule)
175 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframesRule)
177 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CSSKeyframesRule, css::Rule)
178 if (tmp->mKeyframeList) {
179 tmp->mKeyframeList->DropReferences();
180 tmp->mKeyframeList = nullptr;
182 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframesRule, Rule)
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mKeyframeList)
186 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
188 /* virtual */
189 bool CSSKeyframesRule::IsCCLeaf() const {
190 // If we don't have rule list constructed, we are a leaf.
191 return Rule::IsCCLeaf() && !mKeyframeList;
194 #ifdef DEBUG
195 /* virtual */
196 void CSSKeyframesRule::List(FILE* out, int32_t aIndent) const {
197 nsAutoCString str;
198 for (int32_t i = 0; i < aIndent; i++) {
199 str.AppendLiteral(" ");
201 Servo_KeyframesRule_Debug(mRawRule, &str);
202 fprintf_stderr(out, "%s\n", str.get());
204 #endif
206 /* virtual */
207 void CSSKeyframesRule::DropSheetReference() {
208 if (mKeyframeList) {
209 mKeyframeList->DropSheetReference();
211 css::Rule::DropSheetReference();
214 static const uint32_t kRuleNotFound = std::numeric_limits<uint32_t>::max();
216 uint32_t CSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey) {
217 NS_ConvertUTF16toUTF8 key(aKey);
218 return Servo_KeyframesRule_FindRule(mRawRule, &key);
221 template <typename Func>
222 nsresult CSSKeyframesRule::UpdateRule(Func aCallback) {
223 if (IsReadOnly()) {
224 return NS_OK;
227 aCallback();
228 if (StyleSheet* sheet = GetStyleSheet()) {
229 sheet->RuleChanged(this, StyleRuleChangeKind::Generic);
232 return NS_OK;
235 void CSSKeyframesRule::GetName(nsAString& aName) const {
236 nsAtom* name = Servo_KeyframesRule_GetName(mRawRule);
237 aName = nsDependentAtomString(name);
240 void CSSKeyframesRule::SetName(const nsAString& aName) {
241 RefPtr<nsAtom> name = NS_Atomize(aName);
242 nsAtom* oldName = Servo_KeyframesRule_GetName(mRawRule);
243 if (name == oldName) {
244 return;
247 UpdateRule([this, &name]() {
248 Servo_KeyframesRule_SetName(mRawRule, name.forget().take());
252 void CSSKeyframesRule::AppendRule(const nsAString& aRule) {
253 StyleSheet* sheet = GetStyleSheet();
254 if (!sheet) {
255 // We cannot parse the rule if we don't have a stylesheet.
256 return;
259 NS_ConvertUTF16toUTF8 rule(aRule);
260 UpdateRule([this, sheet, &rule]() {
261 bool parsedOk =
262 Servo_KeyframesRule_AppendRule(mRawRule, sheet->RawContents(), &rule);
263 if (parsedOk && mKeyframeList) {
264 mKeyframeList->AppendRule();
269 void CSSKeyframesRule::DeleteRule(const nsAString& aKey) {
270 auto index = FindRuleIndexForKey(aKey);
271 if (index == kRuleNotFound) {
272 return;
275 UpdateRule([this, index]() {
276 Servo_KeyframesRule_DeleteRule(mRawRule, index);
277 if (mKeyframeList) {
278 mKeyframeList->RemoveRule(index);
283 /* virtual */
284 void CSSKeyframesRule::GetCssText(nsACString& aCssText) const {
285 Servo_KeyframesRule_GetCssText(mRawRule, &aCssText);
288 /* virtual */ dom::CSSRuleList* CSSKeyframesRule::CssRules() {
289 if (!mKeyframeList) {
290 mKeyframeList = new CSSKeyframeList(do_AddRef(mRawRule), mSheet, this);
292 return mKeyframeList;
295 /* virtual */ dom::CSSKeyframeRule* CSSKeyframesRule::FindRule(
296 const nsAString& aKey) {
297 auto index = FindRuleIndexForKey(aKey);
298 if (index != kRuleNotFound) {
299 // Construct mKeyframeList but ignore the result.
300 CssRules();
301 return mKeyframeList->GetRule(index);
303 return nullptr;
306 /* virtual */
307 size_t CSSKeyframesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
308 size_t n = aMallocSizeOf(this);
309 if (mKeyframeList) {
310 n += mKeyframeList->SizeOfIncludingThis(aMallocSizeOf);
312 return n;
315 /* virtual */
316 JSObject* CSSKeyframesRule::WrapObject(JSContext* aCx,
317 JS::Handle<JSObject*> aGivenProto) {
318 return CSSKeyframesRule_Binding::Wrap(aCx, this, aGivenProto);
321 } // namespace dom
322 } // namespace mozilla