Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
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/. */
6 /*
7 * representation of CSS style rules (selectors+declaration), CSS
8 * selectors, and DOM objects for style rules, selectors, and
9 * declarations
10 */
12 #include "mozilla/css/StyleRule.h"
14 #include "mozilla/MemoryReporting.h"
15 #include "mozilla/css/GroupRule.h"
16 #include "mozilla/css/Declaration.h"
17 #include "nsCSSStyleSheet.h"
18 #include "nsIDocument.h"
19 #include "nsIAtom.h"
20 #include "nsString.h"
21 #include "nsStyleUtil.h"
22 #include "nsICSSStyleRuleDOMWrapper.h"
23 #include "nsDOMCSSDeclaration.h"
24 #include "nsNameSpaceManager.h"
25 #include "nsXMLNameSpaceMap.h"
26 #include "nsCSSPseudoElements.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"
35 class nsIDOMCSSStyleDeclaration;
36 class nsIDOMCSSStyleSheet;
38 using namespace mozilla;
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
51 #define NS_IF_DELETE(ptr) \
52 PR_BEGIN_MACRO \
53 delete ptr; \
54 ptr = nullptr; \
55 PR_END_MACRO
57 /* ************************************************************************** */
59 nsAtomList::nsAtomList(nsIAtom* aAtom)
60 : mAtom(aAtom),
61 mNext(nullptr)
62 {
63 MOZ_COUNT_CTOR(nsAtomList);
64 }
66 nsAtomList::nsAtomList(const nsString& aAtomValue)
67 : mAtom(nullptr),
68 mNext(nullptr)
69 {
70 MOZ_COUNT_CTOR(nsAtomList);
71 mAtom = do_GetAtom(aAtomValue);
72 }
74 nsAtomList*
75 nsAtomList::Clone(bool aDeep) const
76 {
77 nsAtomList *result = new nsAtomList(mAtom);
78 if (!result)
79 return nullptr;
81 if (aDeep)
82 NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
83 return result;
84 }
86 size_t
87 nsAtomList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
88 {
89 size_t n = 0;
90 const nsAtomList* a = this;
91 while (a) {
92 n += aMallocSizeOf(a);
94 // The following members aren't measured:
95 // - a->mAtom, because it may be shared
97 a = a->mNext;
98 }
99 return n;
100 }
102 nsAtomList::~nsAtomList(void)
103 {
104 MOZ_COUNT_DTOR(nsAtomList);
105 NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
106 }
108 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type 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 }
119 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type 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 }
131 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type 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 }
144 // adopts aSelectorList
145 nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type 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 }
157 nsPseudoClassList*
158 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 }
174 if (aDeep)
175 NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
176 (false));
178 return result;
179 }
181 size_t
182 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
191 } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
192 n += aMallocSizeOf(p->u.mString);
194 } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
195 n += aMallocSizeOf(p->u.mNumbers);
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 }
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 NS_Free(u.mMemory);
214 }
215 NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext);
216 }
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 mCaseSensitive(1)
226 {
227 MOZ_COUNT_CTOR(nsAttrSelector);
229 nsAutoString lowercase;
230 nsContentUtils::ASCIIToLower(aAttr, lowercase);
232 mCasedAttr = do_GetAtom(aAttr);
233 mLowercaseAttr = do_GetAtom(lowercase);
234 }
236 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
237 const nsString& aValue, bool aCaseSensitive)
238 : mValue(aValue),
239 mNext(nullptr),
240 mLowercaseAttr(nullptr),
241 mCasedAttr(nullptr),
242 mNameSpace(aNameSpace),
243 mFunction(aFunction),
244 mCaseSensitive(aCaseSensitive)
245 {
246 MOZ_COUNT_CTOR(nsAttrSelector);
248 nsAutoString lowercase;
249 nsContentUtils::ASCIIToLower(aAttr, lowercase);
251 mCasedAttr = do_GetAtom(aAttr);
252 mLowercaseAttr = do_GetAtom(lowercase);
253 }
255 nsAttrSelector::nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr,
256 nsIAtom* aCasedAttr, uint8_t aFunction,
257 const nsString& aValue, bool aCaseSensitive)
258 : mValue(aValue),
259 mNext(nullptr),
260 mLowercaseAttr(aLowercaseAttr),
261 mCasedAttr(aCasedAttr),
262 mNameSpace(aNameSpace),
263 mFunction(aFunction),
264 mCaseSensitive(aCaseSensitive)
265 {
266 MOZ_COUNT_CTOR(nsAttrSelector);
267 }
269 nsAttrSelector*
270 nsAttrSelector::Clone(bool aDeep) const
271 {
272 nsAttrSelector *result =
273 new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr,
274 mFunction, mValue, mCaseSensitive);
276 if (aDeep)
277 NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false));
279 return result;
280 }
282 nsAttrSelector::~nsAttrSelector(void)
283 {
284 MOZ_COUNT_DTOR(nsAttrSelector);
286 NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext);
287 }
289 // -- nsCSSSelector -------------------------------
291 nsCSSSelector::nsCSSSelector(void)
292 : mLowercaseTag(nullptr),
293 mCasedTag(nullptr),
294 mIDList(nullptr),
295 mClassList(nullptr),
296 mPseudoClassList(nullptr),
297 mAttrList(nullptr),
298 mNegations(nullptr),
299 mNext(nullptr),
300 mNameSpace(kNameSpaceID_Unknown),
301 mOperator(0),
302 mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement)
303 {
304 MOZ_COUNT_CTOR(nsCSSSelector);
305 static_assert(nsCSSPseudoElements::ePseudo_MAX < INT16_MAX,
306 "nsCSSPseudoElements::Type values overflow mPseudoType");
307 }
309 nsCSSSelector*
310 nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
311 {
312 nsCSSSelector *result = new nsCSSSelector();
313 if (!result)
314 return nullptr;
316 result->mNameSpace = mNameSpace;
317 result->mLowercaseTag = mLowercaseTag;
318 result->mCasedTag = mCasedTag;
319 result->mOperator = mOperator;
320 result->mPseudoType = mPseudoType;
322 NS_IF_CLONE(mIDList);
323 NS_IF_CLONE(mClassList);
324 NS_IF_CLONE(mPseudoClassList);
325 NS_IF_CLONE(mAttrList);
327 // No need to worry about multiple levels of recursion since an
328 // mNegations can't have an mNext.
329 NS_ASSERTION(!mNegations || !mNegations->mNext,
330 "mNegations can't have non-null mNext");
331 if (aDeepNegations) {
332 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result,
333 (true, false));
334 }
336 if (aDeepNext) {
337 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result,
338 (false, true));
339 }
341 return result;
342 }
344 nsCSSSelector::~nsCSSSelector(void)
345 {
346 MOZ_COUNT_DTOR(nsCSSSelector);
347 Reset();
348 // No need to worry about multiple levels of recursion since an
349 // mNegations can't have an mNext.
350 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext);
351 }
353 void nsCSSSelector::Reset(void)
354 {
355 mNameSpace = kNameSpaceID_Unknown;
356 mLowercaseTag = nullptr;
357 mCasedTag = nullptr;
358 NS_IF_DELETE(mIDList);
359 NS_IF_DELETE(mClassList);
360 NS_IF_DELETE(mPseudoClassList);
361 NS_IF_DELETE(mAttrList);
362 // No need to worry about multiple levels of recursion since an
363 // mNegations can't have an mNext.
364 NS_ASSERTION(!mNegations || !mNegations->mNext,
365 "mNegations can't have non-null mNext");
366 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations);
367 mOperator = char16_t(0);
368 }
370 void nsCSSSelector::SetNameSpace(int32_t aNameSpace)
371 {
372 mNameSpace = aNameSpace;
373 }
375 void nsCSSSelector::SetTag(const nsString& aTag)
376 {
377 if (aTag.IsEmpty()) {
378 mLowercaseTag = mCasedTag = nullptr;
379 return;
380 }
382 mCasedTag = do_GetAtom(aTag);
384 nsAutoString lowercase;
385 nsContentUtils::ASCIIToLower(aTag, lowercase);
386 mLowercaseTag = do_GetAtom(lowercase);
387 }
389 void nsCSSSelector::AddID(const nsString& aID)
390 {
391 if (!aID.IsEmpty()) {
392 nsAtomList** list = &mIDList;
393 while (nullptr != *list) {
394 list = &((*list)->mNext);
395 }
396 *list = new nsAtomList(aID);
397 }
398 }
400 void nsCSSSelector::AddClass(const nsString& aClass)
401 {
402 if (!aClass.IsEmpty()) {
403 nsAtomList** list = &mClassList;
404 while (nullptr != *list) {
405 list = &((*list)->mNext);
406 }
407 *list = new nsAtomList(aClass);
408 }
409 }
411 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType)
412 {
413 AddPseudoClassInternal(new nsPseudoClassList(aType));
414 }
416 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
417 const char16_t* aString)
418 {
419 AddPseudoClassInternal(new nsPseudoClassList(aType, aString));
420 }
422 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
423 const int32_t* aIntPair)
424 {
425 AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair));
426 }
428 void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
429 nsCSSSelectorList* aSelectorList)
430 {
431 // Take ownership of nsCSSSelectorList instead of copying.
432 AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList));
433 }
435 void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass)
436 {
437 nsPseudoClassList** list = &mPseudoClassList;
438 while (nullptr != *list) {
439 list = &((*list)->mNext);
440 }
441 *list = aPseudoClass;
442 }
444 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr)
445 {
446 if (!aAttr.IsEmpty()) {
447 nsAttrSelector** list = &mAttrList;
448 while (nullptr != *list) {
449 list = &((*list)->mNext);
450 }
451 *list = new nsAttrSelector(aNameSpace, aAttr);
452 }
453 }
455 void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
456 const nsString& aValue, bool aCaseSensitive)
457 {
458 if (!aAttr.IsEmpty()) {
459 nsAttrSelector** list = &mAttrList;
460 while (nullptr != *list) {
461 list = &((*list)->mNext);
462 }
463 *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitive);
464 }
465 }
467 void nsCSSSelector::SetOperator(char16_t aOperator)
468 {
469 mOperator = aOperator;
470 }
472 int32_t nsCSSSelector::CalcWeightWithoutNegations() const
473 {
474 int32_t weight = 0;
476 #ifdef MOZ_XUL
477 MOZ_ASSERT(!(IsPseudoElement() &&
478 PseudoType() != nsCSSPseudoElements::ePseudo_XULTree &&
479 mClassList),
480 "If non-XUL-tree pseudo-elements can have class selectors "
481 "after them, specificity calculation must be updated");
482 #else
483 MOZ_ASSERT(!(IsPseudoElement() && mClassList),
484 "If pseudo-elements can have class selectors "
485 "after them, specificity calculation must be updated");
486 #endif
487 MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
488 "If pseudo-elements can have id or attribute selectors "
489 "after them, specificity calculation must be updated");
491 if (nullptr != mCasedTag) {
492 weight += 0x000001;
493 }
494 nsAtomList* list = mIDList;
495 while (nullptr != list) {
496 weight += 0x010000;
497 list = list->mNext;
498 }
499 list = mClassList;
500 #ifdef MOZ_XUL
501 // XUL tree pseudo-elements abuse mClassList to store some private
502 // data; ignore that.
503 if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) {
504 list = nullptr;
505 }
506 #endif
507 while (nullptr != list) {
508 weight += 0x000100;
509 list = list->mNext;
510 }
511 // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't
512 // really a pseudo-class. In order to handle :-moz-any() correctly,
513 // we need to compute specificity after we match, based on which
514 // option we matched with (and thus also need to try the
515 // highest-specificity options first).
516 nsPseudoClassList *plist = mPseudoClassList;
517 while (nullptr != plist) {
518 weight += 0x000100;
519 plist = plist->mNext;
520 }
521 nsAttrSelector* attr = mAttrList;
522 while (nullptr != attr) {
523 weight += 0x000100;
524 attr = attr->mNext;
525 }
526 return weight;
527 }
529 int32_t nsCSSSelector::CalcWeight() const
530 {
531 // Loop over this selector and all its negations.
532 int32_t weight = 0;
533 for (const nsCSSSelector *n = this; n; n = n->mNegations) {
534 weight += n->CalcWeightWithoutNegations();
535 }
536 return weight;
537 }
539 //
540 // Builds the textual representation of a selector. Called by DOM 2 CSS
541 // StyleRule:selectorText
542 //
543 void
544 nsCSSSelector::ToString(nsAString& aString, nsCSSStyleSheet* aSheet,
545 bool aAppend) const
546 {
547 if (!aAppend)
548 aString.Truncate();
550 // selectors are linked from right-to-left, so the next selector in
551 // the linked list actually precedes this one in the resulting string
552 nsAutoTArray<const nsCSSSelector*, 8> stack;
553 for (const nsCSSSelector *s = this; s; s = s->mNext) {
554 stack.AppendElement(s);
555 }
557 while (!stack.IsEmpty()) {
558 uint32_t index = stack.Length() - 1;
559 const nsCSSSelector *s = stack.ElementAt(index);
560 stack.RemoveElementAt(index);
562 s->AppendToStringWithoutCombinators(aString, aSheet);
564 // Append the combinator, if needed.
565 if (!stack.IsEmpty()) {
566 const nsCSSSelector *next = stack.ElementAt(index - 1);
567 char16_t oper = s->mOperator;
568 if (next->IsPseudoElement()) {
569 NS_ASSERTION(oper == char16_t(':'),
570 "improperly chained pseudo element");
571 } else {
572 NS_ASSERTION(oper != char16_t(0),
573 "compound selector without combinator");
575 aString.Append(char16_t(' '));
576 if (oper != char16_t(' ')) {
577 aString.Append(oper);
578 aString.Append(char16_t(' '));
579 }
580 }
581 }
582 }
583 }
585 void
586 nsCSSSelector::AppendToStringWithoutCombinators
587 (nsAString& aString, nsCSSStyleSheet* aSheet) const
588 {
589 AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false);
591 for (const nsCSSSelector* negation = mNegations; negation;
592 negation = negation->mNegations) {
593 aString.AppendLiteral(":not(");
594 negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet,
595 true);
596 aString.Append(char16_t(')'));
597 }
598 }
600 void
601 nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
602 (nsAString& aString, nsCSSStyleSheet* aSheet,
603 bool aIsNegated) const
604 {
605 nsAutoString temp;
606 bool isPseudoElement = IsPseudoElement();
608 // For non-pseudo-element selectors or for lone pseudo-elements, deal with
609 // namespace prefixes.
610 bool wroteNamespace = false;
611 if (!isPseudoElement || !mNext) {
612 // append the namespace prefix if needed
613 nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr;
615 // sheetNS is non-null if and only if we had an @namespace rule. If it's
616 // null, that means that the only namespaces we could have are the
617 // wildcard namespace (which can be implicit in this case) and the "none"
618 // namespace, which then needs to be explicitly specified.
619 if (!sheetNS) {
620 NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
621 mNameSpace == kNameSpaceID_None,
622 "How did we get this namespace?");
623 if (mNameSpace == kNameSpaceID_None) {
624 aString.Append(char16_t('|'));
625 wroteNamespace = true;
626 }
627 } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) {
628 // We have the default namespace (possibly including the wildcard
629 // namespace). Do nothing.
630 NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
631 CanBeNamespaced(aIsNegated),
632 "How did we end up with this namespace?");
633 } else if (mNameSpace == kNameSpaceID_None) {
634 NS_ASSERTION(CanBeNamespaced(aIsNegated),
635 "How did we end up with this namespace?");
636 aString.Append(char16_t('|'));
637 wroteNamespace = true;
638 } else if (mNameSpace != kNameSpaceID_Unknown) {
639 NS_ASSERTION(CanBeNamespaced(aIsNegated),
640 "How did we end up with this namespace?");
641 nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
642 NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
643 "without a prefix?");
644 nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom),
645 aString);
646 aString.Append(char16_t('|'));
647 wroteNamespace = true;
648 } else {
649 // A selector for an element in any namespace, while the default
650 // namespace is something else. :not() is special in that the default
651 // namespace is not implied for non-type selectors, so if this is a
652 // negated non-type selector we don't need to output an explicit wildcard
653 // namespace here, since those default to a wildcard namespace.
654 if (CanBeNamespaced(aIsNegated)) {
655 aString.AppendLiteral("*|");
656 wroteNamespace = true;
657 }
658 }
659 }
661 if (!mLowercaseTag) {
662 // Universal selector: avoid writing the universal selector when we
663 // can avoid it, especially since we're required to avoid it for the
664 // inside of :not()
665 if (wroteNamespace ||
666 (!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
667 (aIsNegated || !mNegations))) {
668 aString.Append(char16_t('*'));
669 }
670 } else {
671 // Append the tag name
672 nsAutoString tag;
673 (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
674 if (isPseudoElement) {
675 if (!mNext) {
676 // Lone pseudo-element selector -- toss in a wildcard type selector
677 // XXXldb Why?
678 aString.Append(char16_t('*'));
679 }
680 if (!nsCSSPseudoElements::IsCSS2PseudoElement(mLowercaseTag)) {
681 aString.Append(char16_t(':'));
682 }
683 // This should not be escaped since (a) the pseudo-element string
684 // has a ":" that can't be escaped and (b) all pseudo-elements at
685 // this point are known, and therefore we know they don't need
686 // escaping.
687 aString.Append(tag);
688 } else {
689 nsStyleUtil::AppendEscapedCSSIdent(tag, aString);
690 }
691 }
693 // Append the id, if there is one
694 if (mIDList) {
695 nsAtomList* list = mIDList;
696 while (list != nullptr) {
697 list->mAtom->ToString(temp);
698 aString.Append(char16_t('#'));
699 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
700 list = list->mNext;
701 }
702 }
704 // Append each class in the linked list
705 if (mClassList) {
706 if (isPseudoElement) {
707 #ifdef MOZ_XUL
708 NS_ABORT_IF_FALSE(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag),
709 "must be tree pseudo-element");
711 aString.Append(char16_t('('));
712 for (nsAtomList* list = mClassList; list; list = list->mNext) {
713 nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString);
714 aString.Append(char16_t(','));
715 }
716 // replace the final comma with a close-paren
717 aString.Replace(aString.Length() - 1, 1, char16_t(')'));
718 #else
719 NS_ERROR("Can't happen");
720 #endif
721 } else {
722 nsAtomList* list = mClassList;
723 while (list != nullptr) {
724 list->mAtom->ToString(temp);
725 aString.Append(char16_t('.'));
726 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
727 list = list->mNext;
728 }
729 }
730 }
732 // Append each attribute selector in the linked list
733 if (mAttrList) {
734 nsAttrSelector* list = mAttrList;
735 while (list != nullptr) {
736 aString.Append(char16_t('['));
737 // Append the namespace prefix
738 if (list->mNameSpace == kNameSpaceID_Unknown) {
739 aString.Append(char16_t('*'));
740 aString.Append(char16_t('|'));
741 } else if (list->mNameSpace != kNameSpaceID_None) {
742 if (aSheet) {
743 nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
744 nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
745 // Default namespaces don't apply to attribute selectors, so
746 // we must have a useful prefix.
747 NS_ASSERTION(prefixAtom,
748 "How did we end up with a namespace if the prefix "
749 "is unknown?");
750 nsAutoString prefix;
751 prefixAtom->ToString(prefix);
752 nsStyleUtil::AppendEscapedCSSIdent(prefix, aString);
753 aString.Append(char16_t('|'));
754 }
755 }
756 // Append the attribute name
757 list->mCasedAttr->ToString(temp);
758 nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
760 if (list->mFunction != NS_ATTR_FUNC_SET) {
761 // Append the function
762 if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
763 aString.Append(char16_t('~'));
764 else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
765 aString.Append(char16_t('|'));
766 else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
767 aString.Append(char16_t('^'));
768 else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
769 aString.Append(char16_t('$'));
770 else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
771 aString.Append(char16_t('*'));
773 aString.Append(char16_t('='));
775 // Append the value
776 nsStyleUtil::AppendEscapedCSSString(list->mValue, aString);
777 }
779 aString.Append(char16_t(']'));
781 list = list->mNext;
782 }
783 }
785 // Append each pseudo-class in the linked list
786 for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) {
787 nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp);
788 // This should not be escaped since (a) the pseudo-class string
789 // has a ":" that can't be escaped and (b) all pseudo-classes at
790 // this point are known, and therefore we know they don't need
791 // escaping.
792 aString.Append(temp);
793 if (list->u.mMemory) {
794 aString.Append(char16_t('('));
795 if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
796 nsStyleUtil::AppendEscapedCSSIdent(
797 nsDependentString(list->u.mString), aString);
798 } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) {
799 int32_t a = list->u.mNumbers[0],
800 b = list->u.mNumbers[1];
801 temp.Truncate();
802 if (a != 0) {
803 if (a == -1) {
804 temp.Append(char16_t('-'));
805 } else if (a != 1) {
806 temp.AppendInt(a);
807 }
808 temp.Append(char16_t('n'));
809 }
810 if (b != 0 || a == 0) {
811 if (b >= 0 && a != 0) // check a != 0 for whether we printed above
812 temp.Append(char16_t('+'));
813 temp.AppendInt(b);
814 }
815 aString.Append(temp);
816 } else {
817 NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType),
818 "unexpected pseudo-class");
819 nsString tmp;
820 list->u.mSelectors->ToString(tmp, aSheet);
821 aString.Append(tmp);
822 }
823 aString.Append(char16_t(')'));
824 }
825 }
826 }
828 bool
829 nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
830 {
831 return !aIsNegated ||
832 (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
833 }
835 size_t
836 nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
837 {
838 size_t n = 0;
839 const nsCSSSelector* s = this;
840 while (s) {
841 n += aMallocSizeOf(s);
843 #define MEASURE(x) n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
845 MEASURE(s->mIDList);
846 MEASURE(s->mClassList);
847 MEASURE(s->mPseudoClassList);
848 MEASURE(s->mNegations);
850 // Measurement of the following members may be added later if DMD finds it is
851 // worthwhile:
852 // - s->mAttrList
853 //
854 // The following members aren't measured:
855 // - s->mLowercaseTag, because it's an atom and therefore shared
856 // - s->mCasedTag, because it's an atom and therefore shared
858 s = s->mNext;
859 }
860 return n;
861 }
863 // -- nsCSSSelectorList -------------------------------
865 nsCSSSelectorList::nsCSSSelectorList(void)
866 : mSelectors(nullptr),
867 mWeight(0),
868 mNext(nullptr)
869 {
870 MOZ_COUNT_CTOR(nsCSSSelectorList);
871 }
873 nsCSSSelectorList::~nsCSSSelectorList()
874 {
875 MOZ_COUNT_DTOR(nsCSSSelectorList);
876 delete mSelectors;
877 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext);
878 }
880 nsCSSSelector*
881 nsCSSSelectorList::AddSelector(char16_t aOperator)
882 {
883 nsCSSSelector* newSel = new nsCSSSelector();
885 if (mSelectors) {
886 NS_ASSERTION(aOperator != char16_t(0), "chaining without combinator");
887 mSelectors->SetOperator(aOperator);
888 } else {
889 NS_ASSERTION(aOperator == char16_t(0), "combinator without chaining");
890 }
892 newSel->mNext = mSelectors;
893 mSelectors = newSel;
894 return newSel;
895 }
897 void
898 nsCSSSelectorList::ToString(nsAString& aResult, nsCSSStyleSheet* aSheet)
899 {
900 aResult.Truncate();
901 nsCSSSelectorList *p = this;
902 for (;;) {
903 p->mSelectors->ToString(aResult, aSheet, true);
904 p = p->mNext;
905 if (!p)
906 break;
907 aResult.AppendLiteral(", ");
908 }
909 }
911 nsCSSSelectorList*
912 nsCSSSelectorList::Clone(bool aDeep) const
913 {
914 nsCSSSelectorList *result = new nsCSSSelectorList();
915 result->mWeight = mWeight;
916 NS_IF_CLONE(mSelectors);
918 if (aDeep) {
919 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
920 (false));
921 }
922 return result;
923 }
925 size_t
926 nsCSSSelectorList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
927 {
928 size_t n = 0;
929 const nsCSSSelectorList* s = this;
930 while (s) {
931 n += aMallocSizeOf(s);
932 n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
933 s = s->mNext;
934 }
935 return n;
936 }
938 // -- ImportantRule ----------------------------------
940 namespace mozilla {
941 namespace css {
943 ImportantRule::ImportantRule(Declaration* aDeclaration)
944 : mDeclaration(aDeclaration)
945 {
946 }
948 ImportantRule::~ImportantRule()
949 {
950 }
952 NS_IMPL_ISUPPORTS(ImportantRule, nsIStyleRule)
954 /* virtual */ void
955 ImportantRule::MapRuleInfoInto(nsRuleData* aRuleData)
956 {
957 mDeclaration->MapImportantRuleInfoInto(aRuleData);
958 }
960 #ifdef DEBUG
961 /* virtual */ void
962 ImportantRule::List(FILE* out, int32_t aIndent) const
963 {
964 // Indent
965 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
967 fprintf(out, "! Important declaration=%p\n",
968 static_cast<void*>(mDeclaration));
969 }
970 #endif
972 } // namespace css
973 } // namespace mozilla
975 // --------------------------------------------------------
977 namespace mozilla {
978 namespace css {
979 class DOMCSSStyleRule;
980 }
981 }
983 class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
984 {
985 public:
986 DOMCSSDeclarationImpl(css::StyleRule *aRule);
987 virtual ~DOMCSSDeclarationImpl(void);
989 NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) MOZ_OVERRIDE;
990 void DropReference(void);
991 virtual css::Declaration* GetCSSDeclaration(bool aAllocate) MOZ_OVERRIDE;
992 virtual nsresult SetCSSDeclaration(css::Declaration* aDecl) MOZ_OVERRIDE;
993 virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) MOZ_OVERRIDE;
994 virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE;
996 // Override |AddRef| and |Release| for being a member of
997 // |DOMCSSStyleRule|. Also, we need to forward QI for cycle
998 // collection things to DOMCSSStyleRule.
999 NS_DECL_ISUPPORTS_INHERITED
1001 virtual nsINode *GetParentObject() MOZ_OVERRIDE
1002 {
1003 return mRule ? mRule->GetDocument() : nullptr;
1004 }
1006 friend class css::DOMCSSStyleRule;
1008 protected:
1009 // This reference is not reference-counted. The rule object tells us
1010 // when it's about to go away.
1011 css::StyleRule *mRule;
1013 inline css::DOMCSSStyleRule* DomRule();
1015 private:
1016 // NOT TO BE IMPLEMENTED
1017 // This object cannot be allocated on its own. It must be a member of
1018 // DOMCSSStyleRule.
1019 void* operator new(size_t size) CPP_THROW_NEW;
1020 };
1022 namespace mozilla {
1023 namespace css {
1025 class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper
1026 {
1027 public:
1028 DOMCSSStyleRule(StyleRule *aRule);
1029 virtual ~DOMCSSStyleRule();
1031 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
1032 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCSSStyleRule)
1033 NS_DECL_NSIDOMCSSRULE
1034 NS_DECL_NSIDOMCSSSTYLERULE
1036 // nsICSSStyleRuleDOMWrapper
1037 NS_IMETHOD GetCSSStyleRule(StyleRule **aResult);
1039 DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
1041 friend class ::DOMCSSDeclarationImpl;
1043 protected:
1044 DOMCSSDeclarationImpl mDOMDeclaration;
1046 StyleRule* Rule() {
1047 return mDOMDeclaration.mRule;
1048 }
1049 };
1051 } // namespace css
1052 } // namespace mozilla
1054 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
1055 : mRule(aRule)
1056 {
1057 MOZ_COUNT_CTOR(DOMCSSDeclarationImpl);
1058 }
1060 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
1061 {
1062 NS_ASSERTION(!mRule, "DropReference not called.");
1064 MOZ_COUNT_DTOR(DOMCSSDeclarationImpl);
1065 }
1067 inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule()
1068 {
1069 return reinterpret_cast<css::DOMCSSStyleRule*>
1070 (reinterpret_cast<char*>(this) -
1071 offsetof(css::DOMCSSStyleRule, mDOMDeclaration));
1072 }
1074 NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1075 NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1077 NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl)
1078 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1079 // We forward the cycle collection interfaces to DomRule(), which is
1080 // never null (in fact, we're part of that object!)
1081 if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
1082 aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
1083 return DomRule()->QueryInterface(aIID, aInstancePtr);
1084 }
1085 else
1086 NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
1088 void
1089 DOMCSSDeclarationImpl::DropReference(void)
1090 {
1091 mRule = nullptr;
1092 }
1094 css::Declaration*
1095 DOMCSSDeclarationImpl::GetCSSDeclaration(bool aAllocate)
1096 {
1097 if (mRule) {
1098 return mRule->GetDeclaration();
1099 } else {
1100 return nullptr;
1101 }
1102 }
1104 void
1105 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
1106 {
1107 GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
1108 }
1110 NS_IMETHODIMP
1111 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
1112 {
1113 NS_ENSURE_ARG_POINTER(aParent);
1115 if (!mRule) {
1116 *aParent = nullptr;
1117 return NS_OK;
1118 }
1120 NS_IF_ADDREF(*aParent = mRule->GetDOMRule());
1121 return NS_OK;
1122 }
1124 nsresult
1125 DOMCSSDeclarationImpl::SetCSSDeclaration(css::Declaration* aDecl)
1126 {
1127 NS_PRECONDITION(mRule,
1128 "can only be called when |GetCSSDeclaration| returned a declaration");
1130 nsCOMPtr<nsIDocument> owningDoc;
1131 nsCOMPtr<nsIStyleSheet> sheet = mRule->GetStyleSheet();
1132 if (sheet) {
1133 owningDoc = sheet->GetOwningDocument();
1134 }
1136 mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
1138 nsRefPtr<css::StyleRule> oldRule = mRule;
1139 mRule = oldRule->DeclarationChanged(aDecl, true).take();
1140 if (!mRule)
1141 return NS_ERROR_OUT_OF_MEMORY;
1142 nsrefcnt cnt = mRule->Release();
1143 if (cnt == 0) {
1144 NS_NOTREACHED("container didn't take ownership");
1145 mRule = nullptr;
1146 return NS_ERROR_UNEXPECTED;
1147 }
1149 if (owningDoc) {
1150 owningDoc->StyleRuleChanged(sheet, oldRule, mRule);
1151 }
1152 return NS_OK;
1153 }
1155 nsIDocument*
1156 DOMCSSDeclarationImpl::DocToUpdate()
1157 {
1158 return nullptr;
1159 }
1161 // needs to be outside the namespace
1162 DOMCI_DATA(CSSStyleRule, css::DOMCSSStyleRule)
1164 namespace mozilla {
1165 namespace css {
1167 DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule)
1168 : mDOMDeclaration(aRule)
1169 {
1170 }
1172 DOMCSSStyleRule::~DOMCSSStyleRule()
1173 {
1174 }
1176 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCSSStyleRule)
1177 NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
1178 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
1179 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
1180 NS_INTERFACE_MAP_ENTRY(nsISupports)
1181 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
1182 NS_INTERFACE_MAP_END
1184 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCSSStyleRule)
1185 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCSSStyleRule)
1187 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMCSSStyleRule)
1189 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMCSSStyleRule)
1190 // Trace the wrapper for our declaration. This just expands out
1191 // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
1192 // directly because the wrapper is on the declaration, not on us.
1193 tmp->DOMDeclaration()->TraceWrapper(aCallbacks, aClosure);
1194 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1196 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMCSSStyleRule)
1197 // Unlink the wrapper for our declaraton. This just expands out
1198 // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
1199 // directly because the wrapper is on the declaration, not on us.
1200 tmp->DOMDeclaration()->ReleaseWrapper(static_cast<nsISupports*>(p));
1201 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1203 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule)
1204 // Just NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS here: that will call
1205 // into our Trace hook, where we do the right thing with declarations
1206 // already.
1207 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1208 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1210 NS_IMETHODIMP
1211 DOMCSSStyleRule::GetType(uint16_t* aType)
1212 {
1213 *aType = nsIDOMCSSRule::STYLE_RULE;
1215 return NS_OK;
1216 }
1218 NS_IMETHODIMP
1219 DOMCSSStyleRule::GetCssText(nsAString& aCssText)
1220 {
1221 if (!Rule()) {
1222 aCssText.Truncate();
1223 } else {
1224 Rule()->GetCssText(aCssText);
1225 }
1226 return NS_OK;
1227 }
1229 NS_IMETHODIMP
1230 DOMCSSStyleRule::SetCssText(const nsAString& aCssText)
1231 {
1232 if (Rule()) {
1233 Rule()->SetCssText(aCssText);
1234 }
1235 return NS_OK;
1236 }
1238 NS_IMETHODIMP
1239 DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
1240 {
1241 if (!Rule()) {
1242 *aSheet = nullptr;
1243 return NS_OK;
1244 }
1245 return Rule()->GetParentStyleSheet(aSheet);
1246 }
1248 NS_IMETHODIMP
1249 DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
1250 {
1251 if (!Rule()) {
1252 *aParentRule = nullptr;
1253 return NS_OK;
1254 }
1255 return Rule()->GetParentRule(aParentRule);
1256 }
1258 NS_IMETHODIMP
1259 DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText)
1260 {
1261 if (!Rule()) {
1262 aSelectorText.Truncate();
1263 } else {
1264 Rule()->GetSelectorText(aSelectorText);
1265 }
1266 return NS_OK;
1267 }
1269 NS_IMETHODIMP
1270 DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText)
1271 {
1272 if (Rule()) {
1273 Rule()->SetSelectorText(aSelectorText);
1274 }
1275 return NS_OK;
1276 }
1278 NS_IMETHODIMP
1279 DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
1280 {
1281 *aStyle = &mDOMDeclaration;
1282 NS_ADDREF(*aStyle);
1283 return NS_OK;
1284 }
1286 NS_IMETHODIMP
1287 DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult)
1288 {
1289 *aResult = Rule();
1290 NS_IF_ADDREF(*aResult);
1291 return NS_OK;
1292 }
1294 } // namespace css
1295 } // namespace mozilla
1297 // -- StyleRule ------------------------------------
1299 namespace mozilla {
1300 namespace css {
1302 StyleRule::StyleRule(nsCSSSelectorList* aSelector,
1303 Declaration* aDeclaration)
1304 : Rule(),
1305 mSelector(aSelector),
1306 mDeclaration(aDeclaration),
1307 mImportantRule(nullptr),
1308 mDOMRule(nullptr),
1309 mLineNumber(0),
1310 mColumnNumber(0),
1311 mWasMatched(false)
1312 {
1313 NS_PRECONDITION(aDeclaration, "must have a declaration");
1314 }
1316 // for |Clone|
1317 StyleRule::StyleRule(const StyleRule& aCopy)
1318 : Rule(aCopy),
1319 mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr),
1320 mDeclaration(new Declaration(*aCopy.mDeclaration)),
1321 mImportantRule(nullptr),
1322 mDOMRule(nullptr),
1323 mLineNumber(aCopy.mLineNumber),
1324 mColumnNumber(aCopy.mColumnNumber),
1325 mWasMatched(false)
1326 {
1327 // rest is constructed lazily on existing data
1328 }
1330 // for |SetCSSDeclaration|
1331 StyleRule::StyleRule(StyleRule& aCopy,
1332 Declaration* aDeclaration)
1333 : Rule(aCopy),
1334 mSelector(aCopy.mSelector),
1335 mDeclaration(aDeclaration),
1336 mImportantRule(nullptr),
1337 mDOMRule(aCopy.mDOMRule),
1338 mLineNumber(aCopy.mLineNumber),
1339 mColumnNumber(aCopy.mColumnNumber),
1340 mWasMatched(false)
1341 {
1342 // The DOM rule is replacing |aCopy| with |this|, so transfer
1343 // the reverse pointer as well (and transfer ownership).
1344 aCopy.mDOMRule = nullptr;
1346 // Similarly for the selector.
1347 aCopy.mSelector = nullptr;
1349 // We are probably replacing the old declaration with |aDeclaration|
1350 // instead of taking ownership of the old declaration; only null out
1351 // aCopy.mDeclaration if we are taking ownership.
1352 if (mDeclaration == aCopy.mDeclaration) {
1353 // This should only ever happen if the declaration was modifiable.
1354 mDeclaration->AssertMutable();
1355 aCopy.mDeclaration = nullptr;
1356 }
1357 }
1359 StyleRule::~StyleRule()
1360 {
1361 delete mSelector;
1362 delete mDeclaration;
1363 NS_IF_RELEASE(mImportantRule);
1364 if (mDOMRule) {
1365 mDOMRule->DOMDeclaration()->DropReference();
1366 NS_RELEASE(mDOMRule);
1367 }
1368 }
1370 // QueryInterface implementation for StyleRule
1371 NS_INTERFACE_MAP_BEGIN(StyleRule)
1372 if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
1373 *aInstancePtr = this;
1374 NS_ADDREF_THIS();
1375 return NS_OK;
1376 }
1377 else
1378 NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
1379 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
1380 NS_INTERFACE_MAP_END
1382 NS_IMPL_ADDREF(StyleRule)
1383 NS_IMPL_RELEASE(StyleRule)
1385 void
1386 StyleRule::RuleMatched()
1387 {
1388 if (!mWasMatched) {
1389 NS_ABORT_IF_FALSE(!mImportantRule, "should not have important rule yet");
1391 mWasMatched = true;
1392 mDeclaration->SetImmutable();
1393 if (mDeclaration->HasImportantData()) {
1394 NS_ADDREF(mImportantRule = new ImportantRule(mDeclaration));
1395 }
1396 }
1397 }
1399 /* virtual */ int32_t
1400 StyleRule::GetType() const
1401 {
1402 return Rule::STYLE_RULE;
1403 }
1405 /* virtual */ already_AddRefed<Rule>
1406 StyleRule::Clone() const
1407 {
1408 nsRefPtr<Rule> clone = new StyleRule(*this);
1409 return clone.forget();
1410 }
1412 /* virtual */ nsIDOMCSSRule*
1413 StyleRule::GetDOMRule()
1414 {
1415 if (!mDOMRule) {
1416 if (!GetStyleSheet()) {
1417 // Inline style rules aren't supposed to have a DOM rule object, only
1418 // a declaration. But if we do have one already, from a style sheet
1419 // rule that used to be in a document, we still want to return it.
1420 return nullptr;
1421 }
1422 mDOMRule = new DOMCSSStyleRule(this);
1423 NS_ADDREF(mDOMRule);
1424 }
1425 return mDOMRule;
1426 }
1428 /* virtual */ nsIDOMCSSRule*
1429 StyleRule::GetExistingDOMRule()
1430 {
1431 return mDOMRule;
1432 }
1434 /* virtual */ already_AddRefed<StyleRule>
1435 StyleRule::DeclarationChanged(Declaration* aDecl,
1436 bool aHandleContainer)
1437 {
1438 nsRefPtr<StyleRule> clone = new StyleRule(*this, aDecl);
1440 if (aHandleContainer) {
1441 nsCSSStyleSheet* sheet = GetStyleSheet();
1442 if (mParentRule) {
1443 if (sheet) {
1444 sheet->ReplaceRuleInGroup(mParentRule, this, clone);
1445 } else {
1446 mParentRule->ReplaceStyleRule(this, clone);
1447 }
1448 } else if (sheet) {
1449 sheet->ReplaceStyleRule(this, clone);
1450 }
1451 }
1453 return clone.forget();
1454 }
1456 /* virtual */ void
1457 StyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
1458 {
1459 NS_ABORT_IF_FALSE(mWasMatched,
1460 "somebody forgot to call css::StyleRule::RuleMatched");
1461 mDeclaration->MapNormalRuleInfoInto(aRuleData);
1462 }
1464 #ifdef DEBUG
1465 /* virtual */ void
1466 StyleRule::List(FILE* out, int32_t aIndent) const
1467 {
1468 // Indent
1469 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
1471 nsAutoString buffer;
1472 if (mSelector)
1473 mSelector->ToString(buffer, GetStyleSheet());
1475 buffer.AppendLiteral(" ");
1476 fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
1477 if (nullptr != mDeclaration) {
1478 mDeclaration->List(out);
1479 }
1480 else {
1481 fputs("{ null declaration }", out);
1482 }
1483 fputs("\n", out);
1484 }
1485 #endif
1487 void
1488 StyleRule::GetCssText(nsAString& aCssText)
1489 {
1490 if (mSelector) {
1491 mSelector->ToString(aCssText, GetStyleSheet());
1492 aCssText.Append(char16_t(' '));
1493 }
1494 aCssText.Append(char16_t('{'));
1495 aCssText.Append(char16_t(' '));
1496 if (mDeclaration)
1497 {
1498 nsAutoString tempString;
1499 mDeclaration->ToString( tempString );
1500 aCssText.Append( tempString );
1501 }
1502 aCssText.Append(char16_t(' '));
1503 aCssText.Append(char16_t('}'));
1504 }
1506 void
1507 StyleRule::SetCssText(const nsAString& aCssText)
1508 {
1509 // XXX TBI - need to re-parse rule & declaration
1510 }
1512 void
1513 StyleRule::GetSelectorText(nsAString& aSelectorText)
1514 {
1515 if (mSelector)
1516 mSelector->ToString(aSelectorText, GetStyleSheet());
1517 else
1518 aSelectorText.Truncate();
1519 }
1521 void
1522 StyleRule::SetSelectorText(const nsAString& aSelectorText)
1523 {
1524 // XXX TBI - get a parser and re-parse the selectors,
1525 // XXX then need to re-compute the cascade
1526 // XXX and dirty sheet
1527 }
1529 /* virtual */ size_t
1530 StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1531 {
1532 size_t n = aMallocSizeOf(this);
1533 n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
1534 n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
1536 // Measurement of the following members may be added later if DMD finds it is
1537 // worthwhile:
1538 // - mImportantRule;
1539 // - mDOMRule;
1541 return n;
1542 }
1545 } // namespace css
1546 } // namespace mozilla