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