1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * David Hyatt <hyatt@netscape.com>
24 * Daniel Glazman <glazman@netscape.com>
25 * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * representation of CSS style rules (selectors+declaration), CSS
43 * selectors, and DOM objects for style rules, selectors, and
48 #include "nsCSSRule.h"
49 #include "nsICSSStyleRule.h"
50 #include "nsICSSGroupRule.h"
51 #include "nsCSSDeclaration.h"
52 #include "nsICSSStyleSheet.h"
53 #include "nsICSSParser.h"
54 #include "nsICSSLoader.h"
56 #include "nsPresContext.h"
57 #include "nsIDocument.h"
58 #include "nsIDeviceContext.h"
62 #include "nsStyleConsts.h"
63 #include "nsStyleUtil.h"
64 #include "nsIFontMetrics.h"
65 #include "nsIDOMCSSStyleSheet.h"
66 #include "nsICSSStyleRuleDOMWrapper.h"
67 #include "nsIDOMCSSStyleDeclaration.h"
68 #include "nsDOMCSSDeclaration.h"
69 #include "nsINameSpaceManager.h"
70 #include "nsXMLNameSpaceMap.h"
71 #include "nsILookAndFeel.h"
72 #include "nsRuleNode.h"
73 #include "nsUnicharUtils.h"
74 #include "nsCSSPseudoElements.h"
75 #include "nsIPrincipal.h"
76 #include "nsComponentManagerUtils.h"
77 #include "nsCSSPseudoClasses.h"
79 #include "nsContentUtils.h"
80 #include "nsContentErrors.h"
81 #include "mozAutoDocUpdate.h"
83 #define NS_IF_CLONE(member_) \
86 result->member_ = member_->Clone(); \
87 if (!result->member_) { \
94 #define NS_IF_DELETE(ptr) \
100 /* ************************************************************************** */
102 nsAtomList::nsAtomList(nsIAtom
* aAtom
)
106 MOZ_COUNT_CTOR(nsAtomList
);
109 nsAtomList::nsAtomList(const nsString
& aAtomValue
)
113 MOZ_COUNT_CTOR(nsAtomList
);
114 mAtom
= do_GetAtom(aAtomValue
);
118 nsAtomList::Clone(PRBool aDeep
) const
120 nsAtomList
*result
= new nsAtomList(mAtom
);
125 NS_CSS_CLONE_LIST_MEMBER(nsAtomList
, this, mNext
, result
, (PR_FALSE
));
129 nsAtomList::~nsAtomList(void)
131 MOZ_COUNT_DTOR(nsAtomList
);
132 NS_CSS_DELETE_LIST_MEMBER(nsAtomList
, this, mNext
);
135 nsPseudoClassList::nsPseudoClassList(nsIAtom
* aAtom
)
139 NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aAtom
) &&
140 !nsCSSPseudoClasses::HasNthPairArg(aAtom
),
141 "unexpected pseudo-class");
142 MOZ_COUNT_CTOR(nsPseudoClassList
);
146 nsPseudoClassList::nsPseudoClassList(nsIAtom
* aAtom
, const PRUnichar
* aString
)
150 NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aAtom
),
151 "unexpected pseudo-class");
152 NS_ASSERTION(aString
, "string expected");
153 MOZ_COUNT_CTOR(nsPseudoClassList
);
154 u
.mString
= NS_strdup(aString
);
157 nsPseudoClassList::nsPseudoClassList(nsIAtom
* aAtom
, const PRInt32
* aIntPair
)
161 NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aAtom
),
162 "unexpected pseudo-class");
163 NS_ASSERTION(aIntPair
, "integer pair expected");
164 MOZ_COUNT_CTOR(nsPseudoClassList
);
166 static_cast<PRInt32
*>(nsMemory::Clone(aIntPair
, sizeof(PRInt32
) * 2));
170 nsPseudoClassList::Clone(PRBool aDeep
) const
172 nsPseudoClassList
*result
;
174 result
= new nsPseudoClassList(mAtom
);
175 } else if (nsCSSPseudoClasses::HasStringArg(mAtom
)) {
176 result
= new nsPseudoClassList(mAtom
, u
.mString
);
178 NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(mAtom
),
179 "unexpected pseudo-class");
180 result
= new nsPseudoClassList(mAtom
, u
.mNumbers
);
184 NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList
, this, mNext
, result
,
190 nsPseudoClassList::~nsPseudoClassList(void)
192 MOZ_COUNT_DTOR(nsPseudoClassList
);
195 NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList
, this, mNext
);
198 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace
, const nsString
& aAttr
)
199 : mNameSpace(aNameSpace
),
201 mFunction(NS_ATTR_FUNC_SET
),
206 MOZ_COUNT_CTOR(nsAttrSelector
);
208 mAttr
= do_GetAtom(aAttr
);
211 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace
, const nsString
& aAttr
, PRUint8 aFunction
,
212 const nsString
& aValue
, PRBool aCaseSensitive
)
213 : mNameSpace(aNameSpace
),
215 mFunction(aFunction
),
216 mCaseSensitive(aCaseSensitive
),
220 MOZ_COUNT_CTOR(nsAttrSelector
);
222 mAttr
= do_GetAtom(aAttr
);
225 nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace
, nsIAtom
* aAttr
,
226 PRUint8 aFunction
, const nsString
& aValue
,
227 PRBool aCaseSensitive
)
228 : mNameSpace(aNameSpace
),
230 mFunction(aFunction
),
231 mCaseSensitive(aCaseSensitive
),
235 MOZ_COUNT_CTOR(nsAttrSelector
);
239 nsAttrSelector::Clone(PRBool aDeep
) const
241 nsAttrSelector
*result
=
242 new nsAttrSelector(mNameSpace
, mAttr
, mFunction
, mValue
, mCaseSensitive
);
245 NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector
, this, mNext
, result
, (PR_FALSE
));
250 nsAttrSelector::~nsAttrSelector(void)
252 MOZ_COUNT_DTOR(nsAttrSelector
);
254 NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector
, this, mNext
);
257 // -- nsCSSSelector -------------------------------
259 nsCSSSelector::nsCSSSelector(void)
260 : mNameSpace(kNameSpaceID_Unknown
), mTag(nsnull
),
263 mPseudoClassList(nsnull
),
269 MOZ_COUNT_CTOR(nsCSSSelector
);
273 nsCSSSelector::Clone(PRBool aDeepNext
, PRBool aDeepNegations
) const
275 nsCSSSelector
*result
= new nsCSSSelector();
279 result
->mNameSpace
= mNameSpace
;
282 NS_IF_CLONE(mIDList
);
283 NS_IF_CLONE(mClassList
);
284 NS_IF_CLONE(mPseudoClassList
);
285 NS_IF_CLONE(mAttrList
);
287 // No need to worry about multiple levels of recursion since an
288 // mNegations can't have an mNext.
289 NS_ASSERTION(!mNegations
|| !mNegations
->mNext
,
290 "mNegations can't have non-null mNext");
291 if (aDeepNegations
) {
292 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector
, this, mNegations
, result
,
293 (PR_TRUE
, PR_FALSE
));
297 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector
, this, mNext
, result
,
298 (PR_FALSE
, PR_TRUE
));
304 nsCSSSelector::~nsCSSSelector(void)
306 MOZ_COUNT_DTOR(nsCSSSelector
);
308 // No need to worry about multiple levels of recursion since an
309 // mNegations can't have an mNext.
310 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector
, this, mNext
);
313 void nsCSSSelector::Reset(void)
315 mNameSpace
= kNameSpaceID_Unknown
;
317 NS_IF_DELETE(mIDList
);
318 NS_IF_DELETE(mClassList
);
319 NS_IF_DELETE(mPseudoClassList
);
320 NS_IF_DELETE(mAttrList
);
321 // No need to worry about multiple levels of recursion since an
322 // mNegations can't have an mNext.
323 NS_ASSERTION(!mNegations
|| !mNegations
->mNext
,
324 "mNegations can't have non-null mNext");
325 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector
, this, mNegations
);
326 mOperator
= PRUnichar(0);
329 void nsCSSSelector::SetNameSpace(PRInt32 aNameSpace
)
331 mNameSpace
= aNameSpace
;
334 void nsCSSSelector::SetTag(const nsString
& aTag
)
339 mTag
= do_GetAtom(aTag
);
342 void nsCSSSelector::AddID(const nsString
& aID
)
344 if (!aID
.IsEmpty()) {
345 nsAtomList
** list
= &mIDList
;
346 while (nsnull
!= *list
) {
347 list
= &((*list
)->mNext
);
349 *list
= new nsAtomList(aID
);
353 void nsCSSSelector::AddClass(const nsString
& aClass
)
355 if (!aClass
.IsEmpty()) {
356 nsAtomList
** list
= &mClassList
;
357 while (nsnull
!= *list
) {
358 list
= &((*list
)->mNext
);
360 *list
= new nsAtomList(aClass
);
364 void nsCSSSelector::AddPseudoClass(nsIAtom
* aPseudoClass
)
366 AddPseudoClassInternal(new nsPseudoClassList(aPseudoClass
));
369 void nsCSSSelector::AddPseudoClass(nsIAtom
* aPseudoClass
,
370 const PRUnichar
* aString
)
372 AddPseudoClassInternal(new nsPseudoClassList(aPseudoClass
, aString
));
375 void nsCSSSelector::AddPseudoClass(nsIAtom
* aPseudoClass
,
376 const PRInt32
* aIntPair
)
378 AddPseudoClassInternal(new nsPseudoClassList(aPseudoClass
, aIntPair
));
381 void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList
*aPseudoClass
)
383 nsPseudoClassList
** list
= &mPseudoClassList
;
384 while (nsnull
!= *list
) {
385 list
= &((*list
)->mNext
);
387 *list
= aPseudoClass
;
390 void nsCSSSelector::AddAttribute(PRInt32 aNameSpace
, const nsString
& aAttr
)
392 if (!aAttr
.IsEmpty()) {
393 nsAttrSelector
** list
= &mAttrList
;
394 while (nsnull
!= *list
) {
395 list
= &((*list
)->mNext
);
397 *list
= new nsAttrSelector(aNameSpace
, aAttr
);
401 void nsCSSSelector::AddAttribute(PRInt32 aNameSpace
, const nsString
& aAttr
, PRUint8 aFunc
,
402 const nsString
& aValue
, PRBool aCaseSensitive
)
404 if (!aAttr
.IsEmpty()) {
405 nsAttrSelector
** list
= &mAttrList
;
406 while (nsnull
!= *list
) {
407 list
= &((*list
)->mNext
);
409 *list
= new nsAttrSelector(aNameSpace
, aAttr
, aFunc
, aValue
, aCaseSensitive
);
413 void nsCSSSelector::SetOperator(PRUnichar aOperator
)
415 mOperator
= aOperator
;
418 PRInt32
nsCSSSelector::CalcWeight(void) const
422 if (nsnull
!= mTag
) {
425 nsAtomList
* list
= mIDList
;
426 while (nsnull
!= list
) {
431 while (nsnull
!= list
) {
435 nsPseudoClassList
*plist
= mPseudoClassList
;
436 while (nsnull
!= plist
) {
438 plist
= plist
->mNext
;
440 nsAttrSelector
* attr
= mAttrList
;
441 while (nsnull
!= attr
) {
445 if (nsnull
!= mNegations
) {
446 weight
+= mNegations
->CalcWeight();
451 // pseudo-elements are stored in the selectors' chain using fictional elements;
452 // these fictional elements have mTag starting with a colon
453 static PRBool
IsPseudoElement(nsIAtom
* aAtom
)
457 aAtom
->GetUTF8String(&str
);
458 return str
&& (*str
== ':');
464 void nsCSSSelector::AppendNegationToString(nsAString
& aString
)
466 aString
.AppendLiteral(":not(");
470 // Builds the textual representation of a selector. Called by DOM 2 CSS
471 // StyleRule:selectorText
474 nsCSSSelector::ToString(nsAString
& aString
, nsICSSStyleSheet
* aSheet
,
475 PRBool aAppend
) const
480 ToStringInternal(aString
, aSheet
, IsPseudoElement(mTag
), PR_FALSE
);
483 void nsCSSSelector::ToStringInternal(nsAString
& aString
,
484 nsICSSStyleSheet
* aSheet
,
485 PRBool aIsPseudoElem
,
486 PRBool aIsNegated
) const
489 PRBool isPseudoElement
= IsPseudoElement(mTag
);
491 // selectors are linked from right-to-left, so the next selector in the linked list
492 // actually precedes this one in the resulting string
494 mNext
->ToStringInternal(aString
, aSheet
, IsPseudoElement(mTag
), 0);
495 if (!aIsNegated
&& !isPseudoElement
) {
496 // don't add a leading whitespace if we have a pseudo-element
497 // or a negated simple selector
498 aString
.Append(PRUnichar(' '));
502 // For non-pseudo-element selectors or for lone pseudo-elements, deal with
503 // namespace prefixes.
504 PRBool wroteNamespace
= PR_FALSE
;
505 if (!isPseudoElement
|| !mNext
) {
506 // append the namespace prefix if needed
507 nsXMLNameSpaceMap
*sheetNS
= aSheet
? aSheet
->GetNameSpaceMap() : nsnull
;
509 // sheetNS is non-null if and only if we had an @namespace rule. If it's
510 // null, that means that the only namespaces we could have are the
511 // wildcard namespace (which can be implicit in this case) and the "none"
512 // namespace, which then needs to be explicitly specified.
514 NS_ASSERTION(mNameSpace
== kNameSpaceID_Unknown
||
515 mNameSpace
== kNameSpaceID_None
,
516 "How did we get this namespace?");
517 if (mNameSpace
== kNameSpaceID_None
) {
518 aString
.Append(PRUnichar('|'));
519 wroteNamespace
= PR_TRUE
;
521 } else if (sheetNS
->FindNameSpaceID(nsnull
) == mNameSpace
) {
522 // We have the default namespace (possibly including the wildcard
523 // namespace). Do nothing.
524 NS_ASSERTION(mNameSpace
== kNameSpaceID_Unknown
||
525 CanBeNamespaced(aIsNegated
),
526 "How did we end up with this namespace?");
527 } else if (mNameSpace
!= kNameSpaceID_Unknown
) {
528 NS_ASSERTION(CanBeNamespaced(aIsNegated
),
529 "How did we end up with this namespace?");
530 nsIAtom
*prefixAtom
= sheetNS
->FindPrefix(mNameSpace
);
531 NS_ASSERTION(prefixAtom
, "how'd we get a non-default namespace "
532 "without a prefix?");
534 prefixAtom
->ToString(prefix
);
535 aString
.Append(prefix
);
536 aString
.Append(PRUnichar('|'));
537 wroteNamespace
= PR_TRUE
;
539 // A selector for an element in any namespace, while the default
540 // namespace is something else. :not() is special in that the default
541 // namespace is not implied for non-type selectors, so if this is a
542 // negated non-type selector we don't need to output an explicit wildcard
543 // namespace here, since those default to a wildcard namespace.
544 if (CanBeNamespaced(aIsNegated
)) {
545 aString
.AppendLiteral("*|");
546 wroteNamespace
= PR_TRUE
;
552 // Universal selector: avoid writing the universal selector when we
553 // can avoid it, especially since we're required to avoid it for the
555 if (wroteNamespace
||
556 (!mIDList
&& !mClassList
&& !mPseudoClassList
&& !mAttrList
&&
557 (aIsNegated
|| !mNegations
))) {
558 aString
.Append(PRUnichar('*'));
561 // Append the tag name
562 if (isPseudoElement
) {
564 // Lone pseudo-element selector -- toss in a wildcard type selector
566 aString
.Append(PRUnichar('*'));
568 if (!nsCSSPseudoElements::IsCSS2PseudoElement(mTag
)) {
569 aString
.Append(PRUnichar(':'));
573 mTag
->ToString(prefix
);
574 aString
.Append(prefix
);
577 // Append the id, if there is one
579 nsAtomList
* list
= mIDList
;
580 while (list
!= nsnull
) {
581 list
->mAtom
->ToString(temp
);
582 aString
.Append(PRUnichar('#'));
583 aString
.Append(temp
);
588 // Append each class in the linked list
590 nsAtomList
* list
= mClassList
;
591 while (list
!= nsnull
) {
592 list
->mAtom
->ToString(temp
);
593 aString
.Append(PRUnichar('.'));
594 aString
.Append(temp
);
599 // Append each attribute selector in the linked list
601 nsAttrSelector
* list
= mAttrList
;
602 while (list
!= nsnull
) {
603 aString
.Append(PRUnichar('['));
604 // Append the namespace prefix
605 if (list
->mNameSpace
> 0) {
607 nsXMLNameSpaceMap
*sheetNS
= aSheet
->GetNameSpaceMap();
608 // will return null if namespace was the default
609 nsIAtom
*prefixAtom
= sheetNS
->FindPrefix(list
->mNameSpace
);
612 prefixAtom
->ToString(prefix
);
613 aString
.Append(prefix
);
614 aString
.Append(PRUnichar('|'));
618 // Append the attribute name
619 list
->mAttr
->ToString(temp
);
620 aString
.Append(temp
);
622 if (list
->mFunction
!= NS_ATTR_FUNC_SET
) {
623 // Append the function
624 if (list
->mFunction
== NS_ATTR_FUNC_INCLUDES
)
625 aString
.Append(PRUnichar('~'));
626 else if (list
->mFunction
== NS_ATTR_FUNC_DASHMATCH
)
627 aString
.Append(PRUnichar('|'));
628 else if (list
->mFunction
== NS_ATTR_FUNC_BEGINSMATCH
)
629 aString
.Append(PRUnichar('^'));
630 else if (list
->mFunction
== NS_ATTR_FUNC_ENDSMATCH
)
631 aString
.Append(PRUnichar('$'));
632 else if (list
->mFunction
== NS_ATTR_FUNC_CONTAINSMATCH
)
633 aString
.Append(PRUnichar('*'));
635 aString
.Append(PRUnichar('='));
638 nsAutoString escaped
;
639 nsStyleUtil::EscapeCSSString(list
->mValue
, escaped
);
641 aString
.Append(PRUnichar('\"'));
642 aString
.Append(escaped
);
643 aString
.Append(PRUnichar('\"'));
646 aString
.Append(PRUnichar(']'));
652 // Append each pseudo-class in the linked list
653 if (mPseudoClassList
) {
654 nsPseudoClassList
* list
= mPseudoClassList
;
655 while (list
!= nsnull
) {
656 list
->mAtom
->ToString(temp
);
657 aString
.Append(temp
);
658 if (list
->u
.mMemory
) {
659 aString
.Append(PRUnichar('('));
660 if (nsCSSPseudoClasses::HasStringArg(list
->mAtom
)) {
661 aString
.Append(list
->u
.mString
);
663 NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(list
->mAtom
),
664 "unexpected pseudo-class");
665 PRInt32 a
= list
->u
.mNumbers
[0],
666 b
= list
->u
.mNumbers
[1];
670 temp
.Append(PRUnichar('-'));
674 temp
.Append(PRUnichar('n'));
676 if (b
!= 0 || a
== 0) {
677 if (b
>= 0 && a
!= 0) // check a != 0 for whether we printed above
678 temp
.Append(PRUnichar('+'));
681 aString
.Append(temp
);
683 aString
.Append(PRUnichar(')'));
690 for (nsCSSSelector
* negation
= mNegations
; negation
;
691 negation
= negation
->mNegations
) {
692 aString
.AppendLiteral(":not(");
693 negation
->ToStringInternal(aString
, aSheet
, PR_FALSE
, PR_TRUE
);
694 aString
.Append(PRUnichar(')'));
698 // Append the operator only if the selector is not negated and is not
700 if (!aIsNegated
&& mOperator
&& !aIsPseudoElem
) {
701 aString
.Append(PRUnichar(' '));
702 aString
.Append(mOperator
);
707 nsCSSSelector::CanBeNamespaced(PRBool aIsNegated
) const
709 return !aIsNegated
||
710 (!mIDList
&& !mClassList
&& !mPseudoClassList
&& !mAttrList
);
713 // -- nsCSSSelectorList -------------------------------
715 nsCSSSelectorList::nsCSSSelectorList(void)
716 : mSelectors(nsnull
),
720 MOZ_COUNT_CTOR(nsCSSSelectorList
);
723 nsCSSSelectorList::~nsCSSSelectorList()
725 MOZ_COUNT_DTOR(nsCSSSelectorList
);
727 NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList
, this, mNext
);
730 void nsCSSSelectorList::AddSelector(nsAutoPtr
<nsCSSSelector
>& aSelector
)
732 nsCSSSelector
* newSel
= aSelector
.forget();
734 newSel
->mNext
= mSelectors
;
740 nsCSSSelectorList::ToString(nsAString
& aResult
, nsICSSStyleSheet
* aSheet
)
743 nsCSSSelectorList
*p
= this;
745 p
->mSelectors
->ToString(aResult
, aSheet
, PR_TRUE
);
749 aResult
.AppendLiteral(", ");
754 nsCSSSelectorList::Clone(PRBool aDeep
) const
756 nsCSSSelectorList
*result
= new nsCSSSelectorList();
757 result
->mWeight
= mWeight
;
758 NS_IF_CLONE(mSelectors
);
761 NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList
, this, mNext
, result
,
767 // -- CSSImportantRule -------------------------------
769 class CSSStyleRuleImpl
;
771 class CSSImportantRule
: public nsIStyleRule
{
773 CSSImportantRule(nsCSSDeclaration
* aDeclaration
);
777 // nsIStyleRule interface
778 NS_IMETHOD
MapRuleInfoInto(nsRuleData
* aRuleData
);
780 NS_IMETHOD
List(FILE* out
= stdout
, PRInt32 aIndent
= 0) const;
784 virtual ~CSSImportantRule(void);
786 nsCSSDeclaration
* mDeclaration
;
788 friend class CSSStyleRuleImpl
;
791 CSSImportantRule::CSSImportantRule(nsCSSDeclaration
* aDeclaration
)
792 : mDeclaration(aDeclaration
)
796 CSSImportantRule::~CSSImportantRule(void)
798 mDeclaration
= nsnull
;
801 NS_IMPL_ISUPPORTS1(CSSImportantRule
, nsIStyleRule
)
804 CSSImportantRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
806 // Check this at runtime because it might be hit in some out-of-memory cases.
807 NS_ENSURE_TRUE(mDeclaration
->HasImportantData(), NS_ERROR_UNEXPECTED
);
809 return mDeclaration
->MapImportantRuleInfoInto(aRuleData
);
814 CSSImportantRule::List(FILE* out
, PRInt32 aIndent
) const
817 for (PRInt32 index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
819 fputs("! Important rule ", out
);
820 if (nsnull
!= mDeclaration
) {
821 mDeclaration
->List(out
);
824 fputs("{ null declaration }", out
);
832 // --------------------------------------------------------
834 class DOMCSSStyleRuleImpl
;
836 class DOMCSSDeclarationImpl
: public nsDOMCSSDeclaration
839 DOMCSSDeclarationImpl(nsICSSStyleRule
*aRule
);
840 virtual ~DOMCSSDeclarationImpl(void);
842 NS_IMETHOD
GetParentRule(nsIDOMCSSRule
**aParent
);
843 virtual void DropReference(void);
844 virtual nsresult
GetCSSDeclaration(nsCSSDeclaration
**aDecl
,
846 virtual nsresult
GetCSSParsingEnvironment(nsIURI
** aSheetURI
,
848 nsIPrincipal
** aSheetPrincipal
,
849 nsICSSLoader
** aCSSLoader
,
850 nsICSSParser
** aCSSParser
);
851 virtual nsresult
DeclarationChanged();
853 // Override |AddRef| and |Release| for being a member of
854 // |DOMCSSStyleRuleImpl|.
855 NS_IMETHOD_(nsrefcnt
) AddRef(void);
856 NS_IMETHOD_(nsrefcnt
) Release(void);
858 friend class DOMCSSStyleRuleImpl
;
861 // This reference is not reference-counted. The rule object tells us
862 // when it's about to go away.
863 nsICSSStyleRule
*mRule
;
865 inline DOMCSSStyleRuleImpl
* DomRule();
868 // NOT TO BE IMPLEMENTED
869 // This object cannot be allocated on its own. It must be a member of
870 // DOMCSSStyleRuleImpl.
871 void* operator new(size_t size
) CPP_THROW_NEW
;
874 class DOMCSSStyleRuleImpl
: public nsICSSStyleRuleDOMWrapper
877 DOMCSSStyleRuleImpl(nsICSSStyleRule
*aRule
);
878 virtual ~DOMCSSStyleRuleImpl();
881 NS_DECL_NSIDOMCSSRULE
882 NS_DECL_NSIDOMCSSSTYLERULE
884 // nsICSSStyleRuleDOMWrapper
885 NS_IMETHOD
GetCSSStyleRule(nsICSSStyleRule
**aResult
);
887 DOMCSSDeclarationImpl
* DOMDeclaration() { return &mDOMDeclaration
; }
889 friend class DOMCSSDeclarationImpl
;
892 DOMCSSDeclarationImpl mDOMDeclaration
;
894 nsICSSStyleRule
* Rule() {
895 return mDOMDeclaration
.mRule
;
899 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(nsICSSStyleRule
*aRule
)
902 MOZ_COUNT_CTOR(DOMCSSDeclarationImpl
);
905 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
907 NS_ASSERTION(!mRule
, "DropReference not called.");
909 MOZ_COUNT_DTOR(DOMCSSDeclarationImpl
);
912 inline DOMCSSStyleRuleImpl
* DOMCSSDeclarationImpl::DomRule()
914 return reinterpret_cast<DOMCSSStyleRuleImpl
*>
915 (reinterpret_cast<char*>(this) -
916 offsetof(DOMCSSStyleRuleImpl
, mDOMDeclaration
));
919 NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl
, DomRule())
920 NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl
, DomRule())
923 DOMCSSDeclarationImpl::DropReference(void)
929 DOMCSSDeclarationImpl::GetCSSDeclaration(nsCSSDeclaration
**aDecl
,
933 *aDecl
= mRule
->GetDeclaration();
943 * This is a utility function. It will only fail if it can't get a
944 * parser. This means it can return NS_OK without aURI or aCSSLoader
948 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(nsIURI
** aSheetURI
,
950 nsIPrincipal
** aSheetPrincipal
,
951 nsICSSLoader
** aCSSLoader
,
952 nsICSSParser
** aCSSParser
)
954 // null out the out params since some of them may not get initialized below
957 *aSheetPrincipal
= nsnull
;
958 *aCSSLoader
= nsnull
;
959 *aCSSParser
= nsnull
;
961 nsCOMPtr
<nsIStyleSheet
> sheet
;
963 mRule
->GetStyleSheet(*getter_AddRefs(sheet
));
965 sheet
->GetSheetURI(aSheetURI
);
966 sheet
->GetBaseURI(aBaseURI
);
968 nsCOMPtr
<nsICSSStyleSheet
> cssSheet(do_QueryInterface(sheet
));
970 NS_ADDREF(*aSheetPrincipal
= cssSheet
->Principal());
973 nsCOMPtr
<nsIDocument
> document
;
974 sheet
->GetOwningDocument(*getter_AddRefs(document
));
976 NS_ADDREF(*aCSSLoader
= document
->CSSLoader());
980 // XXXldb Why bother if |mRule| is null?
982 result
= (*aCSSLoader
)->GetParserFor(nsnull
, aCSSParser
);
984 result
= NS_NewCSSParser(aCSSParser
);
987 if (NS_SUCCEEDED(result
) && !*aSheetPrincipal
) {
988 result
= CallCreateInstance("@mozilla.org/nullprincipal;1",
996 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule
**aParent
)
998 NS_ENSURE_ARG_POINTER(aParent
);
1005 return mRule
->GetDOMRule(aParent
);
1009 DOMCSSDeclarationImpl::DeclarationChanged()
1011 NS_PRECONDITION(mRule
,
1012 "can only be called when |GetCSSDeclaration| returned a declaration");
1014 nsCOMPtr
<nsIDocument
> owningDoc
;
1015 nsCOMPtr
<nsIStyleSheet
> sheet
;
1016 mRule
->GetStyleSheet(*getter_AddRefs(sheet
));
1018 sheet
->GetOwningDocument(*getter_AddRefs(owningDoc
));
1021 mozAutoDocUpdate
updateBatch(owningDoc
, UPDATE_STYLE
, PR_TRUE
);
1023 nsCOMPtr
<nsICSSStyleRule
> oldRule
= mRule
;
1024 mRule
= oldRule
->DeclarationChanged(PR_TRUE
).get();
1026 return NS_ERROR_OUT_OF_MEMORY
;
1027 nsrefcnt cnt
= mRule
->Release();
1029 NS_NOTREACHED("container didn't take ownership");
1031 return NS_ERROR_UNEXPECTED
;
1035 owningDoc
->StyleRuleChanged(sheet
, oldRule
, mRule
);
1040 DOMCSSStyleRuleImpl::DOMCSSStyleRuleImpl(nsICSSStyleRule
* aRule
)
1041 : mDOMDeclaration(aRule
)
1045 DOMCSSStyleRuleImpl::~DOMCSSStyleRuleImpl()
1049 NS_INTERFACE_MAP_BEGIN(DOMCSSStyleRuleImpl
)
1050 NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper
)
1051 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule
)
1052 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule
)
1053 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1054 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleRule
)
1055 NS_INTERFACE_MAP_END
1057 NS_IMPL_ADDREF(DOMCSSStyleRuleImpl
)
1058 NS_IMPL_RELEASE(DOMCSSStyleRuleImpl
)
1061 DOMCSSStyleRuleImpl::GetType(PRUint16
* aType
)
1063 *aType
= nsIDOMCSSRule::STYLE_RULE
;
1069 DOMCSSStyleRuleImpl::GetCssText(nsAString
& aCssText
)
1072 aCssText
.Truncate();
1075 return Rule()->GetCssText(aCssText
);
1079 DOMCSSStyleRuleImpl::SetCssText(const nsAString
& aCssText
)
1084 return Rule()->SetCssText(aCssText
);
1088 DOMCSSStyleRuleImpl::GetParentStyleSheet(nsIDOMCSSStyleSheet
** aSheet
)
1094 nsCOMPtr
<nsICSSStyleSheet
> sheet
;
1095 Rule()->GetParentStyleSheet(getter_AddRefs(sheet
));
1100 return CallQueryInterface(sheet
, aSheet
);
1104 DOMCSSStyleRuleImpl::GetParentRule(nsIDOMCSSRule
** aParentRule
)
1107 *aParentRule
= nsnull
;
1110 nsCOMPtr
<nsICSSGroupRule
> rule
;
1111 Rule()->GetParentRule(getter_AddRefs(rule
));
1113 *aParentRule
= nsnull
;
1116 return rule
->GetDOMRule(aParentRule
);
1120 DOMCSSStyleRuleImpl::GetSelectorText(nsAString
& aSelectorText
)
1123 aSelectorText
.Truncate();
1126 return Rule()->GetSelectorText(aSelectorText
);
1130 DOMCSSStyleRuleImpl::SetSelectorText(const nsAString
& aSelectorText
)
1135 return Rule()->SetSelectorText(aSelectorText
);
1139 DOMCSSStyleRuleImpl::GetStyle(nsIDOMCSSStyleDeclaration
** aStyle
)
1141 *aStyle
= &mDOMDeclaration
;
1147 DOMCSSStyleRuleImpl::GetCSSStyleRule(nsICSSStyleRule
**aResult
)
1150 NS_IF_ADDREF(*aResult
);
1154 // -- nsCSSStyleRule -------------------------------
1156 class CSSStyleRuleImpl
: public nsCSSRule
,
1157 public nsICSSStyleRule
1160 CSSStyleRuleImpl(nsCSSSelectorList
* aSelector
,
1161 nsCSSDeclaration
*aDeclaration
);
1164 CSSStyleRuleImpl(const CSSStyleRuleImpl
& aCopy
);
1165 // for |DeclarationChanged|
1166 CSSStyleRuleImpl(CSSStyleRuleImpl
& aCopy
,
1167 nsCSSDeclaration
*aDeclaration
);
1170 NS_DECL_ISUPPORTS_INHERITED
1172 virtual nsCSSSelectorList
* Selector(void);
1174 virtual PRUint32
GetLineNumber(void) const;
1175 virtual void SetLineNumber(PRUint32 aLineNumber
);
1177 virtual nsCSSDeclaration
* GetDeclaration(void) const;
1179 virtual already_AddRefed
<nsIStyleRule
> GetImportantRule(void);
1181 NS_IMETHOD
GetStyleSheet(nsIStyleSheet
*& aSheet
) const;
1182 NS_IMETHOD
SetStyleSheet(nsICSSStyleSheet
* aSheet
);
1184 NS_IMETHOD
SetParentRule(nsICSSGroupRule
* aRule
);
1186 virtual nsresult
GetCssText(nsAString
& aCssText
);
1187 virtual nsresult
SetCssText(const nsAString
& aCssText
);
1188 virtual nsresult
GetParentStyleSheet(nsICSSStyleSheet
** aSheet
);
1189 virtual nsresult
GetParentRule(nsICSSGroupRule
** aParentRule
);
1190 virtual nsresult
GetSelectorText(nsAString
& aSelectorText
);
1191 virtual nsresult
SetSelectorText(const nsAString
& aSelectorText
);
1193 NS_IMETHOD
GetType(PRInt32
& aType
) const;
1194 NS_IMETHOD
Clone(nsICSSRule
*& aClone
) const;
1196 nsIDOMCSSRule
* GetDOMRuleWeak(nsresult
* aResult
);
1198 virtual already_AddRefed
<nsICSSStyleRule
>
1199 DeclarationChanged(PRBool aHandleContainer
);
1201 // The new mapping function.
1202 NS_IMETHOD
MapRuleInfoInto(nsRuleData
* aRuleData
);
1205 NS_IMETHOD
List(FILE* out
= stdout
, PRInt32 aIndent
= 0) const;
1209 // These are not supported and are not implemented!
1210 CSSStyleRuleImpl
& operator=(const CSSStyleRuleImpl
& aCopy
);
1213 virtual ~CSSStyleRuleImpl(void);
1216 nsCSSSelectorList
* mSelector
; // null for style attribute
1217 nsCSSDeclaration
* mDeclaration
;
1218 CSSImportantRule
* mImportantRule
;
1219 DOMCSSStyleRuleImpl
* mDOMRule
;
1220 PRUint32 mLineNumber
;
1223 CSSStyleRuleImpl::CSSStyleRuleImpl(nsCSSSelectorList
* aSelector
,
1224 nsCSSDeclaration
* aDeclaration
)
1226 mSelector(aSelector
),
1227 mDeclaration(aDeclaration
),
1228 mImportantRule(nsnull
),
1232 mDeclaration
->AddRef();
1236 CSSStyleRuleImpl::CSSStyleRuleImpl(const CSSStyleRuleImpl
& aCopy
)
1238 mSelector(aCopy
.mSelector
? aCopy
.mSelector
->Clone() : nsnull
),
1239 mDeclaration(aCopy
.mDeclaration
->Clone()),
1240 mImportantRule(nsnull
),
1242 mLineNumber(aCopy
.mLineNumber
)
1245 mDeclaration
->AddRef();
1246 // rest is constructed lazily on existing data
1249 // for |DeclarationChanged|
1250 CSSStyleRuleImpl::CSSStyleRuleImpl(CSSStyleRuleImpl
& aCopy
,
1251 nsCSSDeclaration
* aDeclaration
)
1253 mSelector(aCopy
.mSelector
),
1254 mDeclaration(aDeclaration
),
1255 mImportantRule(nsnull
),
1256 mDOMRule(aCopy
.mDOMRule
),
1257 mLineNumber(aCopy
.mLineNumber
)
1259 // The DOM rule is replacing |aCopy| with |this|, so transfer
1260 // the reverse pointer as well (and transfer ownership).
1261 aCopy
.mDOMRule
= nsnull
;
1263 NS_ASSERTION(aDeclaration
== aCopy
.mDeclaration
, "declaration mismatch");
1264 // Transfer ownership of selector and declaration:
1265 aCopy
.mSelector
= nsnull
;
1267 aCopy
.mDeclaration
= nsnull
;
1269 // We ought to be able to transfer ownership of the selector and the
1270 // declaration since this rule should now be unused, but unfortunately
1271 // SetInlineStyleRule might use it before setting the new rule (see
1272 // stack in bug 209575). So leave the declaration pointer on the old
1274 mDeclaration
->AddRef();
1279 CSSStyleRuleImpl::~CSSStyleRuleImpl(void)
1285 if (nsnull
!= mDeclaration
) {
1286 mDeclaration
->Release();
1287 mDeclaration
= nsnull
;
1289 if (nsnull
!= mImportantRule
) {
1290 NS_RELEASE(mImportantRule
);
1291 mImportantRule
= nsnull
;
1294 mDOMRule
->DOMDeclaration()->DropReference();
1295 NS_RELEASE(mDOMRule
);
1299 // QueryInterface implementation for CSSStyleRuleImpl
1300 NS_INTERFACE_MAP_BEGIN(CSSStyleRuleImpl
)
1301 NS_INTERFACE_MAP_ENTRY(nsICSSStyleRule
)
1302 NS_INTERFACE_MAP_ENTRY(nsICSSRule
)
1303 NS_INTERFACE_MAP_ENTRY(nsIStyleRule
)
1304 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsICSSStyleRule
)
1305 NS_INTERFACE_MAP_END
1307 NS_IMPL_ADDREF_INHERITED(CSSStyleRuleImpl
, nsCSSRule
)
1308 NS_IMPL_RELEASE_INHERITED(CSSStyleRuleImpl
, nsCSSRule
)
1310 nsCSSSelectorList
* CSSStyleRuleImpl::Selector(void)
1315 PRUint32
CSSStyleRuleImpl::GetLineNumber(void) const
1320 void CSSStyleRuleImpl::SetLineNumber(PRUint32 aLineNumber
)
1322 mLineNumber
= aLineNumber
;
1325 nsCSSDeclaration
* CSSStyleRuleImpl::GetDeclaration(void) const
1327 return mDeclaration
;
1330 already_AddRefed
<nsIStyleRule
> CSSStyleRuleImpl::GetImportantRule(void)
1332 if (!mDeclaration
->HasImportantData()) {
1333 NS_ASSERTION(!mImportantRule
, "immutable, so should be no important rule");
1337 if (!mImportantRule
) {
1338 mImportantRule
= new CSSImportantRule(mDeclaration
);
1339 if (!mImportantRule
)
1341 NS_ADDREF(mImportantRule
);
1343 NS_ADDREF(mImportantRule
);
1344 return mImportantRule
;
1348 CSSStyleRuleImpl::GetStyleSheet(nsIStyleSheet
*& aSheet
) const
1350 // XXX What about inner, etc.
1351 return nsCSSRule::GetStyleSheet(aSheet
);
1355 CSSStyleRuleImpl::SetStyleSheet(nsICSSStyleSheet
* aSheet
)
1357 return nsCSSRule::SetStyleSheet(aSheet
);
1361 CSSStyleRuleImpl::SetParentRule(nsICSSGroupRule
* aRule
)
1363 return nsCSSRule::SetParentRule(aRule
);
1367 CSSStyleRuleImpl::GetType(PRInt32
& aType
) const
1369 aType
= nsICSSRule::STYLE_RULE
;
1374 CSSStyleRuleImpl::Clone(nsICSSRule
*& aClone
) const
1376 CSSStyleRuleImpl
* clone
= new CSSStyleRuleImpl(*this);
1377 if (!clone
|| !clone
->mDeclaration
|| (!clone
->mSelector
!= !mSelector
)) {
1380 return NS_ERROR_OUT_OF_MEMORY
;
1382 return CallQueryInterface(clone
, &aClone
);
1386 CSSStyleRuleImpl::GetDOMRuleWeak(nsresult
*aResult
)
1390 // inline style rules aren't supposed to have a DOM rule object, only
1395 mDOMRule
= new DOMCSSStyleRuleImpl(this);
1397 *aResult
= NS_ERROR_OUT_OF_MEMORY
;
1400 NS_ADDREF(mDOMRule
);
1405 /* virtual */ already_AddRefed
<nsICSSStyleRule
>
1406 CSSStyleRuleImpl::DeclarationChanged(PRBool aHandleContainer
)
1408 CSSStyleRuleImpl
* clone
= new CSSStyleRuleImpl(*this, mDeclaration
);
1413 NS_ADDREF(clone
); // for return
1415 if (aHandleContainer
) {
1416 NS_ASSERTION(mSheet
, "rule must be in a sheet");
1418 mSheet
->ReplaceRuleInGroup(mParentRule
, this, clone
);
1420 mSheet
->ReplaceStyleRule(this, clone
);
1428 CSSStyleRuleImpl::MapRuleInfoInto(nsRuleData
* aRuleData
)
1430 return mDeclaration
->MapRuleInfoInto(aRuleData
);
1435 CSSStyleRuleImpl::List(FILE* out
, PRInt32 aIndent
) const
1438 for (PRInt32 index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
1440 nsAutoString buffer
;
1442 mSelector
->ToString(buffer
, mSheet
);
1444 buffer
.AppendLiteral(" ");
1445 fputs(NS_LossyConvertUTF16toASCII(buffer
).get(), out
);
1446 if (nsnull
!= mDeclaration
) {
1447 mDeclaration
->List(out
);
1450 fputs("{ null declaration }", out
);
1458 /* virtual */ nsresult
1459 CSSStyleRuleImpl::GetCssText(nsAString
& aCssText
)
1462 mSelector
->ToString(aCssText
, mSheet
);
1463 aCssText
.Append(PRUnichar(' '));
1465 aCssText
.Append(PRUnichar('{'));
1466 aCssText
.Append(PRUnichar(' '));
1469 nsAutoString tempString
;
1470 mDeclaration
->ToString( tempString
);
1471 aCssText
.Append( tempString
);
1473 aCssText
.Append(PRUnichar(' '));
1474 aCssText
.Append(PRUnichar('}'));
1478 /* virtual */ nsresult
1479 CSSStyleRuleImpl::SetCssText(const nsAString
& aCssText
)
1481 // XXX TBI - need to re-parse rule & declaration
1485 /* virtual */ nsresult
1486 CSSStyleRuleImpl::GetParentStyleSheet(nsICSSStyleSheet
** aSheet
)
1489 NS_IF_ADDREF(*aSheet
);
1493 /* virtual */ nsresult
1494 CSSStyleRuleImpl::GetParentRule(nsICSSGroupRule
** aParentRule
)
1496 *aParentRule
= mParentRule
;
1497 NS_IF_ADDREF(*aParentRule
);
1501 /* virtual */ nsresult
1502 CSSStyleRuleImpl::GetSelectorText(nsAString
& aSelectorText
)
1505 mSelector
->ToString(aSelectorText
, mSheet
);
1507 aSelectorText
.Truncate();
1511 /* virtual */ nsresult
1512 CSSStyleRuleImpl::SetSelectorText(const nsAString
& aSelectorText
)
1514 // XXX TBI - get a parser and re-parse the selectors,
1515 // XXX then need to re-compute the cascade
1516 // XXX and dirty sheet
1521 NS_NewCSSStyleRule(nsICSSStyleRule
** aInstancePtrResult
,
1522 nsCSSSelectorList
* aSelector
,
1523 nsCSSDeclaration
* aDeclaration
)
1525 NS_PRECONDITION(aDeclaration
, "must have a declaration");
1526 CSSStyleRuleImpl
*it
= new CSSStyleRuleImpl(aSelector
, aDeclaration
);
1528 return NS_ERROR_OUT_OF_MEMORY
;
1531 return CallQueryInterface(it
, aInstancePtrResult
);