1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7 * representation of CSS style rules (selectors+declaration), CSS
8 * selectors, and DOM objects for style rules, selectors, and
9 * declarations
10 */
11
12 #include "mozilla/css/StyleRule.h"
13
14 #include "mozilla/DeclarationBlockInlines.h"
15 #include "mozilla/StyleSheetInlines.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/css/GroupRule.h"
18 #include "mozilla/css/Declaration.h"
19 #include "nsIDocument.h"
20 #include "nsIAtom.h"
21 #include "nsString.h"
22 #include "nsStyleUtil.h"
23 #include "nsICSSStyleRuleDOMWrapper.h"
24 #include "nsDOMCSSDeclaration.h"
25 #include "nsNameSpaceManager.h"
26 #include "nsXMLNameSpaceMap.h"
27 #include "nsCSSPseudoClasses.h"
28 #include "nsCSSAnonBoxes.h"
29 #include "nsTArray.h"
30 #include "nsDOMClassInfoID.h"
31 #include "nsContentUtils.h"
32 #include "nsError.h"
33 #include "mozAutoDocUpdate.h"
34
35 class nsIDOMCSSStyleDeclaration;
36 class nsIDOMCSSStyleSheet;
37
38 using namespace mozilla;
39
40 #define NS_IF_CLONE(member_) \
41 PR_BEGIN_MACRO \
42 if (member_) { \
43 result->member_ = member_->Clone(); \
44 if (!result->member_) { \
45 delete result; \
46 return nullptr; \
47 } \
48 } \
49 PR_END_MACRO
50
51 #define NS_IF_DELETE(ptr) \
52 PR_BEGIN_MACRO \
53 delete ptr; \
54 ptr = nullptr; \
55 PR_END_MACRO
56
57 /* ************************************************************************** */
58
nsAtomList(nsIAtom * aAtom)59 nsAtomList::nsAtomList(nsIAtom* aAtom)
60 : mAtom(aAtom),
61 mNext(nullptr)
62 {
63 MOZ_COUNT_CTOR(nsAtomList);
64 }
65
nsAtomList(const nsString & aAtomValue)66 nsAtomList::nsAtomList(const nsString& aAtomValue)
67 : mAtom(nullptr),
68 mNext(nullptr)
69 {
70 MOZ_COUNT_CTOR(nsAtomList);
71 mAtom = NS_Atomize(aAtomValue);
72 }
73
74 nsAtomList*
Clone(bool aDeep) const75 nsAtomList::Clone(bool aDeep) const
76 {
77 nsAtomList *result = new nsAtomList(mAtom);
78 if (!result)
79 return nullptr;
80
81 if (aDeep)
82 NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
83 return result;
84 }
85
86 size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const87 nsAtomList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
88 {
89 size_t n = 0;
90 const nsAtomList* a = this;
91 while (a) {
92 n += aMallocSizeOf(a);
93
94 // The following members aren't measured:
95 // - a->mAtom, because it may be shared
96
97 a = a->mNext;
98 }
99 return n;
100 }
101
~nsAtomList(void)102 nsAtomList::~nsAtomList(void)
103 {
104 MOZ_COUNT_DTOR(nsAtomList);
105 NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
106 }
107
nsPseudoClassList(CSSPseudoClassType aType)108 nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType)
109 : mType(aType),
110 mNext(nullptr)
111 {
112 NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aType) &&
113 !nsCSSPseudoClasses::HasNthPairArg(aType),
114 "unexpected pseudo-class");
115 MOZ_COUNT_CTOR(nsPseudoClassList);
116 u.mMemory = nullptr;
117 }
118
nsPseudoClassList(CSSPseudoClassType aType,const char16_t * aString)119 nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
120 const char16_t* aString)
121 : mType(aType),
122 mNext(nullptr)
123 {
124 NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aType),
125 "unexpected pseudo-class");
126 NS_ASSERTION(aString, "string expected");
127 MOZ_COUNT_CTOR(nsPseudoClassList);
128 u.mString = NS_strdup(aString);
129 }
130
nsPseudoClassList(CSSPseudoClassType aType,const int32_t * aIntPair)131 nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
132 const int32_t* aIntPair)
133 : mType(aType),
134 mNext(nullptr)
135 {
136 NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aType),
137 "unexpected pseudo-class");
138 NS_ASSERTION(aIntPair, "integer pair expected");
139 MOZ_COUNT_CTOR(nsPseudoClassList);
140 u.mNumbers =
141 static_cast<int32_t*>(nsMemory::Clone(aIntPair, sizeof(int32_t) * 2));
142 }
143
144 // adopts aSelectorList
nsPseudoClassList(CSSPseudoClassType aType,nsCSSSelectorList * aSelectorList)145 nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
146 nsCSSSelectorList* aSelectorList)
147 : mType(aType),
148 mNext(nullptr)
149 {
150 NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType),
151 "unexpected pseudo-class");
152 NS_ASSERTION(aSelectorList, "selector list expected");
153 MOZ_COUNT_CTOR(nsPseudoClassList);
154 u.mSelectors = aSelectorList;
155 }
156
157 nsPseudoClassList*
Clone(bool aDeep) const158 nsPseudoClassList::Clone(bool aDeep) const
159 {
160 nsPseudoClassList *result;
161 if (!u.mMemory) {
162 result = new nsPseudoClassList(mType);
163 } else if (nsCSSPseudoClasses::HasStringArg(mType)) {
164 result = new nsPseudoClassList(mType, u.mString);
165 } else if (nsCSSPseudoClasses::HasNthPairArg(mType)) {
166 result = new nsPseudoClassList(mType, u.mNumbers);
167 } else {
168 NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType),
169 "unexpected pseudo-class");
170 // This constructor adopts its selector list argument.
171 result = new nsPseudoClassList(mType, u.mSelectors->Clone());
172 }
173
174 if (aDeep)
175 NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
176 (false));
177
178 return result;
179 }
180
181 size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const182 nsPseudoClassList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
183 {
184 size_t n = 0;
185 const nsPseudoClassList* p = this;
186 while (p) {
187 n += aMallocSizeOf(p);
188 if (!p->u.mMemory) {
189 // do nothing
190
191 } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
192 n += aMallocSizeOf(p->u.mString);
193
194 } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
195 n += aMallocSizeOf(p->u.mNumbers);
196
197 } else {
198 NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType),
199 "unexpected pseudo-class");
200 n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf);
201 }
202 p = p->mNext;
203 }
204 return n;
205 }
206
~nsPseudoClassList(void)207 nsPseudoClassList::~nsPseudoClassList(void)
208 {
209 MOZ_COUNT_DTOR(nsPseudoClassList);
210 if (nsCSSPseudoClasses::HasSelectorListArg(mType)) {
211 delete u.mSelectors;
212 } else if (u.mMemory) {
213 free(u.mMemory);
214 }
215 NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext);
216 }
217
nsAttrSelector(int32_t aNameSpace,const nsString & aAttr)218 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr)
219 : mValue(),
220 mNext(nullptr),
221 mLowercaseAttr(nullptr),
222 mCasedAttr(nullptr),
223 mNameSpace(aNameSpace),
224 mFunction(NS_ATTR_FUNC_SET),
225 // mValueCaseSensitivity doesn't matter; we have no value.
226 mValueCaseSensitivity(ValueCaseSensitivity::CaseSensitive)
227 {
228 MOZ_COUNT_CTOR(nsAttrSelector);
229
230 nsAutoString lowercase;
231 nsContentUtils::ASCIIToLower(aAttr, lowercase);
232
233 mCasedAttr = NS_Atomize(aAttr);
234 mLowercaseAttr = NS_Atomize(lowercase);
235 }
236
nsAttrSelector(int32_t aNameSpace,const nsString & aAttr,uint8_t aFunction,const nsString & aValue,ValueCaseSensitivity aValueCaseSensitivity)237 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
238 const nsString& aValue,
239 ValueCaseSensitivity aValueCaseSensitivity)
240 : mValue(aValue),
241 mNext(nullptr),
242 mLowercaseAttr(nullptr),
243 mCasedAttr(nullptr),
244 mNameSpace(aNameSpace),
245 mFunction(aFunction),
246 mValueCaseSensitivity(aValueCaseSensitivity)
247 {
248 MOZ_COUNT_CTOR(nsAttrSelector);
249
250 nsAutoString lowercase;
251 nsContentUtils::ASCIIToLower(aAttr, lowercase);
252
253 mCasedAttr = NS_Atomize(aAttr);
254 mLowercaseAttr = NS_Atomize(lowercase);
255 }
256
nsAttrSelector(int32_t aNameSpace,nsIAtom * aLowercaseAttr,nsIAtom * aCasedAttr,uint8_t aFunction,const nsString & aValue,ValueCaseSensitivity aValueCaseSensitivity)257 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr,
258 nsIAtom* aCasedAttr, uint8_t aFunction,
259 const nsString& aValue,
260 ValueCaseSensitivity aValueCaseSensitivity)
261 : mValue(aValue),
262 mNext(nullptr),
263 mLowercaseAttr(aLowercaseAttr),
264 mCasedAttr(aCasedAttr),
265 mNameSpace(aNameSpace),
266 mFunction(aFunction),
267 mValueCaseSensitivity(aValueCaseSensitivity)
268 {
269 MOZ_COUNT_CTOR(nsAttrSelector);
270 }
271
272 nsAttrSelector*
Clone(bool aDeep) const273 nsAttrSelector::Clone(bool aDeep) const
274 {
275 nsAttrSelector *result =
276 new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr,
277 mFunction, mValue, mValueCaseSensitivity);
278
279 if (aDeep)
280 NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false));
281
282 return result;
283 }
284
~nsAttrSelector(void)285 nsAttrSelector::~nsAttrSelector(void)
286 {
287 MOZ_COUNT_DTOR(nsAttrSelector);
288
289 NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext);
290 }
291
292 size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const293 nsAttrSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
294 {
295 size_t n = 0;
296 const nsAttrSelector* p = this;
297 while (p) {
298 n += aMallocSizeOf(p);
299 n += p->mValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
300 p = p->mNext;
301 }
302 return n;
303 }
304
305 // -- nsCSSSelector -------------------------------
306
nsCSSSelector(void)307 nsCSSSelector::nsCSSSelector(void)
308 : mLowercaseTag(nullptr),
309 mCasedTag(nullptr),
310 mIDList(nullptr),
311 mClassList(nullptr),
312 mPseudoClassList(nullptr),
313 mAttrList(nullptr),
314 mNegations(nullptr),
315 mNext(nullptr),
316 mNameSpace(kNameSpaceID_Unknown),
317 mOperator(0),
318 mPseudoType(CSSPseudoElementType::NotPseudo)
319 {
320 MOZ_COUNT_CTOR(nsCSSSelector);
321 }
322
323 nsCSSSelector*
Clone(bool aDeepNext,bool aDeepNegations) const324 nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
325 {
326 nsCSSSelector *result = new nsCSSSelector();
327 if (!result)
328 return nullptr;
329
330 result->mNameSpace = mNameSpace;
331 result->mLowercaseTag = mLowercaseTag;
332 result->mCasedTag = mCasedTag;
333 result->mOperator = mOperator;
334 result->mPseudoType = mPseudoType;
335
336 NS_IF_CLONE(mIDList);
337 NS_IF_CLONE(mClassList);
338 NS_IF_CLONE(mPseudoClassList);
339 NS_IF_CLONE(mAttrList);
340
341 // No need to worry about multiple levels of recursion since an
342 // mNegations can't have an mNext.
343 NS_ASSERTION(!mNegations || !mNegations->mNext,
344 "mNegations can't have non-null mNext");
345 if (aDeepNegations) {
346 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result,
347 (true, false));
348 }
349
350 if (aDeepNext) {
351 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result,
352 (false, true));
353 }
354
355 return result;
356 }
357
~nsCSSSelector(void)358 nsCSSSelector::~nsCSSSelector(void)
359 {
360 MOZ_COUNT_DTOR(nsCSSSelector);
361 Reset();
362 // No need to worry about multiple levels of recursion since an
363 // mNegations can't have an mNext.
364 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext);
365 }
366
Reset(void)367 void nsCSSSelector::Reset(void)
368 {
369 mNameSpace = kNameSpaceID_Unknown;
370 mLowercaseTag = nullptr;
371 mCasedTag = nullptr;
372 NS_IF_DELETE(mIDList);
373 NS_IF_DELETE(mClassList);
374 NS_IF_DELETE(mPseudoClassList);
375 NS_IF_DELETE(mAttrList);
376 // No need to worry about multiple levels of recursion since an
377 // mNegations can't have an mNext.
378 NS_ASSERTION(!mNegations || !mNegations->mNext,
379 "mNegations can't have non-null mNext");
380 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations);
381 mOperator = char16_t(0);
382 }
383
SetNameSpace(int32_t aNameSpace)384 void nsCSSSelector::SetNameSpace(int32_t aNameSpace)
385 {
386 mNameSpace = aNameSpace;
387 }
388
SetTag(const nsString & aTag)389 void nsCSSSelector::SetTag(const nsString& aTag)
390 {
391 if (aTag.IsEmpty()) {
392 mLowercaseTag = mCasedTag = nullptr;
393 return;
394 }
395
396 mCasedTag = NS_Atomize(aTag);
397
398 nsAutoString lowercase;
399 nsContentUtils::ASCIIToLower(aTag, lowercase);
400 mLowercaseTag = NS_Atomize(lowercase);
401 }
402
AddID(const nsString & aID)403 void nsCSSSelector::AddID(const nsString& aID)
404 {
405 if (!aID.IsEmpty()) {
406 nsAtomList** list = &mIDList;
407 while (nullptr != *list) {
408 list = &((*list)->mNext);
409 }
410 *list = new nsAtomList(aID);
411 }
412 }
413
AddClass(const nsString & aClass)414 void nsCSSSelector::AddClass(const nsString& aClass)
415 {
416 if (!aClass.IsEmpty()) {
417 nsAtomList** list = &mClassList;
418 while (nullptr != *list) {
419 list = &((*list)->mNext);
420 }
421 *list = new nsAtomList(aClass);
422 }
423 }
424
AddPseudoClass(CSSPseudoClassType aType)425 void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType)
426 {
427 AddPseudoClassInternal(new nsPseudoClassList(aType));
428 }
429
AddPseudoClass(CSSPseudoClassType aType,const char16_t * aString)430 void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
431 const char16_t* aString)
432 {
433 AddPseudoClassInternal(new nsPseudoClassList(aType, aString));
434 }
435
AddPseudoClass(CSSPseudoClassType aType,const int32_t * aIntPair)436 void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
437 const int32_t* aIntPair)
438 {
439 AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair));
440 }
441
AddPseudoClass(CSSPseudoClassType aType,nsCSSSelectorList * aSelectorList)442 void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
443 nsCSSSelectorList* aSelectorList)
444 {
445 // Take ownership of nsCSSSelectorList instead of copying.
446 AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList));
447 }
448
AddPseudoClassInternal(nsPseudoClassList * aPseudoClass)449 void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass)
450 {
451 nsPseudoClassList** list = &mPseudoClassList;
452 while (nullptr != *list) {
453 list = &((*list)->mNext);
454 }
455 *list = aPseudoClass;
456 }
457
AddAttribute(int32_t aNameSpace,const nsString & aAttr)458 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr)
459 {
460 if (!aAttr.IsEmpty()) {
461 nsAttrSelector** list = &mAttrList;
462 while (nullptr != *list) {
463 list = &((*list)->mNext);
464 }
465 *list = new nsAttrSelector(aNameSpace, aAttr);
466 }
467 }
468
AddAttribute(int32_t aNameSpace,const nsString & aAttr,uint8_t aFunc,const nsString & aValue,nsAttrSelector::ValueCaseSensitivity aCaseSensitivity)469 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
470 const nsString& aValue,
471 nsAttrSelector::ValueCaseSensitivity aCaseSensitivity)
472 {
473 if (!aAttr.IsEmpty()) {
474 nsAttrSelector** list = &mAttrList;
475 while (nullptr != *list) {
476 list = &((*list)->mNext);
477 }
478 *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitivity);
479 }
480 }
481
SetOperator(char16_t aOperator)482 void nsCSSSelector::SetOperator(char16_t aOperator)
483 {
484 mOperator = aOperator;
485 }
486
CalcWeightWithoutNegations() const487 int32_t nsCSSSelector::CalcWeightWithoutNegations() const
488 {
489 int32_t weight = 0;
490
491 #ifdef MOZ_XUL
492 MOZ_ASSERT(!(IsPseudoElement() &&
493 PseudoType() != CSSPseudoElementType::XULTree &&
494 mClassList),
495 "If non-XUL-tree pseudo-elements can have class selectors "
496 "after them, specificity calculation must be updated");
497 #else
498 MOZ_ASSERT(!(IsPseudoElement() && mClassList),
499 "If pseudo-elements can have class selectors "
500 "after them, specificity calculation must be updated");
501 #endif
502 MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
503 "If pseudo-elements can have id or attribute selectors "
504 "after them, specificity calculation must be updated");
505
506 if (nullptr != mCasedTag) {
507 weight += 0x000001;
508 }
509 nsAtomList* list = mIDList;
510 while (nullptr != list) {
511 weight += 0x010000;
512 list = list->mNext;
513 }
514 list = mClassList;
515 #ifdef MOZ_XUL
516 // XUL tree pseudo-elements abuse mClassList to store some private
517 // data; ignore that.
518 if (PseudoType() == CSSPseudoElementType::XULTree) {
519 list = nullptr;
520 }
521 #endif
522 while (nullptr != list) {
523 weight += 0x000100;
524 list = list->mNext;
525 }
526 // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't
527 // really a pseudo-class. In order to handle :-moz-any() correctly,
528 // we need to compute specificity after we match, based on which
529 // option we matched with (and thus also need to try the
530 // highest-specificity options first).
531 nsPseudoClassList *plist = mPseudoClassList;
532 while (nullptr != plist) {
533 weight += 0x000100;
534 plist = plist->mNext;
535 }
536 nsAttrSelector* attr = mAttrList;
537 while (nullptr != attr) {
538 weight += 0x000100;
539 attr = attr->mNext;
540 }
541 return weight;
542 }
543
CalcWeight() const544 int32_t nsCSSSelector::CalcWeight() const
545 {
546 // Loop over this selector and all its negations.
547 int32_t weight = 0;
548 for (const nsCSSSelector *n = this; n; n = n->mNegations) {
549 weight += n->CalcWeightWithoutNegations();
550 }
551 return weight;
552 }
553
554 //
555 // Builds the textual representation of a selector. Called by DOM 2 CSS
556 // StyleRule:selectorText
557 //
558 void
ToString(nsAString & aString,CSSStyleSheet * aSheet,bool aAppend) const559 nsCSSSelector::ToString(nsAString& aString, CSSStyleSheet* aSheet,
560 bool aAppend) const
561 {
562 if (!aAppend)
563 aString.Truncate();
564
565 // selectors are linked from right-to-left, so the next selector in
566 // the linked list actually precedes this one in the resulting string
567 AutoTArray<const nsCSSSelector*, 8> stack;
568 for (const nsCSSSelector *s = this; s; s = s->mNext) {
569 stack.AppendElement(s);
570 }
571
572 while (!stack.IsEmpty()) {
573 uint32_t index = stack.Length() - 1;
574 const nsCSSSelector *s = stack.ElementAt(index);
575 stack.RemoveElementAt(index);
576
577 s->AppendToStringWithoutCombinators(aString, aSheet, false);
578
579 // Append the combinator, if needed.
580 if (!stack.IsEmpty()) {
581 const nsCSSSelector *next = stack.ElementAt(index - 1);
582 char16_t oper = s->mOperator;
583 if (next->IsPseudoElement()) {
584 NS_ASSERTION(oper == char16_t(':'),
585 "improperly chained pseudo element");
586 } else {
587 NS_ASSERTION(oper != char16_t(0),
588 "compound selector without combinator");
589
590 aString.Append(char16_t(' '));
591 if (oper != char16_t(' ')) {
592 aString.Append(oper);
593 aString.Append(char16_t(' '));
594 }
595 }
596 }
597 }
598 }
599
600 void
AppendToStringWithoutCombinators(nsAString & aString,CSSStyleSheet * aSheet,bool aUseStandardNamespacePrefixes) const601 nsCSSSelector::AppendToStringWithoutCombinators(
602 nsAString& aString,
603 CSSStyleSheet* aSheet,
604 bool aUseStandardNamespacePrefixes) const
605 {
606 AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false,
607 aUseStandardNamespacePrefixes);
608
609 for (const nsCSSSelector* negation = mNegations; negation;
610 negation = negation->mNegations) {
611 aString.AppendLiteral(":not(");
612 negation->AppendToStringWithoutCombinatorsOrNegations(
613 aString, aSheet, true, aUseStandardNamespacePrefixes);
614 aString.Append(char16_t(')'));
615 }
616 }
617
618 #ifdef DEBUG
619 nsCString
RestrictedSelectorToString() const620 nsCSSSelector::RestrictedSelectorToString() const
621 {
622 MOZ_ASSERT(IsRestrictedSelector());
623
624 nsString result;
625 AppendToStringWithoutCombinators(result, nullptr, true);
626 return NS_ConvertUTF16toUTF8(result);
627 }
628
629 static bool
AppendStandardNamespacePrefixToString(nsAString & aString,int32_t aNameSpace)630 AppendStandardNamespacePrefixToString(nsAString& aString, int32_t aNameSpace)
631 {
632 if (aNameSpace == kNameSpaceID_Unknown) {
633 // Wildcard namespace; no prefix to write.
634 return false;
635 }
636 switch (aNameSpace) {
637 case kNameSpaceID_None:
638 break;
639 case kNameSpaceID_XML:
640 aString.AppendLiteral("xml");
641 break;
642 case kNameSpaceID_XHTML:
643 aString.AppendLiteral("html");
644 break;
645 case kNameSpaceID_XLink:
646 aString.AppendLiteral("xlink");
647 break;
648 case kNameSpaceID_XSLT:
649 aString.AppendLiteral("xsl");
650 break;
651 case kNameSpaceID_XBL:
652 aString.AppendLiteral("xbl");
653 break;
654 case kNameSpaceID_MathML:
655 aString.AppendLiteral("math");
656 break;
657 case kNameSpaceID_RDF:
658 aString.AppendLiteral("rdf");
659 break;
660 case kNameSpaceID_XUL:
661 aString.AppendLiteral("xul");
662 break;
663 case kNameSpaceID_SVG:
664 aString.AppendLiteral("svg");
665 break;
666 default:
667 aString.AppendLiteral("ns");
668 aString.AppendInt(aNameSpace);
669 break;
670 }
671 return true;
672 }
673 #endif
674
675 void
AppendToStringWithoutCombinatorsOrNegations(nsAString & aString,CSSStyleSheet * aSheet,bool aIsNegated,bool aUseStandardNamespacePrefixes) const676 nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
677 (nsAString& aString, CSSStyleSheet* aSheet,
678 bool aIsNegated,
679 bool aUseStandardNamespacePrefixes) const
680 {
681 nsAutoString temp;
682 bool isPseudoElement = IsPseudoElement();
683
684 // For non-pseudo-element selectors or for lone pseudo-elements, deal with
685 // namespace prefixes.
686 bool wroteNamespace = false;
687 if (!isPseudoElement || !mNext) {
688 // append the namespace prefix if needed
689 nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr;
690
691 // sheetNS is non-null if and only if we had an @namespace rule. If it's
692 // null, that means that the only namespaces we could have are the
693 // wildcard namespace (which can be implicit in this case) and the "none"
694 // namespace, which then needs to be explicitly specified.
695 if (aUseStandardNamespacePrefixes) {
696 #ifdef DEBUG
697 // We have no sheet to look up prefix information from. This is
698 // only for debugging, so use some "standard" prefixes that
699 // are recognizable.
700 wroteNamespace =
701 AppendStandardNamespacePrefixToString(aString, mNameSpace);
702 if (wroteNamespace) {
703 aString.Append(char16_t('|'));
704 }
705 #endif
706 } else if (!sheetNS) {
707 NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
708 mNameSpace == kNameSpaceID_None,
709 "How did we get this namespace?");
710 if (mNameSpace == kNameSpaceID_None) {
711 aString.Append(char16_t('|'));
712 wroteNamespace = true;
713 }
714 } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) {
715 // We have the default namespace (possibly including the wildcard
716 // namespace). Do nothing.
717 NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
718 CanBeNamespaced(aIsNegated),
719 "How did we end up with this namespace?");
720 } else if (mNameSpace == kNameSpaceID_None) {
721 NS_ASSERTION(CanBeNamespaced(aIsNegated),
722 "How did we end up with this namespace?");
723 aString.Append(char16_t('|'));
724 wroteNamespace = true;
725 } else if (mNameSpace != kNameSpaceID_Unknown) {
726 NS_ASSERTION(CanBeNamespaced(aIsNegated),
727 "How did we end up with this namespace?");
728 nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
729 NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
730 "without a prefix?");
731 nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom),
732 aString);
733 aString.Append(char16_t('|'));
734 wroteNamespace = true;
735 } else {
736 // A selector for an element in any namespace, while the default
737 // namespace is something else. :not() is special in that the default
738 // namespace is not implied for non-type selectors, so if this is a
739 // negated non-type selector we don't need to output an explicit wildcard
740 // namespace here, since those default to a wildcard namespace.
741 if (CanBeNamespaced(aIsNegated)) {
742 aString.AppendLiteral("*|");
743 wroteNamespace = true;
744 }
745 }
746 }
747
748 if (!mLowercaseTag) {
749 // Universal selector: avoid writing the universal selector when we
750 // can avoid it, especially since we're required to avoid it for the
751 // inside of :not()
752 if (wroteNamespace ||
753 (!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
754 (aIsNegated || !mNegations))) {
755 aString.Append(char16_t('*'));
756 }
757 } else {
758 // Append the tag name
759 nsAutoString tag;
760 (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
761 if (isPseudoElement) {
762 if (!mNext) {
763 // Lone pseudo-element selector -- toss in a wildcard type selector
764 // XXXldb Why?
765 aString.Append(char16_t('*'));
766 }
767 // While our atoms use one colon, most pseudo-elements require two
768 // colons (those not in CSS level 2) and all pseudo-elements allow
769 // two colons. So serialize to the non-deprecated two colon syntax.
770 aString.Append(char16_t(':'));
771 // This should not be escaped since (a) the pseudo-element string
772 // has a ":" that can't be escaped and (b) all pseudo-elements at
773 // this point are known, and therefore we know they don't need
774 // escaping.
775 aString.Append(tag);
776 } else {
777 nsStyleUtil::AppendEscapedCSSIdent(tag, aString);
778 }
779 }
780
781 // Append the id, if there is one
782 if (mIDList) {
783 nsAtomList* list = mIDList;
784 while (list != nullptr) {
785 list->mAtom->ToString(temp);
786 aString.Append(char16_t('#'));
787 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
788 list = list->mNext;
789 }
790 }
791
792 // Append each class in the linked list
793 if (mClassList) {
794 if (isPseudoElement) {
795 #ifdef MOZ_XUL
796 MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag),
797 "must be tree pseudo-element");
798
799 aString.Append(char16_t('('));
800 for (nsAtomList* list = mClassList; list; list = list->mNext) {
801 nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString);
802 aString.Append(char16_t(','));
803 }
804 // replace the final comma with a close-paren
805 aString.Replace(aString.Length() - 1, 1, char16_t(')'));
806 #else
807 NS_ERROR("Can't happen");
808 #endif
809 } else {
810 nsAtomList* list = mClassList;
811 while (list != nullptr) {
812 list->mAtom->ToString(temp);
813 aString.Append(char16_t('.'));
814 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
815 list = list->mNext;
816 }
817 }
818 }
819
820 // Append each attribute selector in the linked list
821 if (mAttrList) {
822 nsAttrSelector* list = mAttrList;
823 while (list != nullptr) {
824 aString.Append(char16_t('['));
825 // Append the namespace prefix
826 if (list->mNameSpace == kNameSpaceID_Unknown) {
827 aString.Append(char16_t('*'));
828 aString.Append(char16_t('|'));
829 } else if (list->mNameSpace != kNameSpaceID_None) {
830 if (aUseStandardNamespacePrefixes) {
831 #ifdef DEBUG
832 AppendStandardNamespacePrefixToString(aString, list->mNameSpace);
833 aString.Append(char16_t('|'));
834 #endif
835 } else if (aSheet) {
836 nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
837 nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
838 // Default namespaces don't apply to attribute selectors, so
839 // we must have a useful prefix.
840 NS_ASSERTION(prefixAtom,
841 "How did we end up with a namespace if the prefix "
842 "is unknown?");
843 nsAutoString prefix;
844 prefixAtom->ToString(prefix);
845 nsStyleUtil::AppendEscapedCSSIdent(prefix, aString);
846 aString.Append(char16_t('|'));
847 }
848 }
849 // Append the attribute name
850 list->mCasedAttr->ToString(temp);
851 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
852
853 if (list->mFunction != NS_ATTR_FUNC_SET) {
854 // Append the function
855 if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
856 aString.Append(char16_t('~'));
857 else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
858 aString.Append(char16_t('|'));
859 else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
860 aString.Append(char16_t('^'));
861 else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
862 aString.Append(char16_t('$'));
863 else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
864 aString.Append(char16_t('*'));
865
866 aString.Append(char16_t('='));
867
868 // Append the value
869 nsStyleUtil::AppendEscapedCSSString(list->mValue, aString);
870
871 if (list->mValueCaseSensitivity ==
872 nsAttrSelector::ValueCaseSensitivity::CaseInsensitive) {
873 aString.Append(NS_LITERAL_STRING(" i"));
874 }
875 }
876
877 aString.Append(char16_t(']'));
878
879 list = list->mNext;
880 }
881 }
882
883 // Append each pseudo-class in the linked list
884 for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) {
885 nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp);
886 // This should not be escaped since (a) the pseudo-class string
887 // has a ":" that can't be escaped and (b) all pseudo-classes at
888 // this point are known, and therefore we know they don't need
889 // escaping.
890 aString.Append(temp);
891 if (list->u.mMemory) {
892 aString.Append(char16_t('('));
893 if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
894 nsStyleUtil::AppendEscapedCSSIdent(
895 nsDependentString(list->u.mString), aString);
896 } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) {
897 int32_t a = list->u.mNumbers[0],
898 b = list->u.mNumbers[1];
899 temp.Truncate();
900 if (a != 0) {
901 if (a == -1) {
902 temp.Append(char16_t('-'));
903 } else if (a != 1) {
904 temp.AppendInt(a);
905 }
906 temp.Append(char16_t('n'));
907 }
908 if (b != 0 || a == 0) {
909 if (b >= 0 && a != 0) // check a != 0 for whether we printed above
910 temp.Append(char16_t('+'));
911 temp.AppendInt(b);
912 }
913 aString.Append(temp);
914 } else {
915 NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType),
916 "unexpected pseudo-class");
917 nsString tmp;
918 list->u.mSelectors->ToString(tmp, aSheet);
919 aString.Append(tmp);
920 }
921 aString.Append(char16_t(')'));
922 }
923 }
924 }
925
926 bool
CanBeNamespaced(bool aIsNegated) const927 nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
928 {
929 return !aIsNegated ||
930 (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
931 }
932
933 size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const934 nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
935 {
936 size_t n = 0;
937 const nsCSSSelector* s = this;
938 while (s) {
939 n += aMallocSizeOf(s);
940
941 #define MEASURE(x) n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
942
943 MEASURE(s->mIDList);
944 MEASURE(s->mClassList);
945 MEASURE(s->mPseudoClassList);
946 MEASURE(s->mNegations);
947 MEASURE(s->mAttrList);
948
949 // The following members aren't measured:
950 // - s->mLowercaseTag, because it's an atom and therefore shared
951 // - s->mCasedTag, because it's an atom and therefore shared
952
953 s = s->mNext;
954 }
955 return n;
956 }
957
958 // -- nsCSSSelectorList -------------------------------
959
nsCSSSelectorList(void)960 nsCSSSelectorList::nsCSSSelectorList(void)
961 : mSelectors(nullptr),
962 mWeight(0),
963 mNext(nullptr)
964 {
965 MOZ_COUNT_CTOR(nsCSSSelectorList);
966 }
967
~nsCSSSelectorList()968 nsCSSSelectorList::~nsCSSSelectorList()
969 {
970 MOZ_COUNT_DTOR(nsCSSSelectorList);
971 delete mSelectors;
972 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext);
973 }
974
975 nsCSSSelector*
AddSelector(char16_t aOperator)976 nsCSSSelectorList::AddSelector(char16_t aOperator)
977 {
978 nsCSSSelector* newSel = new nsCSSSelector();
979
980 if (mSelectors) {
981 NS_ASSERTION(aOperator != char16_t(0), "chaining without combinator");
982 mSelectors->SetOperator(aOperator);
983 } else {
984 NS_ASSERTION(aOperator == char16_t(0), "combinator without chaining");
985 }
986
987 newSel->mNext = mSelectors;
988 mSelectors = newSel;
989 return newSel;
990 }
991
992 void
RemoveRightmostSelector()993 nsCSSSelectorList::RemoveRightmostSelector()
994 {
995 nsCSSSelector* current = mSelectors;
996 mSelectors = mSelectors->mNext;
997 MOZ_ASSERT(mSelectors,
998 "Rightmost selector has been removed, but now "
999 "mSelectors is null");
1000 mSelectors->SetOperator(char16_t(0));
1001
1002 // Make sure that deleting current won't delete the whole list.
1003 current->mNext = nullptr;
1004 delete current;
1005 }
1006
1007 void
ToString(nsAString & aResult,CSSStyleSheet * aSheet)1008 nsCSSSelectorList::ToString(nsAString& aResult, CSSStyleSheet* aSheet)
1009 {
1010 aResult.Truncate();
1011 nsCSSSelectorList *p = this;
1012 for (;;) {
1013 p->mSelectors->ToString(aResult, aSheet, true);
1014 p = p->mNext;
1015 if (!p)
1016 break;
1017 aResult.AppendLiteral(", ");
1018 }
1019 }
1020
1021 nsCSSSelectorList*
Clone(bool aDeep) const1022 nsCSSSelectorList::Clone(bool aDeep) const
1023 {
1024 nsCSSSelectorList *result = new nsCSSSelectorList();
1025 result->mWeight = mWeight;
1026 NS_IF_CLONE(mSelectors);
1027
1028 if (aDeep) {
1029 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
1030 (false));
1031 }
1032 return result;
1033 }
1034
1035 size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const1036 nsCSSSelectorList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1037 {
1038 size_t n = 0;
1039 const nsCSSSelectorList* s = this;
1040 while (s) {
1041 n += aMallocSizeOf(s);
1042 n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
1043 s = s->mNext;
1044 }
1045 return n;
1046 }
1047
1048 // --------------------------------------------------------
1049
1050 namespace mozilla {
1051 namespace css {
1052 class DOMCSSStyleRule;
1053 } // namespace css
1054 } // namespace mozilla
1055
1056 class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
1057 {
1058 protected:
1059 virtual ~DOMCSSDeclarationImpl(void);
1060
1061 public:
1062 explicit DOMCSSDeclarationImpl(css::StyleRule *aRule);
1063
1064 NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) override;
1065 void DropReference(void);
1066 virtual DeclarationBlock* GetCSSDeclaration(Operation aOperation) override;
1067 virtual nsresult SetCSSDeclaration(DeclarationBlock* aDecl) override;
1068 virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) override;
1069 virtual nsIDocument* DocToUpdate() override;
1070
1071 // Override |AddRef| and |Release| for being a member of
1072 // |DOMCSSStyleRule|. Also, we need to forward QI for cycle
1073 // collection things to DOMCSSStyleRule.
1074 NS_DECL_ISUPPORTS_INHERITED
1075
GetParentObject()1076 virtual nsINode *GetParentObject() override
1077 {
1078 return mRule ? mRule->GetDocument() : nullptr;
1079 }
1080
1081 friend class css::DOMCSSStyleRule;
1082
1083 protected:
1084 // This reference is not reference-counted. The rule object tells us
1085 // when it's about to go away.
1086 css::StyleRule *mRule;
1087
1088 inline css::DOMCSSStyleRule* DomRule();
1089
1090 private:
1091 // NOT TO BE IMPLEMENTED
1092 // This object cannot be allocated on its own. It must be a member of
1093 // DOMCSSStyleRule.
1094 void* operator new(size_t size) CPP_THROW_NEW;
1095 };
1096
1097 namespace mozilla {
1098 namespace css {
1099
1100 class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper
1101 {
1102 public:
1103 explicit DOMCSSStyleRule(StyleRule *aRule);
1104
1105 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1106 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCSSStyleRule)
1107 NS_DECL_NSIDOMCSSRULE
1108 NS_DECL_NSIDOMCSSSTYLERULE
1109
1110 // nsICSSStyleRuleDOMWrapper
1111 NS_IMETHOD GetCSSStyleRule(StyleRule **aResult) override;
1112
DOMDeclaration()1113 DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
1114
1115 friend class ::DOMCSSDeclarationImpl;
1116
1117 protected:
1118 virtual ~DOMCSSStyleRule();
1119
1120 DOMCSSDeclarationImpl mDOMDeclaration;
1121
Rule()1122 StyleRule* Rule() {
1123 return mDOMDeclaration.mRule;
1124 }
1125 };
1126
1127 } // namespace css
1128 } // namespace mozilla
1129
DOMCSSDeclarationImpl(css::StyleRule * aRule)1130 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
1131 : mRule(aRule)
1132 {
1133 MOZ_COUNT_CTOR(DOMCSSDeclarationImpl);
1134 }
1135
~DOMCSSDeclarationImpl(void)1136 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
1137 {
1138 NS_ASSERTION(!mRule, "DropReference not called.");
1139
1140 MOZ_COUNT_DTOR(DOMCSSDeclarationImpl);
1141 }
1142
DomRule()1143 inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule()
1144 {
1145 return reinterpret_cast<css::DOMCSSStyleRule*>
1146 (reinterpret_cast<char*>(this) -
1147 offsetof(css::DOMCSSStyleRule, mDOMDeclaration));
1148 }
1149
1150 NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1151 NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1152
1153 NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl)
1154 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1155 // We forward the cycle collection interfaces to DomRule(), which is
1156 // never null (in fact, we're part of that object!)
1157 if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
1158 aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
1159 return DomRule()->QueryInterface(aIID, aInstancePtr);
1160 }
1161 else
NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)1162 NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
1163
1164 void
1165 DOMCSSDeclarationImpl::DropReference(void)
1166 {
1167 mRule = nullptr;
1168 }
1169
1170 DeclarationBlock*
GetCSSDeclaration(Operation aOperation)1171 DOMCSSDeclarationImpl::GetCSSDeclaration(Operation aOperation)
1172 {
1173 if (mRule) {
1174 if (aOperation != eOperation_Read) {
1175 RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
1176 if (sheet) {
1177 sheet->WillDirty();
1178 }
1179 }
1180 return mRule->GetDeclaration();
1181 } else {
1182 return nullptr;
1183 }
1184 }
1185
1186 void
GetCSSParsingEnvironment(CSSParsingEnvironment & aCSSParseEnv)1187 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
1188 {
1189 GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
1190 }
1191
1192 NS_IMETHODIMP
GetParentRule(nsIDOMCSSRule ** aParent)1193 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
1194 {
1195 NS_ENSURE_ARG_POINTER(aParent);
1196
1197 if (!mRule) {
1198 *aParent = nullptr;
1199 return NS_OK;
1200 }
1201
1202 NS_IF_ADDREF(*aParent = mRule->GetDOMRule());
1203 return NS_OK;
1204 }
1205
1206 nsresult
SetCSSDeclaration(DeclarationBlock * aDecl)1207 DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
1208 {
1209 NS_PRECONDITION(mRule,
1210 "can only be called when |GetCSSDeclaration| returned a declaration");
1211
1212 nsCOMPtr<nsIDocument> owningDoc;
1213 RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
1214 if (sheet) {
1215 owningDoc = sheet->GetOwningDocument();
1216 }
1217
1218 mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
1219
1220 mRule->SetDeclaration(aDecl->AsGecko());
1221
1222 if (sheet) {
1223 sheet->DidDirty();
1224 }
1225
1226 if (owningDoc) {
1227 owningDoc->StyleRuleChanged(sheet, mRule);
1228 }
1229 return NS_OK;
1230 }
1231
1232 nsIDocument*
DocToUpdate()1233 DOMCSSDeclarationImpl::DocToUpdate()
1234 {
1235 return nullptr;
1236 }
1237
1238 namespace mozilla {
1239 namespace css {
1240
DOMCSSStyleRule(StyleRule * aRule)1241 DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule)
1242 : mDOMDeclaration(aRule)
1243 {
1244 }
1245
~DOMCSSStyleRule()1246 DOMCSSStyleRule::~DOMCSSStyleRule()
1247 {
1248 }
1249
1250 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCSSStyleRule)
1251 NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
1252 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
1253 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
1254 NS_INTERFACE_MAP_ENTRY(nsISupports)
1255 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
1256 NS_INTERFACE_MAP_END
1257
1258 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCSSStyleRule)
1259 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCSSStyleRule)
1260
1261 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMCSSStyleRule)
1262
1263 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMCSSStyleRule)
1264 // Trace the wrapper for our declaration. This just expands out
1265 // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
1266 // directly because the wrapper is on the declaration, not on us.
1267 tmp->DOMDeclaration()->TraceWrapper(aCallbacks, aClosure);
1268 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1269
1270 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMCSSStyleRule)
1271 // Unlink the wrapper for our declaraton. This just expands out
1272 // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
1273 // directly because the wrapper is on the declaration, not on us.
1274 tmp->DOMDeclaration()->ReleaseWrapper(static_cast<nsISupports*>(p));
1275 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1276
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule)1277 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule)
1278 // Just NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS here: that will call
1279 // into our Trace hook, where we do the right thing with declarations
1280 // already.
1281 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1282 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1283
1284 NS_IMETHODIMP
1285 DOMCSSStyleRule::GetType(uint16_t* aType)
1286 {
1287 *aType = nsIDOMCSSRule::STYLE_RULE;
1288
1289 return NS_OK;
1290 }
1291
1292 NS_IMETHODIMP
GetCssText(nsAString & aCssText)1293 DOMCSSStyleRule::GetCssText(nsAString& aCssText)
1294 {
1295 if (!Rule()) {
1296 aCssText.Truncate();
1297 } else {
1298 Rule()->GetCssText(aCssText);
1299 }
1300 return NS_OK;
1301 }
1302
1303 NS_IMETHODIMP
SetCssText(const nsAString & aCssText)1304 DOMCSSStyleRule::SetCssText(const nsAString& aCssText)
1305 {
1306 if (Rule()) {
1307 Rule()->SetCssText(aCssText);
1308 }
1309 return NS_OK;
1310 }
1311
1312 NS_IMETHODIMP
GetParentStyleSheet(nsIDOMCSSStyleSheet ** aSheet)1313 DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
1314 {
1315 if (!Rule()) {
1316 *aSheet = nullptr;
1317 return NS_OK;
1318 }
1319 return Rule()->GetParentStyleSheet(aSheet);
1320 }
1321
1322 NS_IMETHODIMP
GetParentRule(nsIDOMCSSRule ** aParentRule)1323 DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
1324 {
1325 if (!Rule()) {
1326 *aParentRule = nullptr;
1327 return NS_OK;
1328 }
1329 return Rule()->GetParentRule(aParentRule);
1330 }
1331
1332 css::Rule*
GetCSSRule()1333 DOMCSSStyleRule::GetCSSRule()
1334 {
1335 return Rule();
1336 }
1337
1338 NS_IMETHODIMP
GetSelectorText(nsAString & aSelectorText)1339 DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText)
1340 {
1341 if (!Rule()) {
1342 aSelectorText.Truncate();
1343 } else {
1344 Rule()->GetSelectorText(aSelectorText);
1345 }
1346 return NS_OK;
1347 }
1348
1349 NS_IMETHODIMP
SetSelectorText(const nsAString & aSelectorText)1350 DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText)
1351 {
1352 if (Rule()) {
1353 Rule()->SetSelectorText(aSelectorText);
1354 }
1355 return NS_OK;
1356 }
1357
1358 NS_IMETHODIMP
GetStyle(nsIDOMCSSStyleDeclaration ** aStyle)1359 DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
1360 {
1361 *aStyle = &mDOMDeclaration;
1362 NS_ADDREF(*aStyle);
1363 return NS_OK;
1364 }
1365
1366 NS_IMETHODIMP
GetCSSStyleRule(StyleRule ** aResult)1367 DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult)
1368 {
1369 *aResult = Rule();
1370 NS_IF_ADDREF(*aResult);
1371 return NS_OK;
1372 }
1373
1374 } // namespace css
1375 } // namespace mozilla
1376
1377 // -- StyleRule ------------------------------------
1378
1379 namespace mozilla {
1380 namespace css {
1381
StyleRule(nsCSSSelectorList * aSelector,Declaration * aDeclaration,uint32_t aLineNumber,uint32_t aColumnNumber)1382 StyleRule::StyleRule(nsCSSSelectorList* aSelector,
1383 Declaration* aDeclaration,
1384 uint32_t aLineNumber,
1385 uint32_t aColumnNumber)
1386 : Rule(aLineNumber, aColumnNumber),
1387 mSelector(aSelector),
1388 mDeclaration(aDeclaration)
1389 {
1390 NS_PRECONDITION(aDeclaration, "must have a declaration");
1391
1392 mDeclaration->SetOwningRule(this);
1393 }
1394
1395 // for |Clone|
StyleRule(const StyleRule & aCopy)1396 StyleRule::StyleRule(const StyleRule& aCopy)
1397 : Rule(aCopy),
1398 mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr),
1399 mDeclaration(new Declaration(*aCopy.mDeclaration))
1400 {
1401 mDeclaration->SetOwningRule(this);
1402 // rest is constructed lazily on existing data
1403 }
1404
~StyleRule()1405 StyleRule::~StyleRule()
1406 {
1407 delete mSelector;
1408 if (mDOMRule) {
1409 mDOMRule->DOMDeclaration()->DropReference();
1410 }
1411
1412 if (mDeclaration) {
1413 mDeclaration->SetOwningRule(nullptr);
1414 }
1415 }
1416
1417 // QueryInterface implementation for StyleRule
1418 NS_INTERFACE_MAP_BEGIN(StyleRule)
1419 if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
1420 *aInstancePtr = this;
1421 NS_ADDREF_THIS();
1422 return NS_OK;
1423 }
1424 else
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,mozilla::css::Rule)1425 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
1426 NS_INTERFACE_MAP_END
1427
1428 NS_IMPL_ADDREF(StyleRule)
1429 NS_IMPL_RELEASE(StyleRule)
1430
1431 /* virtual */ int32_t
1432 StyleRule::GetType() const
1433 {
1434 return Rule::STYLE_RULE;
1435 }
1436
1437 /* virtual */ already_AddRefed<Rule>
Clone() const1438 StyleRule::Clone() const
1439 {
1440 RefPtr<Rule> clone = new StyleRule(*this);
1441 return clone.forget();
1442 }
1443
1444 /* virtual */ nsIDOMCSSRule*
GetDOMRule()1445 StyleRule::GetDOMRule()
1446 {
1447 if (!mDOMRule) {
1448 if (!GetStyleSheet()) {
1449 // Inline style rules aren't supposed to have a DOM rule object, only
1450 // a declaration. But if we do have one already, from a style sheet
1451 // rule that used to be in a document, we still want to return it.
1452 return nullptr;
1453 }
1454 mDOMRule = new DOMCSSStyleRule(this);
1455 }
1456 return mDOMRule;
1457 }
1458
1459 /* virtual */ nsIDOMCSSRule*
GetExistingDOMRule()1460 StyleRule::GetExistingDOMRule()
1461 {
1462 return mDOMRule;
1463 }
1464
1465 void
SetDeclaration(Declaration * aDecl)1466 StyleRule::SetDeclaration(Declaration* aDecl)
1467 {
1468 if (aDecl == mDeclaration) {
1469 return;
1470 }
1471 mDeclaration->SetOwningRule(nullptr);
1472 mDeclaration = aDecl;
1473 mDeclaration->SetOwningRule(this);
1474 }
1475
1476 #ifdef DEBUG
1477 /* virtual */ void
List(FILE * out,int32_t aIndent) const1478 StyleRule::List(FILE* out, int32_t aIndent) const
1479 {
1480 nsAutoCString str;
1481 // Indent
1482 for (int32_t index = aIndent; --index >= 0; ) {
1483 str.AppendLiteral(" ");
1484 }
1485
1486 if (mSelector) {
1487 nsAutoString buffer;
1488 mSelector->ToString(buffer, GetStyleSheet());
1489 AppendUTF16toUTF8(buffer, str);
1490 str.Append(' ');
1491 }
1492
1493 if (nullptr != mDeclaration) {
1494 nsAutoString buffer;
1495 str.AppendLiteral("{ ");
1496 mDeclaration->ToString(buffer);
1497 AppendUTF16toUTF8(buffer, str);
1498 str.Append('}');
1499 CSSStyleSheet* sheet = GetStyleSheet();
1500 if (sheet) {
1501 nsIURI* uri = sheet->GetSheetURI();
1502 if (uri) {
1503 str.Append(" /* ");
1504 str.Append(uri->GetSpecOrDefault());
1505 str.Append(':');
1506 str.AppendInt(mLineNumber);
1507 str.Append(" */");
1508 }
1509 }
1510 }
1511 else {
1512 str.AppendLiteral("{ null declaration }");
1513 }
1514 str.Append('\n');
1515 fprintf_stderr(out, "%s", str.get());
1516 }
1517 #endif
1518
1519 void
GetCssText(nsAString & aCssText)1520 StyleRule::GetCssText(nsAString& aCssText)
1521 {
1522 if (mSelector) {
1523 mSelector->ToString(aCssText, GetStyleSheet());
1524 aCssText.Append(char16_t(' '));
1525 }
1526 aCssText.Append(char16_t('{'));
1527 aCssText.Append(char16_t(' '));
1528 if (mDeclaration)
1529 {
1530 nsAutoString tempString;
1531 mDeclaration->ToString( tempString );
1532 aCssText.Append( tempString );
1533 }
1534 aCssText.Append(char16_t(' '));
1535 aCssText.Append(char16_t('}'));
1536 }
1537
1538 void
SetCssText(const nsAString & aCssText)1539 StyleRule::SetCssText(const nsAString& aCssText)
1540 {
1541 // XXX TBI - need to re-parse rule & declaration
1542 }
1543
1544 void
GetSelectorText(nsAString & aSelectorText)1545 StyleRule::GetSelectorText(nsAString& aSelectorText)
1546 {
1547 if (mSelector)
1548 mSelector->ToString(aSelectorText, GetStyleSheet());
1549 else
1550 aSelectorText.Truncate();
1551 }
1552
1553 void
SetSelectorText(const nsAString & aSelectorText)1554 StyleRule::SetSelectorText(const nsAString& aSelectorText)
1555 {
1556 // XXX TBI - get a parser and re-parse the selectors,
1557 // XXX then need to re-compute the cascade
1558 // XXX and dirty sheet
1559 }
1560
1561 /* virtual */ size_t
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const1562 StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1563 {
1564 size_t n = aMallocSizeOf(this);
1565 n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
1566 n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
1567
1568 // Measurement of the following members may be added later if DMD finds it is
1569 // worthwhile:
1570 // - mDOMRule;
1571
1572 return n;
1573 }
1574
1575
1576 } // namespace css
1577 } // namespace mozilla
1578