1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * L. David Baron <dbaron@dbaron.org>
25 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Daniel Glazman <glazman@netscape.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 /* representation of a CSS style sheet */
44 #include "nsCSSStyleSheet.h"
48 #include "nsIServiceManager.h"
49 #include "nsCSSRuleProcessor.h"
50 #include "nsICSSStyleRule.h"
51 #include "nsICSSNameSpaceRule.h"
52 #include "nsICSSGroupRule.h"
53 #include "nsICSSImportRule.h"
54 #include "nsIMediaList.h"
55 #include "nsIDocument.h"
56 #include "nsPresContext.h"
57 #include "nsGkAtoms.h"
59 #include "nsVoidArray.h"
60 #include "nsIDOMStyleSheetList.h"
61 #include "nsIDOMCSSStyleSheet.h"
62 #include "nsIDOMCSSRule.h"
63 #include "nsIDOMCSSImportRule.h"
64 #include "nsIDOMCSSRuleList.h"
65 #include "nsIDOMMediaList.h"
66 #include "nsIDOMNode.h"
67 #include "nsDOMError.h"
68 #include "nsICSSParser.h"
69 #include "nsICSSLoader.h"
70 #include "nsICSSLoaderObserver.h"
71 #include "nsINameSpaceManager.h"
72 #include "nsXMLNameSpaceMap.h"
74 #include "nsContentUtils.h"
75 #include "nsIJSContextStack.h"
76 #include "nsIScriptSecurityManager.h"
77 #include "mozAutoDocUpdate.h"
78 #include "nsCSSDeclaration.h"
79 #include "nsRuleNode.h"
81 // -------------------------------
82 // Style Rule List for the DOM
84 class CSSRuleListImpl
: public nsIDOMCSSRuleList
87 CSSRuleListImpl(nsCSSStyleSheet
*aStyleSheet
);
91 // nsIDOMCSSRuleList interface
92 NS_IMETHOD
GetLength(PRUint32
* aLength
);
93 NS_IMETHOD
Item(PRUint32 aIndex
, nsIDOMCSSRule
** aReturn
);
95 void DropReference() { mStyleSheet
= nsnull
; }
98 virtual ~CSSRuleListImpl();
100 nsCSSStyleSheet
* mStyleSheet
;
102 PRBool mRulesAccessed
;
105 CSSRuleListImpl::CSSRuleListImpl(nsCSSStyleSheet
*aStyleSheet
)
107 // Not reference counted to avoid circular references.
108 // The style sheet will tell us when its going away.
109 mStyleSheet
= aStyleSheet
;
110 mRulesAccessed
= PR_FALSE
;
113 CSSRuleListImpl::~CSSRuleListImpl()
117 // QueryInterface implementation for CSSRuleList
118 NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl
)
119 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList
)
120 NS_INTERFACE_MAP_ENTRY(nsISupports
)
121 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSRuleList
)
125 NS_IMPL_ADDREF(CSSRuleListImpl
)
126 NS_IMPL_RELEASE(CSSRuleListImpl
)
130 CSSRuleListImpl::GetLength(PRUint32
* aLength
)
132 if (nsnull
!= mStyleSheet
) {
134 mStyleSheet
->StyleRuleCount(count
);
135 *aLength
= (PRUint32
)count
;
145 CSSRuleListImpl::Item(PRUint32 aIndex
, nsIDOMCSSRule
** aReturn
)
147 nsresult result
= NS_OK
;
151 result
= mStyleSheet
->EnsureUniqueInner(); // needed to ensure rules have correct parent
152 if (NS_SUCCEEDED(result
)) {
153 nsCOMPtr
<nsICSSRule
> rule
;
155 result
= mStyleSheet
->GetStyleRuleAt(aIndex
, *getter_AddRefs(rule
));
157 result
= rule
->GetDOMRule(aReturn
);
158 mRulesAccessed
= PR_TRUE
; // signal to never share rules again
159 } else if (result
== NS_ERROR_ILLEGAL_VALUE
) {
160 result
= NS_OK
; // per spec: "Return Value ... null if ... not a valid index."
168 template <class Numeric
>
169 PRInt32
DoCompare(Numeric a
, Numeric b
)
179 nsMediaExpression::Matches(nsPresContext
*aPresContext
,
180 const nsCSSValue
& aActualValue
) const
182 const nsCSSValue
& actual
= aActualValue
;
183 const nsCSSValue
& required
= mValue
;
185 // If we don't have the feature, the match fails.
186 if (actual
.GetUnit() == eCSSUnit_Null
) {
190 // If the expression had no value to match, the match succeeds,
191 // unless the value is an integer 0.
192 if (required
.GetUnit() == eCSSUnit_Null
) {
193 return actual
.GetUnit() != eCSSUnit_Integer
||
194 actual
.GetIntValue() != 0;
197 NS_ASSERTION(mFeature
->mRangeType
== nsMediaFeature::eMinMaxAllowed
||
198 mRange
== nsMediaExpression::eEqual
, "yikes");
199 PRInt32 cmp
; // -1 (actual < required)
200 // 0 (actual == required)
201 // 1 (actual > required)
202 switch (mFeature
->mValueType
) {
203 case nsMediaFeature::eLength
:
205 NS_ASSERTION(actual
.IsLengthUnit(), "bad actual value");
206 NS_ASSERTION(required
.IsLengthUnit(), "bad required value");
207 nscoord actualCoord
= nsRuleNode::CalcLengthWithInitialFont(
208 aPresContext
, actual
);
209 nscoord requiredCoord
= nsRuleNode::CalcLengthWithInitialFont(
210 aPresContext
, required
);
211 cmp
= DoCompare(actualCoord
, requiredCoord
);
214 case nsMediaFeature::eInteger
:
216 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Integer
,
218 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Integer
,
219 "bad required value");
220 cmp
= DoCompare(actual
.GetIntValue(), required
.GetIntValue());
223 case nsMediaFeature::eIntRatio
:
225 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Array
&&
226 actual
.GetArrayValue()->Count() == 2 &&
227 actual
.GetArrayValue()->Item(0).GetUnit() ==
229 actual
.GetArrayValue()->Item(1).GetUnit() ==
232 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Array
&&
233 required
.GetArrayValue()->Count() == 2 &&
234 required
.GetArrayValue()->Item(0).GetUnit() ==
236 required
.GetArrayValue()->Item(1).GetUnit() ==
238 "bad required value");
239 // Convert to PRInt64 so we can multiply without worry. Note
240 // that while the spec requires that both halves of |required|
241 // be positive, the numerator or denominator of |actual| might
242 // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
244 PRInt64 actualNum
= actual
.GetArrayValue()->Item(0).GetIntValue(),
245 actualDen
= actual
.GetArrayValue()->Item(1).GetIntValue(),
246 requiredNum
= required
.GetArrayValue()->Item(0).GetIntValue(),
247 requiredDen
= required
.GetArrayValue()->Item(1).GetIntValue();
248 cmp
= DoCompare(actualNum
* requiredDen
, requiredNum
* actualDen
);
251 case nsMediaFeature::eResolution
:
253 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Inch
||
254 actual
.GetUnit() == eCSSUnit_Centimeter
,
256 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Inch
||
257 required
.GetUnit() == eCSSUnit_Centimeter
,
258 "bad required value");
259 float actualDPI
= actual
.GetFloatValue();
260 if (actual
.GetUnit() == eCSSUnit_Centimeter
)
261 actualDPI
= actualDPI
* 2.54f
;
262 float requiredDPI
= required
.GetFloatValue();
263 if (required
.GetUnit() == eCSSUnit_Centimeter
)
264 requiredDPI
= requiredDPI
* 2.54f
;
265 cmp
= DoCompare(actualDPI
, requiredDPI
);
268 case nsMediaFeature::eEnumerated
:
270 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Enumerated
,
272 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Enumerated
,
273 "bad required value");
274 NS_ASSERTION(mFeature
->mRangeType
== nsMediaFeature::eMinMaxNotAllowed
,
275 "bad range"); // we asserted above about mRange
276 // We don't really need DoCompare, but it doesn't hurt (and
277 // maybe the compiler will condense this case with eInteger).
278 cmp
= DoCompare(actual
.GetIntValue(), required
.GetIntValue());
283 case nsMediaExpression::eMin
:
285 case nsMediaExpression::eMax
:
287 case nsMediaExpression::eEqual
:
290 NS_NOTREACHED("unexpected mRange");
295 nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression
* aExpression
,
296 PRBool aExpressionMatches
)
298 const nsMediaFeature
*feature
= aExpression
->mFeature
;
299 FeatureEntry
*entry
= nsnull
;
300 for (PRUint32 i
= 0; i
< mFeatureCache
.Length(); ++i
) {
301 if (mFeatureCache
[i
].mFeature
== feature
) {
302 entry
= &mFeatureCache
[i
];
307 entry
= mFeatureCache
.AppendElement();
309 return; /* out of memory */
311 entry
->mFeature
= feature
;
314 ExpressionEntry eentry
= { *aExpression
, aExpressionMatches
};
315 entry
->mExpressions
.AppendElement(eentry
);
319 nsMediaQueryResultCacheKey::Matches(nsPresContext
* aPresContext
) const
321 if (aPresContext
->Medium() != mMedium
) {
325 for (PRUint32 i
= 0; i
< mFeatureCache
.Length(); ++i
) {
326 const FeatureEntry
*entry
= &mFeatureCache
[i
];
328 nsresult rv
= (entry
->mFeature
->mGetter
)(aPresContext
, actual
);
329 NS_ENSURE_SUCCESS(rv
, PR_FALSE
); // any better ideas?
331 for (PRUint32 j
= 0; j
< entry
->mExpressions
.Length(); ++j
) {
332 const ExpressionEntry
&eentry
= entry
->mExpressions
[j
];
333 if (eentry
.mExpression
.Matches(aPresContext
, actual
) !=
334 eentry
.mExpressionMatches
) {
344 nsMediaQuery::AppendToString(nsAString
& aString
) const
348 if (mHadUnknownExpression
) {
349 aString
.AppendLiteral("not all");
353 NS_ASSERTION(!mNegated
|| !mHasOnly
, "can't have not and only");
354 NS_ASSERTION(!mTypeOmitted
|| (!mNegated
&& !mHasOnly
),
355 "can't have not or only when type is omitted");
358 aString
.AppendLiteral("not ");
359 } else if (mHasOnly
) {
360 aString
.AppendLiteral("only ");
362 mMediaType
->ToString(buffer
);
363 aString
.Append(buffer
);
367 for (PRUint32 i
= 0, i_end
= mExpressions
.Length(); i
< i_end
; ++i
) {
368 if (i
> 0 || !mTypeOmitted
)
369 aString
.AppendLiteral(" and ");
370 aString
.AppendLiteral("(");
372 const nsMediaExpression
&expr
= mExpressions
[i
];
373 if (expr
.mRange
== nsMediaExpression::eMin
) {
374 aString
.AppendLiteral("min-");
375 } else if (expr
.mRange
== nsMediaExpression::eMax
) {
376 aString
.AppendLiteral("max-");
379 const nsMediaFeature
*feature
= expr
.mFeature
;
380 (*feature
->mName
)->ToString(buffer
);
381 aString
.Append(buffer
);
384 if (expr
.mValue
.GetUnit() != eCSSUnit_Null
) {
385 aString
.AppendLiteral(": ");
386 switch (feature
->mValueType
) {
387 case nsMediaFeature::eLength
:
388 NS_ASSERTION(expr
.mValue
.IsLengthUnit(), "bad unit");
389 // Use 'width' as a property that takes length values
390 // written in the normal way.
391 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_width
,
392 expr
.mValue
, aString
);
394 case nsMediaFeature::eInteger
:
395 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Integer
,
397 // Use 'z-index' as a property that takes integer values
398 // written without anything extra.
399 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index
,
400 expr
.mValue
, aString
);
402 case nsMediaFeature::eIntRatio
:
404 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Array
,
406 nsCSSValue::Array
*array
= expr
.mValue
.GetArrayValue();
407 NS_ASSERTION(array
->Count() == 2, "unexpected length");
408 NS_ASSERTION(array
->Item(0).GetUnit() == eCSSUnit_Integer
,
410 NS_ASSERTION(array
->Item(1).GetUnit() == eCSSUnit_Integer
,
412 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index
,
413 array
->Item(0), aString
);
414 aString
.AppendLiteral("/");
415 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index
,
416 array
->Item(1), aString
);
419 case nsMediaFeature::eResolution
:
420 buffer
.AppendFloat(expr
.mValue
.GetFloatValue());
421 aString
.Append(buffer
);
423 if (expr
.mValue
.GetUnit() == eCSSUnit_Inch
) {
424 aString
.AppendLiteral("dpi");
426 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Centimeter
,
428 aString
.AppendLiteral("dpcm");
431 case nsMediaFeature::eEnumerated
:
432 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Enumerated
,
435 nsCSSProps::ValueToKeyword(expr
.mValue
.GetIntValue(),
436 feature
->mKeywordTable
),
442 aString
.AppendLiteral(")");
447 nsMediaQuery::Clone() const
449 nsAutoPtr
<nsMediaQuery
> result(new nsMediaQuery(*this));
450 NS_ENSURE_TRUE(result
&&
451 result
->mExpressions
.Length() == mExpressions
.Length(),
453 return result
.forget();
457 nsMediaQuery::Matches(nsPresContext
* aPresContext
,
458 nsMediaQueryResultCacheKey
& aKey
) const
460 if (mHadUnknownExpression
)
464 mMediaType
== aPresContext
->Medium() || mMediaType
== nsGkAtoms::all
;
465 for (PRUint32 i
= 0, i_end
= mExpressions
.Length(); match
&& i
< i_end
; ++i
) {
466 const nsMediaExpression
&expr
= mExpressions
[i
];
468 nsresult rv
= (expr
.mFeature
->mGetter
)(aPresContext
, actual
);
469 NS_ENSURE_SUCCESS(rv
, PR_FALSE
); // any better ideas?
471 match
= expr
.Matches(aPresContext
, actual
);
472 aKey
.AddExpression(&expr
, match
);
475 return match
== !mNegated
;
478 NS_INTERFACE_MAP_BEGIN(nsMediaList
)
479 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList
)
480 NS_INTERFACE_MAP_ENTRY(nsISupports
)
481 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(MediaList
)
484 NS_IMPL_ADDREF(nsMediaList
)
485 NS_IMPL_RELEASE(nsMediaList
)
488 nsMediaList::nsMediaList()
490 , mStyleSheet(nsnull
)
494 nsMediaList::~nsMediaList()
499 nsMediaList::GetText(nsAString
& aMediaText
)
501 aMediaText
.Truncate();
503 if (mArray
.Length() == 0 && !mIsEmpty
) {
504 aMediaText
.AppendLiteral("not all");
507 for (PRInt32 i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
508 nsMediaQuery
* query
= mArray
[i
];
509 NS_ENSURE_TRUE(query
, NS_ERROR_FAILURE
);
511 query
->AppendToString(aMediaText
);
514 aMediaText
.AppendLiteral(", ");
521 // XXXbz this is so ill-defined in the spec, it's not clear quite what
522 // it should be doing....
524 nsMediaList::SetText(const nsAString
& aMediaText
)
526 nsCOMPtr
<nsICSSParser
> parser
;
527 nsresult rv
= NS_NewCSSParser(getter_AddRefs(parser
));
528 NS_ENSURE_SUCCESS(rv
, rv
);
530 PRBool htmlMode
= PR_FALSE
;
531 nsCOMPtr
<nsIDOMStyleSheet
> domSheet
=
532 do_QueryInterface(static_cast<nsICSSStyleSheet
*>(mStyleSheet
));
534 nsCOMPtr
<nsIDOMNode
> node
;
535 domSheet
->GetOwnerNode(getter_AddRefs(node
));
539 return parser
->ParseMediaList(nsString(aMediaText
), nsnull
, 0,
544 nsMediaList::Matches(nsPresContext
* aPresContext
,
545 nsMediaQueryResultCacheKey
& aKey
)
547 for (PRInt32 i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
548 if (mArray
[i
]->Matches(aPresContext
, aKey
)) {
556 nsMediaList::SetStyleSheet(nsICSSStyleSheet
*aSheet
)
558 NS_ASSERTION(aSheet
== mStyleSheet
|| !aSheet
|| !mStyleSheet
,
559 "multiple style sheets competing for one media list");
560 mStyleSheet
= static_cast<nsCSSStyleSheet
*>(aSheet
);
565 nsMediaList::Clone(nsMediaList
** aResult
)
567 nsRefPtr
<nsMediaList
> result
= new nsMediaList();
568 if (!result
|| !result
->mArray
.AppendElements(mArray
.Length()))
569 return NS_ERROR_OUT_OF_MEMORY
;
570 for (PRInt32 i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
571 if (!(result
->mArray
[i
] = mArray
[i
]->Clone())) {
572 return NS_ERROR_OUT_OF_MEMORY
;
575 NS_ADDREF(*aResult
= result
);
580 nsMediaList::GetMediaText(nsAString
& aMediaText
)
582 return GetText(aMediaText
);
585 // "sheet" should be an nsCSSStyleSheet and "doc" should be an
586 // nsCOMPtr<nsIDocument>
587 #define BEGIN_MEDIA_CHANGE(sheet, doc) \
589 rv = sheet->GetOwningDocument(*getter_AddRefs(doc)); \
590 NS_ENSURE_SUCCESS(rv, rv); \
592 mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE); \
594 rv = sheet->WillDirty(); \
595 NS_ENSURE_SUCCESS(rv, rv); \
598 #define END_MEDIA_CHANGE(sheet, doc) \
602 /* XXXldb Pass something meaningful? */ \
604 doc->StyleRuleChanged(sheet, nsnull, nsnull); \
609 nsMediaList::SetMediaText(const nsAString
& aMediaText
)
612 nsCOMPtr
<nsIDocument
> doc
;
614 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
616 rv
= SetText(aMediaText
);
620 END_MEDIA_CHANGE(mStyleSheet
, doc
)
626 nsMediaList::GetLength(PRUint32
* aLength
)
628 NS_ENSURE_ARG_POINTER(aLength
);
630 *aLength
= mArray
.Length();
635 nsMediaList::Item(PRUint32 aIndex
, nsAString
& aReturn
)
637 PRInt32 index
= aIndex
;
638 if (0 <= index
&& index
< Count()) {
639 nsMediaQuery
* query
= mArray
[index
];
640 NS_ENSURE_TRUE(query
, NS_ERROR_FAILURE
);
643 query
->AppendToString(aReturn
);
645 SetDOMStringToNull(aReturn
);
652 nsMediaList::DeleteMedium(const nsAString
& aOldMedium
)
655 nsCOMPtr
<nsIDocument
> doc
;
657 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
659 rv
= Delete(aOldMedium
);
663 END_MEDIA_CHANGE(mStyleSheet
, doc
)
669 nsMediaList::AppendMedium(const nsAString
& aNewMedium
)
672 nsCOMPtr
<nsIDocument
> doc
;
674 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
676 rv
= Append(aNewMedium
);
680 END_MEDIA_CHANGE(mStyleSheet
, doc
)
686 nsMediaList::Delete(const nsAString
& aOldMedium
)
688 if (aOldMedium
.IsEmpty())
689 return NS_ERROR_DOM_NOT_FOUND_ERR
;
691 for (PRInt32 i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
692 nsMediaQuery
* query
= mArray
[i
];
693 NS_ENSURE_TRUE(query
, NS_ERROR_FAILURE
);
696 query
->AppendToString(buf
);
697 if (buf
== aOldMedium
) {
698 mArray
.RemoveElementAt(i
);
703 return NS_ERROR_DOM_NOT_FOUND_ERR
;
707 nsMediaList::Append(const nsAString
& aNewMedium
)
709 if (aNewMedium
.IsEmpty())
710 return NS_ERROR_DOM_NOT_FOUND_ERR
;
715 nsTArray
<nsAutoPtr
<nsMediaQuery
> > buf
;
719 mArray
.SwapElements(buf
);
720 NS_ASSERTION(ok
, "SwapElements should never fail when neither array "
723 if (mArray
.Length() == 1) {
724 nsMediaQuery
*query
= mArray
[0].forget();
725 if (!buf
.AppendElement(query
)) {
727 rv
= NS_ERROR_OUT_OF_MEMORY
;
733 mArray
.SwapElements(buf
);
734 NS_ASSERTION(ok
, "SwapElements should never fail when neither array "
739 // -------------------------------
740 // Imports Collection for the DOM
742 class CSSImportsCollectionImpl
: public nsIDOMStyleSheetList
745 CSSImportsCollectionImpl(nsICSSStyleSheet
*aStyleSheet
);
749 // nsIDOMCSSStyleSheetList interface
750 NS_IMETHOD
GetLength(PRUint32
* aLength
);
751 NS_IMETHOD
Item(PRUint32 aIndex
, nsIDOMStyleSheet
** aReturn
);
753 void DropReference() { mStyleSheet
= nsnull
; }
756 virtual ~CSSImportsCollectionImpl();
758 nsICSSStyleSheet
* mStyleSheet
;
761 CSSImportsCollectionImpl::CSSImportsCollectionImpl(nsICSSStyleSheet
*aStyleSheet
)
763 // Not reference counted to avoid circular references.
764 // The style sheet will tell us when its going away.
765 mStyleSheet
= aStyleSheet
;
768 CSSImportsCollectionImpl::~CSSImportsCollectionImpl()
773 // QueryInterface implementation for CSSImportsCollectionImpl
774 NS_INTERFACE_MAP_BEGIN(CSSImportsCollectionImpl
)
775 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList
)
776 NS_INTERFACE_MAP_ENTRY(nsISupports
)
777 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(StyleSheetList
)
781 NS_IMPL_ADDREF(CSSImportsCollectionImpl
)
782 NS_IMPL_RELEASE(CSSImportsCollectionImpl
)
786 CSSImportsCollectionImpl::GetLength(PRUint32
* aLength
)
788 if (nsnull
!= mStyleSheet
) {
790 mStyleSheet
->StyleSheetCount(count
);
791 *aLength
= (PRUint32
)count
;
801 CSSImportsCollectionImpl::Item(PRUint32 aIndex
, nsIDOMStyleSheet
** aReturn
)
803 nsresult result
= NS_OK
;
808 nsCOMPtr
<nsICSSStyleSheet
> sheet
;
810 result
= mStyleSheet
->GetStyleSheetAt(aIndex
, *getter_AddRefs(sheet
));
811 if (NS_SUCCEEDED(result
)) {
812 result
= CallQueryInterface(sheet
, aReturn
);
819 // -------------------------------
820 // CSS Style Sheet Inner Data Container
824 static PRBool
SetStyleSheetReference(nsICSSRule
* aRule
, void* aSheet
)
827 aRule
->SetStyleSheet((nsICSSStyleSheet
*)aSheet
);
832 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsICSSStyleSheet
* aParentSheet
)
836 , mPrincipalSet(PR_FALSE
)
839 MOZ_COUNT_CTOR(nsCSSStyleSheetInner
);
840 mSheets
.AppendElement(aParentSheet
);
842 mPrincipal
= do_CreateInstance("@mozilla.org/nullprincipal;1");
846 CloneRuleInto(nsICSSRule
* aRule
, void* aArray
)
848 nsICSSRule
* clone
= nsnull
;
851 static_cast<nsCOMArray
<nsICSSRule
>*>(aArray
)->AppendObject(clone
);
857 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner
& aCopy
,
858 nsICSSStyleSheet
* aParentSheet
)
860 mSheetURI(aCopy
.mSheetURI
),
861 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
862 mBaseURI(aCopy
.mBaseURI
),
863 mPrincipal(aCopy
.mPrincipal
),
864 mComplete(aCopy
.mComplete
)
866 , mPrincipalSet(aCopy
.mPrincipalSet
)
869 MOZ_COUNT_CTOR(nsCSSStyleSheetInner
);
870 mSheets
.AppendElement(aParentSheet
);
871 aCopy
.mOrderedRules
.EnumerateForwards(CloneRuleInto
, &mOrderedRules
);
872 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
, aParentSheet
);
876 nsCSSStyleSheetInner::~nsCSSStyleSheetInner()
878 MOZ_COUNT_DTOR(nsCSSStyleSheetInner
);
879 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
, nsnull
);
882 nsCSSStyleSheetInner
*
883 nsCSSStyleSheetInner::CloneFor(nsICSSStyleSheet
* aParentSheet
)
885 return new nsCSSStyleSheetInner(*this, aParentSheet
);
889 nsCSSStyleSheetInner::AddSheet(nsICSSStyleSheet
* aParentSheet
)
891 mSheets
.AppendElement(aParentSheet
);
895 nsCSSStyleSheetInner::RemoveSheet(nsICSSStyleSheet
* aParentSheet
)
897 if (1 == mSheets
.Count()) {
898 NS_ASSERTION(aParentSheet
== (nsICSSStyleSheet
*)mSheets
.ElementAt(0), "bad parent");
902 if (aParentSheet
== (nsICSSStyleSheet
*)mSheets
.ElementAt(0)) {
903 mSheets
.RemoveElementAt(0);
904 NS_ASSERTION(mSheets
.Count(), "no parents");
905 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
,
906 (nsICSSStyleSheet
*)mSheets
.ElementAt(0));
909 mSheets
.RemoveElement(aParentSheet
);
914 CreateNameSpace(nsICSSRule
* aRule
, void* aNameSpacePtr
)
916 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
917 aRule
->GetType(type
);
918 if (nsICSSRule::NAMESPACE_RULE
== type
) {
919 nsICSSNameSpaceRule
* nameSpaceRule
= (nsICSSNameSpaceRule
*)aRule
;
920 nsXMLNameSpaceMap
*nameSpaceMap
=
921 static_cast<nsXMLNameSpaceMap
*>(aNameSpacePtr
);
923 nsIAtom
* prefix
= nsnull
;
924 nsAutoString urlSpec
;
925 nameSpaceRule
->GetPrefix(prefix
);
926 nameSpaceRule
->GetURLSpec(urlSpec
);
928 nameSpaceMap
->AddPrefix(prefix
, urlSpec
);
931 // stop if not namespace, import or charset because namespace can't follow anything else
932 return (((nsICSSRule::CHARSET_RULE
== type
) ||
933 (nsICSSRule::IMPORT_RULE
)) ? PR_TRUE
: PR_FALSE
);
937 nsCSSStyleSheetInner::RebuildNameSpaces()
940 mNameSpaceMap
->Clear();
942 mNameSpaceMap
= nsXMLNameSpaceMap::Create();
943 if (!mNameSpaceMap
) {
944 return; // out of memory
948 mOrderedRules
.EnumerateForwards(CreateNameSpace
, mNameSpaceMap
);
952 // -------------------------------
956 nsCSSStyleSheet::nsCSSStyleSheet()
957 : nsICSSStyleSheet(),
965 mImportsCollection(nsnull
),
966 mRuleCollection(nsnull
),
971 mRuleProcessors(nsnull
)
974 mInner
= new nsCSSStyleSheetInner(this);
977 nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet
& aCopy
,
978 nsICSSStyleSheet
* aParentToUse
,
979 nsICSSImportRule
* aOwnerRuleToUse
,
980 nsIDocument
* aDocumentToUse
,
981 nsIDOMNode
* aOwningNodeToUse
)
982 : nsICSSStyleSheet(),
984 mTitle(aCopy
.mTitle
),
988 mParent(aParentToUse
),
989 mOwnerRule(aOwnerRuleToUse
),
990 mImportsCollection(nsnull
), // re-created lazily
991 mRuleCollection(nsnull
), // re-created lazily
992 mDocument(aDocumentToUse
),
993 mOwningNode(aOwningNodeToUse
),
994 mDisabled(aCopy
.mDisabled
),
996 mInner(aCopy
.mInner
),
997 mRuleProcessors(nsnull
)
1000 mInner
->AddSheet(this);
1002 if (aCopy
.mRuleCollection
&&
1003 aCopy
.mRuleCollection
->mRulesAccessed
) { // CSSOM's been there, force full copy now
1004 NS_ASSERTION(mInner
->mComplete
, "Why have rules been accessed on an incomplete sheet?");
1005 EnsureUniqueInner();
1009 aCopy
.mMedia
->Clone(getter_AddRefs(mMedia
));
1012 if (aCopy
.mFirstChild
) {
1013 nsCSSStyleSheet
* otherChild
= aCopy
.mFirstChild
;
1014 nsCSSStyleSheet
** ourSlot
= &mFirstChild
;
1016 // XXX This is wrong; we should be keeping @import rules and
1018 nsCSSStyleSheet
* child
= new nsCSSStyleSheet(*otherChild
,
1026 ourSlot
= &(child
->mNext
);
1028 otherChild
= otherChild
->mNext
;
1030 while (otherChild
&& ourSlot
);
1034 nsCSSStyleSheet::~nsCSSStyleSheet()
1037 nsCSSStyleSheet
* child
= mFirstChild
;
1039 child
->mParent
= nsnull
;
1040 child
->mDocument
= nsnull
;
1041 child
= child
->mNext
;
1043 NS_RELEASE(mFirstChild
);
1045 NS_IF_RELEASE(mNext
);
1046 if (nsnull
!= mRuleCollection
) {
1047 mRuleCollection
->DropReference();
1048 NS_RELEASE(mRuleCollection
);
1050 if (nsnull
!= mImportsCollection
) {
1051 mImportsCollection
->DropReference();
1052 NS_RELEASE(mImportsCollection
);
1055 mMedia
->SetStyleSheet(nsnull
);
1058 mInner
->RemoveSheet(this);
1059 // XXX The document reference is not reference counted and should
1060 // not be released. The document will let us know when it is going
1062 if (mRuleProcessors
) {
1063 NS_ASSERTION(mRuleProcessors
->Count() == 0, "destructing sheet with rule processor reference");
1064 delete mRuleProcessors
; // weak refs, should be empty here anyway
1069 // QueryInterface implementation for nsCSSStyleSheet
1070 NS_INTERFACE_MAP_BEGIN(nsCSSStyleSheet
)
1071 NS_INTERFACE_MAP_ENTRY(nsICSSStyleSheet
)
1072 NS_INTERFACE_MAP_ENTRY(nsIStyleSheet
)
1073 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet
)
1074 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet
)
1075 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
1076 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsICSSStyleSheet
)
1077 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleSheet
)
1078 NS_INTERFACE_MAP_END
1081 NS_IMPL_ADDREF(nsCSSStyleSheet
)
1082 NS_IMPL_RELEASE(nsCSSStyleSheet
)
1086 nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor
* aProcessor
)
1088 if (! mRuleProcessors
) {
1089 mRuleProcessors
= new nsAutoVoidArray();
1090 if (!mRuleProcessors
)
1091 return NS_ERROR_OUT_OF_MEMORY
;
1093 NS_ASSERTION(-1 == mRuleProcessors
->IndexOf(aProcessor
),
1094 "processor already registered");
1095 mRuleProcessors
->AppendElement(aProcessor
); // weak ref
1100 nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor
* aProcessor
)
1102 if (!mRuleProcessors
)
1103 return NS_ERROR_FAILURE
;
1104 return mRuleProcessors
->RemoveElement(aProcessor
)
1111 nsCSSStyleSheet::SetURIs(nsIURI
* aSheetURI
, nsIURI
* aOriginalSheetURI
,
1114 NS_PRECONDITION(aSheetURI
&& aBaseURI
, "null ptr");
1116 NS_ASSERTION(mInner
->mOrderedRules
.Count() == 0 && !mInner
->mComplete
,
1117 "Can't call SetURL on sheets that are complete or have rules");
1119 mInner
->mSheetURI
= aSheetURI
;
1120 mInner
->mOriginalSheetURI
= aOriginalSheetURI
;
1121 mInner
->mBaseURI
= aBaseURI
;
1126 nsCSSStyleSheet::SetPrincipal(nsIPrincipal
* aPrincipal
)
1128 NS_PRECONDITION(!mInner
->mPrincipalSet
,
1129 "Should have an inner whose principal has not yet been set");
1131 mInner
->mPrincipal
= aPrincipal
;
1133 mInner
->mPrincipalSet
= PR_TRUE
;
1139 nsCSSStyleSheet::Principal() const
1141 return mInner
->mPrincipal
;
1145 nsCSSStyleSheet::GetSheetURI(nsIURI
** aSheetURI
) const
1147 NS_IF_ADDREF(*aSheetURI
= mInner
->mSheetURI
.get());
1152 nsCSSStyleSheet::GetBaseURI(nsIURI
** aBaseURI
) const
1154 NS_IF_ADDREF(*aBaseURI
= mInner
->mBaseURI
.get());
1159 nsCSSStyleSheet::SetTitle(const nsAString
& aTitle
)
1166 nsCSSStyleSheet::GetType(nsString
& aType
) const
1168 aType
.AssignLiteral("text/css");
1173 nsCSSStyleSheet::UseForPresentation(nsPresContext
* aPresContext
,
1174 nsMediaQueryResultCacheKey
& aKey
) const
1177 return mMedia
->Matches(aPresContext
, aKey
);
1184 nsCSSStyleSheet::SetMedia(nsMediaList
* aMedia
)
1190 NS_IMETHODIMP_(PRBool
)
1191 nsCSSStyleSheet::HasRules() const
1194 StyleRuleCount(count
);
1199 nsCSSStyleSheet::GetApplicable(PRBool
& aApplicable
) const
1201 aApplicable
= !mDisabled
&& mInner
->mComplete
;
1206 nsCSSStyleSheet::SetEnabled(PRBool aEnabled
)
1208 // Internal method, so callers must handle BeginUpdate/EndUpdate
1209 PRBool oldDisabled
= mDisabled
;
1210 mDisabled
= !aEnabled
;
1212 if (mDocument
&& mInner
->mComplete
&& oldDisabled
!= mDisabled
) {
1213 ClearRuleCascades();
1215 mDocument
->SetStyleSheetApplicableState(this, !mDisabled
);
1222 nsCSSStyleSheet::GetComplete(PRBool
& aComplete
) const
1224 aComplete
= mInner
->mComplete
;
1229 nsCSSStyleSheet::SetComplete()
1231 NS_ASSERTION(!mDirty
, "Can't set a dirty sheet complete!");
1232 mInner
->mComplete
= PR_TRUE
;
1233 if (mDocument
&& !mDisabled
) {
1234 // Let the document know
1235 mDocument
->BeginUpdate(UPDATE_STYLE
);
1236 mDocument
->SetStyleSheetApplicableState(this, PR_TRUE
);
1237 mDocument
->EndUpdate(UPDATE_STYLE
);
1243 nsCSSStyleSheet::GetParentSheet(nsIStyleSheet
*& aParent
) const
1246 NS_IF_ADDREF(aParent
);
1251 nsCSSStyleSheet::GetOwningDocument(nsIDocument
*& aDocument
) const
1253 aDocument
= mDocument
;
1254 NS_IF_ADDREF(aDocument
);
1259 nsCSSStyleSheet::SetOwningDocument(nsIDocument
* aDocument
)
1260 { // not ref counted
1261 mDocument
= aDocument
;
1262 // Now set the same document on all our child sheets....
1263 for (nsCSSStyleSheet
* child
= mFirstChild
; child
; child
= child
->mNext
) {
1264 child
->SetOwningDocument(aDocument
);
1270 nsCSSStyleSheet::SetOwningNode(nsIDOMNode
* aOwningNode
)
1271 { // not ref counted
1272 mOwningNode
= aOwningNode
;
1277 nsCSSStyleSheet::SetOwnerRule(nsICSSImportRule
* aOwnerRule
)
1278 { // not ref counted
1279 mOwnerRule
= aOwnerRule
;
1284 nsCSSStyleSheet::GetOwnerRule(nsICSSImportRule
** aOwnerRule
)
1286 *aOwnerRule
= mOwnerRule
;
1287 NS_IF_ADDREF(*aOwnerRule
);
1292 nsCSSStyleSheet::ContainsStyleSheet(nsIURI
* aURL
, PRBool
& aContains
, nsIStyleSheet
** aTheChild
/*=nsnull*/)
1294 NS_PRECONDITION(nsnull
!= aURL
, "null arg");
1296 if (!mInner
->mSheetURI
) {
1297 // We're not yet far enough along in our load to know what our URL is (we
1298 // may still get redirected and such). Assert (caller should really not be
1299 // calling this on us at this stage) and return.
1300 NS_ERROR("ContainsStyleSheet called on a sheet that's still loading");
1301 aContains
= PR_FALSE
;
1305 // first check ourself out
1306 nsresult rv
= mInner
->mSheetURI
->Equals(aURL
, &aContains
);
1307 if (NS_FAILED(rv
)) aContains
= PR_FALSE
;
1310 // if we found it and the out-param is there, set it and addref
1312 rv
= QueryInterface( NS_GET_IID(nsIStyleSheet
), (void **)aTheChild
);
1315 nsCSSStyleSheet
* child
= mFirstChild
;
1316 // now check the chil'ins out (recursively)
1317 while ((PR_FALSE
== aContains
) && (nsnull
!= child
)) {
1318 child
->ContainsStyleSheet(aURL
, aContains
, aTheChild
);
1322 child
= child
->mNext
;
1327 // NOTE: if there are errors in the above we are handling them locally
1328 // and not promoting them to the caller
1333 nsCSSStyleSheet::AppendStyleSheet(nsICSSStyleSheet
* aSheet
)
1335 NS_PRECONDITION(nsnull
!= aSheet
, "null arg");
1337 if (NS_SUCCEEDED(WillDirty())) {
1339 nsCSSStyleSheet
* sheet
= (nsCSSStyleSheet
*)aSheet
;
1341 if (! mFirstChild
) {
1342 mFirstChild
= sheet
;
1345 nsCSSStyleSheet
* child
= mFirstChild
;
1346 while (child
->mNext
) {
1347 child
= child
->mNext
;
1349 child
->mNext
= sheet
;
1352 // This is not reference counted. Our parent tells us when
1354 sheet
->mParent
= this;
1355 sheet
->mDocument
= mDocument
;
1362 nsCSSStyleSheet::InsertStyleSheetAt(nsICSSStyleSheet
* aSheet
, PRInt32 aIndex
)
1364 NS_PRECONDITION(nsnull
!= aSheet
, "null arg");
1366 nsresult result
= WillDirty();
1368 if (NS_SUCCEEDED(result
)) {
1370 nsCSSStyleSheet
* sheet
= (nsCSSStyleSheet
*)aSheet
;
1371 nsCSSStyleSheet
* child
= mFirstChild
;
1373 if (aIndex
&& child
) {
1374 while ((0 < --aIndex
) && child
->mNext
) {
1375 child
= child
->mNext
;
1377 sheet
->mNext
= child
->mNext
;
1378 child
->mNext
= sheet
;
1381 sheet
->mNext
= mFirstChild
;
1382 mFirstChild
= sheet
;
1385 // This is not reference counted. Our parent tells us when
1387 sheet
->mParent
= this;
1388 sheet
->mDocument
= mDocument
;
1395 nsCSSStyleSheet::PrependStyleRule(nsICSSRule
* aRule
)
1397 NS_PRECONDITION(nsnull
!= aRule
, "null arg");
1399 if (NS_SUCCEEDED(WillDirty())) {
1400 mInner
->mOrderedRules
.InsertObjectAt(aRule
, 0);
1401 aRule
->SetStyleSheet(this);
1404 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
1405 aRule
->GetType(type
);
1406 if (nsICSSRule::NAMESPACE_RULE
== type
) {
1407 // no api to prepend a namespace (ugh), release old ones and re-create them all
1408 mInner
->RebuildNameSpaces();
1415 nsCSSStyleSheet::AppendStyleRule(nsICSSRule
* aRule
)
1417 NS_PRECONDITION(nsnull
!= aRule
, "null arg");
1419 if (NS_SUCCEEDED(WillDirty())) {
1420 mInner
->mOrderedRules
.AppendObject(aRule
);
1421 aRule
->SetStyleSheet(this);
1424 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
1425 aRule
->GetType(type
);
1426 if (nsICSSRule::NAMESPACE_RULE
== type
) {
1427 if (!mInner
->mNameSpaceMap
) {
1428 mInner
->mNameSpaceMap
= nsXMLNameSpaceMap::Create();
1429 NS_ENSURE_TRUE(mInner
->mNameSpaceMap
, NS_ERROR_OUT_OF_MEMORY
);
1432 nsCOMPtr
<nsICSSNameSpaceRule
> nameSpaceRule(do_QueryInterface(aRule
));
1434 nsCOMPtr
<nsIAtom
> prefix
;
1435 nsAutoString urlSpec
;
1436 nameSpaceRule
->GetPrefix(*getter_AddRefs(prefix
));
1437 nameSpaceRule
->GetURLSpec(urlSpec
);
1439 mInner
->mNameSpaceMap
->AddPrefix(prefix
, urlSpec
);
1446 nsCSSStyleSheet::ReplaceStyleRule(nsICSSRule
* aOld
, nsICSSRule
* aNew
)
1448 NS_PRECONDITION(mInner
->mOrderedRules
.Count() != 0, "can't have old rule");
1449 NS_PRECONDITION(mInner
->mComplete
, "No replacing in an incomplete sheet!");
1451 if (NS_SUCCEEDED(WillDirty())) {
1452 PRInt32 index
= mInner
->mOrderedRules
.IndexOf(aOld
);
1453 NS_ENSURE_TRUE(index
!= -1, NS_ERROR_UNEXPECTED
);
1454 mInner
->mOrderedRules
.ReplaceObjectAt(aNew
, index
);
1456 aNew
->SetStyleSheet(this);
1457 aOld
->SetStyleSheet(nsnull
);
1460 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
1461 aNew
->GetType(type
);
1462 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE
!= type
, "not yet implemented");
1463 aOld
->GetType(type
);
1464 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE
!= type
, "not yet implemented");
1471 nsCSSStyleSheet::StyleRuleCount(PRInt32
& aCount
) const
1473 aCount
= mInner
->mOrderedRules
.Count();
1478 nsCSSStyleSheet::GetStyleRuleAt(PRInt32 aIndex
, nsICSSRule
*& aRule
) const
1480 // Important: If this function is ever made scriptable, we must add
1481 // a security check here. See GetCssRules below for an example.
1482 aRule
= mInner
->mOrderedRules
.SafeObjectAt(aIndex
);
1488 return NS_ERROR_ILLEGAL_VALUE
;
1492 nsCSSStyleSheet::GetNameSpaceMap() const
1494 return mInner
->mNameSpaceMap
;
1498 nsCSSStyleSheet::StyleSheetCount(PRInt32
& aCount
) const
1500 // XXX Far from an ideal way to do this, but the hope is that
1501 // it won't be done too often. If it is, we might want to
1502 // consider storing the children in an array.
1505 const nsCSSStyleSheet
* child
= mFirstChild
;
1508 child
= child
->mNext
;
1515 nsCSSStyleSheet::GetStyleSheetAt(PRInt32 aIndex
, nsICSSStyleSheet
*& aSheet
) const
1517 // XXX Ughh...an O(n^2) method for doing iteration. Again, we hope
1518 // that this isn't done too often. If it is, we need to change the
1519 // underlying storage mechanism
1523 const nsCSSStyleSheet
* child
= mFirstChild
;
1524 while ((child
) && (0 != aIndex
)) {
1526 child
= child
->mNext
;
1529 aSheet
= (nsICSSStyleSheet
*)child
;
1530 NS_IF_ADDREF(aSheet
);
1537 nsCSSStyleSheet::EnsureUniqueInner()
1539 if (1 < mInner
->mSheets
.Count()) {
1540 nsCSSStyleSheetInner
* clone
= mInner
->CloneFor(this);
1542 mInner
->RemoveSheet(this);
1546 return NS_ERROR_OUT_OF_MEMORY
;
1553 nsCSSStyleSheet::Clone(nsICSSStyleSheet
* aCloneParent
,
1554 nsICSSImportRule
* aCloneOwnerRule
,
1555 nsIDocument
* aCloneDocument
,
1556 nsIDOMNode
* aCloneOwningNode
,
1557 nsICSSStyleSheet
** aClone
) const
1559 NS_PRECONDITION(aClone
, "Null out param!");
1560 nsCSSStyleSheet
* clone
= new nsCSSStyleSheet(*this,
1566 *aClone
= static_cast<nsICSSStyleSheet
*>(clone
);
1574 ListRules(const nsCOMArray
<nsICSSRule
>& aRules
, FILE* aOut
, PRInt32 aIndent
)
1576 for (PRInt32 index
= aRules
.Count() - 1; index
>= 0; --index
) {
1577 aRules
.ObjectAt(index
)->List(aOut
, aIndent
);
1581 struct ListEnumData
{
1582 ListEnumData(FILE* aOut
, PRInt32 aIndent
)
1591 void nsCSSStyleSheet::List(FILE* out
, PRInt32 aIndent
) const
1597 for (index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
1599 fputs("CSS Style Sheet: ", out
);
1600 nsCAutoString urlSpec
;
1601 nsresult rv
= mInner
->mSheetURI
->GetSpec(urlSpec
);
1602 if (NS_SUCCEEDED(rv
) && !urlSpec
.IsEmpty()) {
1603 fputs(urlSpec
.get(), out
);
1607 fputs(" media: ", out
);
1608 nsAutoString buffer
;
1609 mMedia
->GetText(buffer
);
1610 fputs(NS_ConvertUTF16toUTF8(buffer
).get(), out
);
1614 const nsCSSStyleSheet
* child
= mFirstChild
;
1615 while (nsnull
!= child
) {
1616 child
->List(out
, aIndent
+ 1);
1617 child
= child
->mNext
;
1620 fputs("Rules in source order:\n", out
);
1621 ListRules(mInner
->mOrderedRules
, out
, aIndent
);
1625 static PRBool PR_CALLBACK
1626 EnumClearRuleCascades(void* aProcessor
, void* aData
)
1628 nsCSSRuleProcessor
* processor
=
1629 static_cast<nsCSSRuleProcessor
*>(aProcessor
);
1630 processor
->ClearRuleCascades();
1635 nsCSSStyleSheet::ClearRuleCascades()
1637 if (mRuleProcessors
) {
1638 mRuleProcessors
->EnumerateForwards(EnumClearRuleCascades
, nsnull
);
1641 nsCSSStyleSheet
* parent
= (nsCSSStyleSheet
*)mParent
;
1642 parent
->ClearRuleCascades();
1647 nsCSSStyleSheet::WillDirty()
1649 if (!mInner
->mComplete
) {
1654 return EnsureUniqueInner();
1658 nsCSSStyleSheet::DidDirty()
1660 ClearRuleCascades();
1665 nsCSSStyleSheet::SubjectSubsumesInnerPrincipal() const
1667 // Get the security manager and do the subsumes check
1668 nsIScriptSecurityManager
*securityManager
=
1669 nsContentUtils::GetSecurityManager();
1671 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
;
1672 securityManager
->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal
));
1674 if (!subjectPrincipal
) {
1675 return NS_ERROR_DOM_SECURITY_ERR
;
1679 nsresult rv
= subjectPrincipal
->Subsumes(mInner
->mPrincipal
, &subsumes
);
1680 NS_ENSURE_SUCCESS(rv
, rv
);
1686 if (!nsContentUtils::IsCallerTrustedForWrite()) {
1687 return NS_ERROR_DOM_SECURITY_ERR
;
1694 nsCSSStyleSheet::IsModified(PRBool
* aSheetModified
) const
1696 *aSheetModified
= mDirty
;
1701 nsCSSStyleSheet::SetModified(PRBool aModified
)
1707 // nsIDOMStyleSheet interface
1709 nsCSSStyleSheet::GetType(nsAString
& aType
)
1711 aType
.AssignLiteral("text/css");
1716 nsCSSStyleSheet::GetDisabled(PRBool
* aDisabled
)
1718 *aDisabled
= mDisabled
;
1723 nsCSSStyleSheet::SetDisabled(PRBool aDisabled
)
1725 // DOM method, so handle BeginUpdate/EndUpdate
1726 MOZ_AUTO_DOC_UPDATE(mDocument
, UPDATE_STYLE
, PR_TRUE
);
1727 nsresult rv
= nsCSSStyleSheet::SetEnabled(!aDisabled
);
1732 nsCSSStyleSheet::GetOwnerNode(nsIDOMNode
** aOwnerNode
)
1734 *aOwnerNode
= mOwningNode
;
1735 NS_IF_ADDREF(*aOwnerNode
);
1740 nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet
** aParentStyleSheet
)
1742 NS_ENSURE_ARG_POINTER(aParentStyleSheet
);
1744 nsresult rv
= NS_OK
;
1747 rv
= mParent
->QueryInterface(NS_GET_IID(nsIDOMStyleSheet
),
1748 (void **)aParentStyleSheet
);
1750 *aParentStyleSheet
= nsnull
;
1757 nsCSSStyleSheet::GetHref(nsAString
& aHref
)
1759 if (mInner
->mOriginalSheetURI
) {
1761 mInner
->mOriginalSheetURI
->GetSpec(str
);
1762 CopyUTF8toUTF16(str
, aHref
);
1764 SetDOMStringToNull(aHref
);
1771 nsCSSStyleSheet::GetTitle(nsString
& aTitle
) const
1778 nsCSSStyleSheet::GetTitle(nsAString
& aTitle
)
1780 aTitle
.Assign(mTitle
);
1785 nsCSSStyleSheet::GetMedia(nsIDOMMediaList
** aMedia
)
1787 NS_ENSURE_ARG_POINTER(aMedia
);
1791 mMedia
= new nsMediaList();
1792 NS_ENSURE_TRUE(mMedia
, NS_ERROR_OUT_OF_MEMORY
);
1793 mMedia
->SetStyleSheet(this);
1803 nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule
** aOwnerRule
)
1806 return mOwnerRule
->GetDOMRule(aOwnerRule
);
1809 *aOwnerRule
= nsnull
;
1814 nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList
** aCssRules
)
1816 // No doing this on incomplete sheets!
1818 GetComplete(complete
);
1820 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1823 //-- Security check: Only scripts whose principal subsumes that of the
1824 // style sheet can access rule collections.
1825 nsresult rv
= SubjectSubsumesInnerPrincipal();
1826 NS_ENSURE_SUCCESS(rv
, rv
);
1828 // OK, security check passed, so get the rule collection
1829 if (nsnull
== mRuleCollection
) {
1830 mRuleCollection
= new CSSRuleListImpl(this);
1831 if (nsnull
== mRuleCollection
) {
1832 return NS_ERROR_OUT_OF_MEMORY
;
1834 NS_ADDREF(mRuleCollection
);
1837 *aCssRules
= mRuleCollection
;
1838 NS_ADDREF(mRuleCollection
);
1844 nsCSSStyleSheet::InsertRule(const nsAString
& aRule
,
1848 //-- Security check: Only scripts whose principal subsumes that of the
1849 // style sheet can modify rule collections.
1850 nsresult rv
= SubjectSubsumesInnerPrincipal();
1851 NS_ENSURE_SUCCESS(rv
, rv
);
1853 return InsertRuleInternal(aRule
, aIndex
, aReturn
);
1857 nsCSSStyleSheet::InsertRuleInternal(const nsAString
& aRule
,
1861 // No doing this if the sheet is not complete!
1863 GetComplete(complete
);
1865 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1868 if (aRule
.IsEmpty()) {
1869 // Nothing to do here
1874 result
= WillDirty();
1875 if (NS_FAILED(result
))
1878 if (aIndex
> PRUint32(mInner
->mOrderedRules
.Count()))
1879 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
1881 NS_ASSERTION(PRUint32(mInner
->mOrderedRules
.Count()) <= PR_INT32_MAX
,
1882 "Too many style rules!");
1884 // Hold strong ref to the CSSLoader in case the document update
1885 // kills the document
1886 nsCOMPtr
<nsICSSLoader
> loader
;
1888 loader
= mDocument
->CSSLoader();
1889 NS_ASSERTION(loader
, "Document with no CSS loader!");
1892 nsCOMPtr
<nsICSSParser
> css
;
1894 result
= loader
->GetParserFor(this, getter_AddRefs(css
));
1897 result
= NS_NewCSSParser(getter_AddRefs(css
));
1899 css
->SetStyleSheet(this);
1902 if (NS_FAILED(result
))
1905 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, PR_TRUE
);
1907 nsCOMArray
<nsICSSRule
> rules
;
1908 result
= css
->ParseRule(aRule
, mInner
->mSheetURI
, mInner
->mBaseURI
,
1909 mInner
->mPrincipal
, rules
);
1910 if (NS_FAILED(result
))
1913 PRInt32 rulecount
= rules
.Count();
1914 if (rulecount
== 0) {
1915 // Since we know aRule was not an empty string, just throw
1916 return NS_ERROR_DOM_SYNTAX_ERR
;
1919 // Hierarchy checking. Just check the first and last rule in the list.
1921 // check that we're not inserting before a charset rule
1922 PRInt32 nextType
= nsICSSRule::UNKNOWN_RULE
;
1923 nsICSSRule
* nextRule
= mInner
->mOrderedRules
.SafeObjectAt(aIndex
);
1925 nextRule
->GetType(nextType
);
1926 if (nextType
== nsICSSRule::CHARSET_RULE
) {
1927 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1930 // check last rule in list
1931 nsICSSRule
* lastRule
= rules
.ObjectAt(rulecount
- 1);
1932 PRInt32 lastType
= nsICSSRule::UNKNOWN_RULE
;
1933 lastRule
->GetType(lastType
);
1935 if (nextType
== nsICSSRule::IMPORT_RULE
&&
1936 lastType
!= nsICSSRule::CHARSET_RULE
&&
1937 lastType
!= nsICSSRule::IMPORT_RULE
) {
1938 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1941 if (nextType
== nsICSSRule::NAMESPACE_RULE
&&
1942 lastType
!= nsICSSRule::CHARSET_RULE
&&
1943 lastType
!= nsICSSRule::IMPORT_RULE
&&
1944 lastType
!= nsICSSRule::NAMESPACE_RULE
) {
1945 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1949 // check first rule in list
1950 nsICSSRule
* firstRule
= rules
.ObjectAt(0);
1951 PRInt32 firstType
= nsICSSRule::UNKNOWN_RULE
;
1952 firstRule
->GetType(firstType
);
1954 if (firstType
== nsICSSRule::CHARSET_RULE
) { // no inserting charset at nonzero position
1955 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1958 nsICSSRule
* prevRule
= mInner
->mOrderedRules
.SafeObjectAt(aIndex
- 1);
1959 PRInt32 prevType
= nsICSSRule::UNKNOWN_RULE
;
1960 prevRule
->GetType(prevType
);
1962 if (firstType
== nsICSSRule::IMPORT_RULE
&&
1963 prevType
!= nsICSSRule::CHARSET_RULE
&&
1964 prevType
!= nsICSSRule::IMPORT_RULE
) {
1965 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1968 if (firstType
== nsICSSRule::NAMESPACE_RULE
&&
1969 prevType
!= nsICSSRule::CHARSET_RULE
&&
1970 prevType
!= nsICSSRule::IMPORT_RULE
&&
1971 prevType
!= nsICSSRule::NAMESPACE_RULE
) {
1972 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1976 PRBool insertResult
= mInner
->mOrderedRules
.InsertObjectsAt(rules
, aIndex
);
1977 NS_ENSURE_TRUE(insertResult
, NS_ERROR_OUT_OF_MEMORY
);
1980 for (PRInt32 counter
= 0; counter
< rulecount
; counter
++) {
1981 nsICSSRule
* cssRule
= rules
.ObjectAt(counter
);
1982 cssRule
->SetStyleSheet(this);
1984 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
1985 cssRule
->GetType(type
);
1986 if (type
== nsICSSRule::NAMESPACE_RULE
) {
1987 if (!mInner
->mNameSpaceMap
) {
1988 mInner
->mNameSpaceMap
= nsXMLNameSpaceMap::Create();
1989 NS_ENSURE_TRUE(mInner
->mNameSpaceMap
, NS_ERROR_OUT_OF_MEMORY
);
1992 nsCOMPtr
<nsICSSNameSpaceRule
> nameSpaceRule(do_QueryInterface(cssRule
));
1994 nsCOMPtr
<nsIAtom
> prefix
;
1995 nsAutoString urlSpec
;
1996 nameSpaceRule
->GetPrefix(*getter_AddRefs(prefix
));
1997 nameSpaceRule
->GetURLSpec(urlSpec
);
1999 mInner
->mNameSpaceMap
->AddPrefix(prefix
, urlSpec
);
2002 // We don't notify immediately for @import rules, but rather when
2003 // the sheet the rule is importing is loaded
2004 PRBool notify
= PR_TRUE
;
2005 if (type
== nsICSSRule::IMPORT_RULE
) {
2006 nsCOMPtr
<nsIDOMCSSImportRule
> importRule(do_QueryInterface(cssRule
));
2007 NS_ASSERTION(importRule
, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
2008 nsCOMPtr
<nsIDOMCSSStyleSheet
> childSheet
;
2009 importRule
->GetStyleSheet(getter_AddRefs(childSheet
));
2014 if (mDocument
&& notify
) {
2015 mDocument
->StyleRuleAdded(this, cssRule
);
2020 loader
->RecycleParser(css
);
2028 nsCSSStyleSheet::DeleteRule(PRUint32 aIndex
)
2030 nsresult result
= NS_ERROR_DOM_INDEX_SIZE_ERR
;
2031 // No doing this if the sheet is not complete!
2033 GetComplete(complete
);
2035 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2038 //-- Security check: Only scripts whose principal subsumes that of the
2039 // style sheet can modify rule collections.
2040 nsresult rv
= SubjectSubsumesInnerPrincipal();
2041 NS_ENSURE_SUCCESS(rv
, rv
);
2043 // XXX TBI: handle @rule types
2044 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, PR_TRUE
);
2046 result
= WillDirty();
2048 if (NS_SUCCEEDED(result
)) {
2049 if (aIndex
>= PRUint32(mInner
->mOrderedRules
.Count()))
2050 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
2052 NS_ASSERTION(PRUint32(mInner
->mOrderedRules
.Count()) <= PR_INT32_MAX
,
2053 "Too many style rules!");
2055 // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
2056 nsCOMPtr
<nsICSSRule
> rule
= mInner
->mOrderedRules
.ObjectAt(aIndex
);
2058 mInner
->mOrderedRules
.RemoveObjectAt(aIndex
);
2059 rule
->SetStyleSheet(nsnull
);
2063 mDocument
->StyleRuleRemoved(this, rule
);
2072 nsCSSStyleSheet::DeleteRuleFromGroup(nsICSSGroupRule
* aGroup
, PRUint32 aIndex
)
2074 NS_ENSURE_ARG_POINTER(aGroup
);
2075 NS_ASSERTION(mInner
->mComplete
, "No deleting from an incomplete sheet!");
2077 nsCOMPtr
<nsICSSRule
> rule
;
2078 result
= aGroup
->GetStyleRuleAt(aIndex
, *getter_AddRefs(rule
));
2079 NS_ENSURE_SUCCESS(result
, result
);
2081 // check that the rule actually belongs to this sheet!
2082 nsCOMPtr
<nsIStyleSheet
> ruleSheet
;
2083 rule
->GetStyleSheet(*getter_AddRefs(ruleSheet
));
2084 if (this != ruleSheet
) {
2085 return NS_ERROR_INVALID_ARG
;
2088 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, PR_TRUE
);
2090 result
= WillDirty();
2091 NS_ENSURE_SUCCESS(result
, result
);
2093 result
= aGroup
->DeleteStyleRuleAt(aIndex
);
2094 NS_ENSURE_SUCCESS(result
, result
);
2096 rule
->SetStyleSheet(nsnull
);
2101 mDocument
->StyleRuleRemoved(this, rule
);
2108 nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString
& aRule
,
2109 nsICSSGroupRule
* aGroup
,
2114 NS_ASSERTION(mInner
->mComplete
, "No inserting into an incomplete sheet!");
2115 // check that the group actually belongs to this sheet!
2116 nsCOMPtr
<nsIStyleSheet
> groupSheet
;
2117 aGroup
->GetStyleSheet(*getter_AddRefs(groupSheet
));
2118 if (this != groupSheet
) {
2119 return NS_ERROR_INVALID_ARG
;
2122 if (aRule
.IsEmpty()) {
2123 // Nothing to do here
2127 // Hold strong ref to the CSSLoader in case the document update
2128 // kills the document
2129 nsCOMPtr
<nsICSSLoader
> loader
;
2131 loader
= mDocument
->CSSLoader();
2132 NS_ASSERTION(loader
, "Document with no CSS loader!");
2135 nsCOMPtr
<nsICSSParser
> css
;
2137 result
= loader
->GetParserFor(this, getter_AddRefs(css
));
2140 result
= NS_NewCSSParser(getter_AddRefs(css
));
2142 css
->SetStyleSheet(this);
2145 NS_ENSURE_SUCCESS(result
, result
);
2147 // parse and grab the rule
2148 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, PR_TRUE
);
2150 result
= WillDirty();
2151 NS_ENSURE_SUCCESS(result
, result
);
2153 nsCOMArray
<nsICSSRule
> rules
;
2154 result
= css
->ParseRule(aRule
, mInner
->mSheetURI
, mInner
->mBaseURI
,
2155 mInner
->mPrincipal
, rules
);
2156 NS_ENSURE_SUCCESS(result
, result
);
2158 PRInt32 rulecount
= rules
.Count();
2159 if (rulecount
== 0) {
2160 // Since we know aRule was not an empty string, just throw
2161 return NS_ERROR_DOM_SYNTAX_ERR
;
2166 for (counter
= 0; counter
< rulecount
; counter
++) {
2167 // Only rulesets are allowed in a group as of CSS2
2168 PRInt32 type
= nsICSSRule::UNKNOWN_RULE
;
2169 rule
= rules
.ObjectAt(counter
);
2170 rule
->GetType(type
);
2171 if (type
!= nsICSSRule::STYLE_RULE
) {
2172 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
2176 result
= aGroup
->InsertStyleRulesAt(aIndex
, rules
);
2177 NS_ENSURE_SUCCESS(result
, result
);
2179 for (counter
= 0; counter
< rulecount
; counter
++) {
2180 rule
= rules
.ObjectAt(counter
);
2183 mDocument
->StyleRuleAdded(this, rule
);
2188 loader
->RecycleParser(css
);
2196 nsCSSStyleSheet::ReplaceRuleInGroup(nsICSSGroupRule
* aGroup
,
2197 nsICSSRule
* aOld
, nsICSSRule
* aNew
)
2200 NS_PRECONDITION(mInner
->mComplete
, "No replacing in an incomplete sheet!");
2203 nsCOMPtr
<nsIStyleSheet
> groupSheet
;
2204 aGroup
->GetStyleSheet(*getter_AddRefs(groupSheet
));
2205 NS_ASSERTION(this == groupSheet
, "group doesn't belong to this sheet");
2208 result
= WillDirty();
2209 NS_ENSURE_SUCCESS(result
, result
);
2211 result
= aGroup
->ReplaceStyleRule(aOld
, aNew
);
2216 // nsICSSLoaderObserver implementation
2218 nsCSSStyleSheet::StyleSheetLoaded(nsICSSStyleSheet
* aSheet
,
2219 PRBool aWasAlternate
,
2223 nsCOMPtr
<nsIStyleSheet
> styleSheet(do_QueryInterface(aSheet
));
2224 NS_ASSERTION(styleSheet
, "Sheet not implementing nsIStyleSheet!\n");
2225 nsCOMPtr
<nsIStyleSheet
> parentSheet
;
2226 aSheet
->GetParentSheet(*getter_AddRefs(parentSheet
));
2227 nsCOMPtr
<nsIStyleSheet
> thisSheet
;
2228 QueryInterface(NS_GET_IID(nsIStyleSheet
), getter_AddRefs(thisSheet
));
2229 NS_ASSERTION(thisSheet
== parentSheet
, "We are being notified of a sheet load for a sheet that is not our child!\n");
2232 if (mDocument
&& NS_SUCCEEDED(aStatus
)) {
2233 nsCOMPtr
<nsICSSImportRule
> ownerRule
;
2234 aSheet
->GetOwnerRule(getter_AddRefs(ownerRule
));
2236 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, PR_TRUE
);
2238 // XXXldb @import rules shouldn't even implement nsIStyleRule (but
2240 nsCOMPtr
<nsIStyleRule
> styleRule(do_QueryInterface(ownerRule
));
2242 mDocument
->StyleRuleAdded(this, styleRule
);
2249 NS_NewCSSStyleSheet(nsICSSStyleSheet
** aInstancePtrResult
)
2251 *aInstancePtrResult
= nsnull
;
2252 nsCSSStyleSheet
*it
= new nsCSSStyleSheet();
2255 return NS_ERROR_OUT_OF_MEMORY
;
2260 if (!it
->mInner
|| !it
->mInner
->mPrincipal
) {
2262 return NS_ERROR_OUT_OF_MEMORY
;
2265 *aInstancePtrResult
= it
;