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"
16 namespace mozilla::dom
{
18 // -------------------------------------------
22 class CSSKeyframeList
: public dom::CSSRuleList
{
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
);
36 for (css::Rule
* rule
: mRules
) {
38 uint32_t line
= 0, column
= 0;
39 RefPtr
<StyleLockedKeyframe
> keyframe
=
40 Servo_KeyframesRule_GetKeyframeAt(mRawRule
, index
, &line
, &column
)
42 static_cast<CSSKeyframeRule
*>(rule
)->SetRawAfterClone(
49 void DropSheetReference() {
53 mStyleSheet
= nullptr;
54 for (css::Rule
* rule
: mRules
) {
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
)
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()) {
82 return GetRule(aIndex
);
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()) {
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
) {
108 mStyleSheet
= nullptr;
109 mParentRule
= nullptr;
110 for (css::Rule
* rule
: mRules
) {
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;
127 virtual ~CSSKeyframeList() {
128 MOZ_ASSERT(!mParentRule
, "Backpointer should have been cleared");
129 MOZ_ASSERT(!mStyleSheet
, "Backpointer should have been cleared");
133 void DropAllRules() {
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
)
157 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList
)
158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframeList
,
160 for (css::Rule
* rule
: tmp
->mRules
) {
162 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mRules[i]");
163 cb
.NoteXPCOMChild(rule
);
166 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
168 // -------------------------------------------
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() {
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
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
);
216 mKeyframeList
->SetRawAfterClone(mRawRule
);
222 void CSSKeyframesRule::List(FILE* out
, int32_t aIndent
) const {
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());
233 void CSSKeyframesRule::DropSheetReference() {
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
) {
253 StyleSheet
* sheet
= GetStyleSheet();
261 sheet
->RuleChanged(this, StyleRuleChangeKind::Generic
);
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
) {
279 UpdateRule([this, &name
]() {
280 Servo_KeyframesRule_SetName(mRawRule
, name
.forget().take());
284 void CSSKeyframesRule::AppendRule(const nsAString
& aRule
) {
285 StyleSheet
* sheet
= GetStyleSheet();
287 // We cannot parse the rule if we don't have a stylesheet.
291 NS_ConvertUTF16toUTF8
rule(aRule
);
292 UpdateRule([this, sheet
, &rule
]() {
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
) {
307 UpdateRule([this, index
]() {
308 Servo_KeyframesRule_DeleteRule(mRawRule
, index
);
310 mKeyframeList
->RemoveRule(index
);
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
);
343 size_t CSSKeyframesRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
344 size_t n
= aMallocSizeOf(this);
346 n
+= mKeyframeList
->SizeOfIncludingThis(aMallocSizeOf
);
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