1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* representation of a CSS style sheet */
9 #include "mozilla/CSSStyleSheet.h"
12 #include "nsCSSRuleProcessor.h"
13 #include "mozilla/MemoryReporting.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/ShadowRoot.h"
16 #include "mozilla/dom/MediaListBinding.h"
17 #include "mozilla/css/NameSpaceRule.h"
18 #include "mozilla/css/GroupRule.h"
19 #include "mozilla/css/ImportRule.h"
20 #include "nsIMediaList.h"
21 #include "nsIDocument.h"
22 #include "nsPresContext.h"
23 #include "nsGkAtoms.h"
26 #include "nsIDOMCSSStyleSheet.h"
27 #include "mozilla/dom/CSSRuleList.h"
28 #include "nsIDOMMediaList.h"
29 #include "nsIDOMNode.h"
31 #include "nsCSSParser.h"
32 #include "mozilla/css/Loader.h"
33 #include "nsICSSLoaderObserver.h"
34 #include "nsNameSpaceManager.h"
35 #include "nsXMLNameSpaceMap.h"
37 #include "nsContentUtils.h"
38 #include "nsIScriptSecurityManager.h"
39 #include "mozAutoDocUpdate.h"
40 #include "nsRuleNode.h"
41 #include "nsMediaFeatures.h"
42 #include "nsDOMClassInfoID.h"
43 #include "mozilla/Likely.h"
44 #include "mozilla/dom/CSSStyleSheetBinding.h"
45 #include "nsComponentManagerUtils.h"
47 using namespace mozilla
;
48 using namespace mozilla::dom
;
50 // -------------------------------
51 // Style Rule List for the DOM
53 class CSSRuleListImpl MOZ_FINAL
: public CSSRuleList
56 explicit CSSRuleListImpl(CSSStyleSheet
*aStyleSheet
);
58 virtual CSSStyleSheet
* GetParentObject() MOZ_OVERRIDE
;
60 virtual nsIDOMCSSRule
*
61 IndexedGetter(uint32_t aIndex
, bool& aFound
) MOZ_OVERRIDE
;
63 Length() MOZ_OVERRIDE
;
65 void DropReference() { mStyleSheet
= nullptr; }
68 virtual ~CSSRuleListImpl();
70 CSSStyleSheet
* mStyleSheet
;
73 CSSRuleListImpl::CSSRuleListImpl(CSSStyleSheet
*aStyleSheet
)
75 // Not reference counted to avoid circular references.
76 // The style sheet will tell us when its going away.
77 mStyleSheet
= aStyleSheet
;
80 CSSRuleListImpl::~CSSRuleListImpl()
85 CSSRuleListImpl::GetParentObject()
91 CSSRuleListImpl::Length()
97 return AssertedCast
<uint32_t>(mStyleSheet
->StyleRuleCount());
101 CSSRuleListImpl::IndexedGetter(uint32_t aIndex
, bool& aFound
)
106 // ensure rules have correct parent
107 mStyleSheet
->EnsureUniqueInner();
108 css::Rule
* rule
= mStyleSheet
->GetStyleRuleAt(aIndex
);
111 return rule
->GetDOMRule();
115 // Per spec: "Return Value ... null if ... not a valid index."
119 template <class Numeric
>
120 int32_t DoCompare(Numeric a
, Numeric b
)
130 nsMediaExpression::Matches(nsPresContext
*aPresContext
,
131 const nsCSSValue
& aActualValue
) const
133 const nsCSSValue
& actual
= aActualValue
;
134 const nsCSSValue
& required
= mValue
;
136 // If we don't have the feature, the match fails.
137 if (actual
.GetUnit() == eCSSUnit_Null
) {
141 // If the expression had no value to match, the match succeeds,
142 // unless the value is an integer 0 or a zero length.
143 if (required
.GetUnit() == eCSSUnit_Null
) {
144 if (actual
.GetUnit() == eCSSUnit_Integer
)
145 return actual
.GetIntValue() != 0;
146 if (actual
.IsLengthUnit())
147 return actual
.GetFloatValue() != 0;
151 NS_ASSERTION(mFeature
->mRangeType
== nsMediaFeature::eMinMaxAllowed
||
152 mRange
== nsMediaExpression::eEqual
, "yikes");
153 int32_t cmp
; // -1 (actual < required)
154 // 0 (actual == required)
155 // 1 (actual > required)
156 switch (mFeature
->mValueType
) {
157 case nsMediaFeature::eLength
:
159 NS_ASSERTION(actual
.IsLengthUnit(), "bad actual value");
160 NS_ASSERTION(required
.IsLengthUnit(), "bad required value");
161 nscoord actualCoord
= nsRuleNode::CalcLengthWithInitialFont(
162 aPresContext
, actual
);
163 nscoord requiredCoord
= nsRuleNode::CalcLengthWithInitialFont(
164 aPresContext
, required
);
165 cmp
= DoCompare(actualCoord
, requiredCoord
);
168 case nsMediaFeature::eInteger
:
169 case nsMediaFeature::eBoolInteger
:
171 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Integer
,
173 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Integer
,
174 "bad required value");
175 NS_ASSERTION(mFeature
->mValueType
!= nsMediaFeature::eBoolInteger
||
176 actual
.GetIntValue() == 0 || actual
.GetIntValue() == 1,
177 "bad actual bool integer value");
178 NS_ASSERTION(mFeature
->mValueType
!= nsMediaFeature::eBoolInteger
||
179 required
.GetIntValue() == 0 || required
.GetIntValue() == 1,
180 "bad required bool integer value");
181 cmp
= DoCompare(actual
.GetIntValue(), required
.GetIntValue());
184 case nsMediaFeature::eFloat
:
186 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Number
,
188 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Number
,
189 "bad required value");
190 cmp
= DoCompare(actual
.GetFloatValue(), required
.GetFloatValue());
193 case nsMediaFeature::eIntRatio
:
195 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Array
&&
196 actual
.GetArrayValue()->Count() == 2 &&
197 actual
.GetArrayValue()->Item(0).GetUnit() ==
199 actual
.GetArrayValue()->Item(1).GetUnit() ==
202 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Array
&&
203 required
.GetArrayValue()->Count() == 2 &&
204 required
.GetArrayValue()->Item(0).GetUnit() ==
206 required
.GetArrayValue()->Item(1).GetUnit() ==
208 "bad required value");
209 // Convert to int64_t so we can multiply without worry. Note
210 // that while the spec requires that both halves of |required|
211 // be positive, the numerator or denominator of |actual| might
212 // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
214 int64_t actualNum
= actual
.GetArrayValue()->Item(0).GetIntValue(),
215 actualDen
= actual
.GetArrayValue()->Item(1).GetIntValue(),
216 requiredNum
= required
.GetArrayValue()->Item(0).GetIntValue(),
217 requiredDen
= required
.GetArrayValue()->Item(1).GetIntValue();
218 cmp
= DoCompare(actualNum
* requiredDen
, requiredNum
* actualDen
);
221 case nsMediaFeature::eResolution
:
223 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Inch
||
224 actual
.GetUnit() == eCSSUnit_Pixel
||
225 actual
.GetUnit() == eCSSUnit_Centimeter
,
227 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Inch
||
228 required
.GetUnit() == eCSSUnit_Pixel
||
229 required
.GetUnit() == eCSSUnit_Centimeter
,
230 "bad required value");
231 float actualDPI
= actual
.GetFloatValue();
232 if (actual
.GetUnit() == eCSSUnit_Centimeter
) {
233 actualDPI
= actualDPI
* 2.54f
;
234 } else if (actual
.GetUnit() == eCSSUnit_Pixel
) {
235 actualDPI
= actualDPI
* 96.0f
;
237 float requiredDPI
= required
.GetFloatValue();
238 if (required
.GetUnit() == eCSSUnit_Centimeter
) {
239 requiredDPI
= requiredDPI
* 2.54f
;
240 } else if (required
.GetUnit() == eCSSUnit_Pixel
) {
241 requiredDPI
= requiredDPI
* 96.0f
;
243 cmp
= DoCompare(actualDPI
, requiredDPI
);
246 case nsMediaFeature::eEnumerated
:
248 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Enumerated
,
250 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Enumerated
,
251 "bad required value");
252 NS_ASSERTION(mFeature
->mRangeType
== nsMediaFeature::eMinMaxNotAllowed
,
253 "bad range"); // we asserted above about mRange
254 // We don't really need DoCompare, but it doesn't hurt (and
255 // maybe the compiler will condense this case with eInteger).
256 cmp
= DoCompare(actual
.GetIntValue(), required
.GetIntValue());
259 case nsMediaFeature::eIdent
:
261 NS_ASSERTION(actual
.GetUnit() == eCSSUnit_Ident
,
263 NS_ASSERTION(required
.GetUnit() == eCSSUnit_Ident
,
264 "bad required value");
265 NS_ASSERTION(mFeature
->mRangeType
== nsMediaFeature::eMinMaxNotAllowed
,
267 cmp
= !(actual
== required
); // string comparison
272 case nsMediaExpression::eMin
:
274 case nsMediaExpression::eMax
:
276 case nsMediaExpression::eEqual
:
279 NS_NOTREACHED("unexpected mRange");
284 nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression
* aExpression
,
285 bool aExpressionMatches
)
287 const nsMediaFeature
*feature
= aExpression
->mFeature
;
288 FeatureEntry
*entry
= nullptr;
289 for (uint32_t i
= 0; i
< mFeatureCache
.Length(); ++i
) {
290 if (mFeatureCache
[i
].mFeature
== feature
) {
291 entry
= &mFeatureCache
[i
];
296 entry
= mFeatureCache
.AppendElement();
298 return; /* out of memory */
300 entry
->mFeature
= feature
;
303 ExpressionEntry eentry
= { *aExpression
, aExpressionMatches
};
304 entry
->mExpressions
.AppendElement(eentry
);
308 nsMediaQueryResultCacheKey::Matches(nsPresContext
* aPresContext
) const
310 if (aPresContext
->Medium() != mMedium
) {
314 for (uint32_t i
= 0; i
< mFeatureCache
.Length(); ++i
) {
315 const FeatureEntry
*entry
= &mFeatureCache
[i
];
318 (entry
->mFeature
->mGetter
)(aPresContext
, entry
->mFeature
, actual
);
319 NS_ENSURE_SUCCESS(rv
, false); // any better ideas?
321 for (uint32_t j
= 0; j
< entry
->mExpressions
.Length(); ++j
) {
322 const ExpressionEntry
&eentry
= entry
->mExpressions
[j
];
323 if (eentry
.mExpression
.Matches(aPresContext
, actual
) !=
324 eentry
.mExpressionMatches
) {
334 nsMediaQuery::AppendToString(nsAString
& aString
) const
336 if (mHadUnknownExpression
) {
337 aString
.AppendLiteral("not all");
341 NS_ASSERTION(!mNegated
|| !mHasOnly
, "can't have not and only");
342 NS_ASSERTION(!mTypeOmitted
|| (!mNegated
&& !mHasOnly
),
343 "can't have not or only when type is omitted");
346 aString
.AppendLiteral("not ");
347 } else if (mHasOnly
) {
348 aString
.AppendLiteral("only ");
350 aString
.Append(nsDependentAtomString(mMediaType
));
353 for (uint32_t i
= 0, i_end
= mExpressions
.Length(); i
< i_end
; ++i
) {
354 if (i
> 0 || !mTypeOmitted
)
355 aString
.AppendLiteral(" and ");
358 const nsMediaExpression
&expr
= mExpressions
[i
];
359 if (expr
.mRange
== nsMediaExpression::eMin
) {
360 aString
.AppendLiteral("min-");
361 } else if (expr
.mRange
== nsMediaExpression::eMax
) {
362 aString
.AppendLiteral("max-");
365 const nsMediaFeature
*feature
= expr
.mFeature
;
366 aString
.Append(nsDependentAtomString(*feature
->mName
));
368 if (expr
.mValue
.GetUnit() != eCSSUnit_Null
) {
369 aString
.AppendLiteral(": ");
370 switch (feature
->mValueType
) {
371 case nsMediaFeature::eLength
:
372 NS_ASSERTION(expr
.mValue
.IsLengthUnit(), "bad unit");
373 // Use 'width' as a property that takes length values
374 // written in the normal way.
375 expr
.mValue
.AppendToString(eCSSProperty_width
, aString
,
376 nsCSSValue::eNormalized
);
378 case nsMediaFeature::eInteger
:
379 case nsMediaFeature::eBoolInteger
:
380 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Integer
,
382 // Use 'z-index' as a property that takes integer values
383 // written without anything extra.
384 expr
.mValue
.AppendToString(eCSSProperty_z_index
, aString
,
385 nsCSSValue::eNormalized
);
387 case nsMediaFeature::eFloat
:
389 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Number
,
391 // Use 'line-height' as a property that takes float values
392 // written in the normal way.
393 expr
.mValue
.AppendToString(eCSSProperty_line_height
, aString
,
394 nsCSSValue::eNormalized
);
397 case nsMediaFeature::eIntRatio
:
399 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Array
,
401 nsCSSValue::Array
*array
= expr
.mValue
.GetArrayValue();
402 NS_ASSERTION(array
->Count() == 2, "unexpected length");
403 NS_ASSERTION(array
->Item(0).GetUnit() == eCSSUnit_Integer
,
405 NS_ASSERTION(array
->Item(1).GetUnit() == eCSSUnit_Integer
,
407 array
->Item(0).AppendToString(eCSSProperty_z_index
, aString
,
408 nsCSSValue::eNormalized
);
410 array
->Item(1).AppendToString(eCSSProperty_z_index
, aString
,
411 nsCSSValue::eNormalized
);
414 case nsMediaFeature::eResolution
:
416 aString
.AppendFloat(expr
.mValue
.GetFloatValue());
417 if (expr
.mValue
.GetUnit() == eCSSUnit_Inch
) {
418 aString
.AppendLiteral("dpi");
419 } else if (expr
.mValue
.GetUnit() == eCSSUnit_Pixel
) {
420 aString
.AppendLiteral("dppx");
422 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Centimeter
,
424 aString
.AppendLiteral("dpcm");
428 case nsMediaFeature::eEnumerated
:
429 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Enumerated
,
432 nsCSSProps::ValueToKeyword(expr
.mValue
.GetIntValue(),
433 feature
->mData
.mKeywordTable
),
436 case nsMediaFeature::eIdent
:
437 NS_ASSERTION(expr
.mValue
.GetUnit() == eCSSUnit_Ident
,
439 aString
.Append(expr
.mValue
.GetStringBufferValue());
449 nsMediaQuery::Clone() const
451 return new nsMediaQuery(*this);
455 nsMediaQuery::Matches(nsPresContext
* aPresContext
,
456 nsMediaQueryResultCacheKey
* aKey
) const
458 if (mHadUnknownExpression
)
462 mMediaType
== aPresContext
->Medium() || mMediaType
== nsGkAtoms::all
;
463 for (uint32_t i
= 0, i_end
= mExpressions
.Length(); match
&& i
< i_end
; ++i
) {
464 const nsMediaExpression
&expr
= mExpressions
[i
];
467 (expr
.mFeature
->mGetter
)(aPresContext
, expr
.mFeature
, actual
);
468 NS_ENSURE_SUCCESS(rv
, false); // any better ideas?
470 match
= expr
.Matches(aPresContext
, actual
);
472 aKey
->AddExpression(&expr
, match
);
476 return match
== !mNegated
;
479 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMediaList
)
480 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
481 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList
)
482 NS_INTERFACE_MAP_ENTRY(nsISupports
)
485 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMediaList
)
486 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMediaList
)
488 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsMediaList
)
490 nsMediaList::nsMediaList()
491 : mStyleSheet(nullptr)
496 nsMediaList::~nsMediaList()
500 /* virtual */ JSObject
*
501 nsMediaList::WrapObject(JSContext
* aCx
)
503 return MediaListBinding::Wrap(aCx
, this);
507 nsMediaList::GetText(nsAString
& aMediaText
)
509 aMediaText
.Truncate();
511 for (int32_t i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
512 nsMediaQuery
* query
= mArray
[i
];
514 query
->AppendToString(aMediaText
);
517 aMediaText
.AppendLiteral(", ");
522 // XXXbz this is so ill-defined in the spec, it's not clear quite what
523 // it should be doing....
525 nsMediaList::SetText(const nsAString
& aMediaText
)
529 bool htmlMode
= mStyleSheet
&& mStyleSheet
->GetOwnerNode();
531 parser
.ParseMediaList(aMediaText
, nullptr, 0, this, htmlMode
);
535 nsMediaList::Matches(nsPresContext
* aPresContext
,
536 nsMediaQueryResultCacheKey
* aKey
)
538 for (int32_t i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
539 if (mArray
[i
]->Matches(aPresContext
, aKey
)) {
543 return mArray
.IsEmpty();
547 nsMediaList::SetStyleSheet(CSSStyleSheet
* aSheet
)
549 NS_ASSERTION(aSheet
== mStyleSheet
|| !aSheet
|| !mStyleSheet
,
550 "multiple style sheets competing for one media list");
551 mStyleSheet
= aSheet
;
554 already_AddRefed
<nsMediaList
>
557 nsRefPtr
<nsMediaList
> result
= new nsMediaList();
558 result
->mArray
.AppendElements(mArray
.Length());
559 for (uint32_t i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
560 result
->mArray
[i
] = mArray
[i
]->Clone();
561 MOZ_ASSERT(result
->mArray
[i
]);
563 return result
.forget();
567 nsMediaList::GetMediaText(nsAString
& aMediaText
)
573 // "sheet" should be a CSSStyleSheet and "doc" should be an
574 // nsCOMPtr<nsIDocument>
575 #define BEGIN_MEDIA_CHANGE(sheet, doc) \
577 doc = sheet->GetOwningDocument(); \
579 mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true); \
581 sheet->WillDirty(); \
584 #define END_MEDIA_CHANGE(sheet, doc) \
588 /* XXXldb Pass something meaningful? */ \
590 doc->StyleRuleChanged(sheet, nullptr, nullptr); \
595 nsMediaList::SetMediaText(const nsAString
& aMediaText
)
597 nsCOMPtr
<nsIDocument
> doc
;
599 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
603 END_MEDIA_CHANGE(mStyleSheet
, doc
)
609 nsMediaList::GetLength(uint32_t* aLength
)
611 NS_ENSURE_ARG_POINTER(aLength
);
618 nsMediaList::Item(uint32_t aIndex
, nsAString
& aReturn
)
621 IndexedGetter(aIndex
, dummy
, aReturn
);
626 nsMediaList::IndexedGetter(uint32_t aIndex
, bool& aFound
, nsAString
& aReturn
)
628 if (aIndex
< Length()) {
631 mArray
[aIndex
]->AppendToString(aReturn
);
634 SetDOMStringToNull(aReturn
);
639 nsMediaList::DeleteMedium(const nsAString
& aOldMedium
)
642 nsCOMPtr
<nsIDocument
> doc
;
644 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
646 rv
= Delete(aOldMedium
);
650 END_MEDIA_CHANGE(mStyleSheet
, doc
)
656 nsMediaList::AppendMedium(const nsAString
& aNewMedium
)
659 nsCOMPtr
<nsIDocument
> doc
;
661 BEGIN_MEDIA_CHANGE(mStyleSheet
, doc
)
663 rv
= Append(aNewMedium
);
667 END_MEDIA_CHANGE(mStyleSheet
, doc
)
673 nsMediaList::Delete(const nsAString
& aOldMedium
)
675 if (aOldMedium
.IsEmpty())
676 return NS_ERROR_DOM_NOT_FOUND_ERR
;
678 for (int32_t i
= 0, i_end
= mArray
.Length(); i
< i_end
; ++i
) {
679 nsMediaQuery
* query
= mArray
[i
];
682 query
->AppendToString(buf
);
683 if (buf
== aOldMedium
) {
684 mArray
.RemoveElementAt(i
);
689 return NS_ERROR_DOM_NOT_FOUND_ERR
;
693 nsMediaList::Append(const nsAString
& aNewMedium
)
695 if (aNewMedium
.IsEmpty())
696 return NS_ERROR_DOM_NOT_FOUND_ERR
;
701 nsTArray
<nsAutoPtr
<nsMediaQuery
> > buf
;
702 mArray
.SwapElements(buf
);
704 if (mArray
.Length() == 1) {
705 nsMediaQuery
*query
= mArray
[0].forget();
706 if (!buf
.AppendElement(query
)) {
708 rv
= NS_ERROR_OUT_OF_MEMORY
;
712 mArray
.SwapElements(buf
);
718 // -------------------------------
719 // CSS Style Sheet Inner Data Container
723 CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheet
* aPrimarySheet
,
726 mCORSMode(aCORSMode
),
729 , mPrincipalSet(false)
732 MOZ_COUNT_CTOR(CSSStyleSheetInner
);
733 mSheets
.AppendElement(aPrimarySheet
);
735 mPrincipal
= do_CreateInstance("@mozilla.org/nullprincipal;1");
737 NS_RUNTIMEABORT("OOM");
741 static bool SetStyleSheetReference(css::Rule
* aRule
, void* aSheet
)
744 aRule
->SetStyleSheet(static_cast<CSSStyleSheet
*>(aSheet
));
749 struct ChildSheetListBuilder
{
750 nsRefPtr
<CSSStyleSheet
>* sheetSlot
;
751 CSSStyleSheet
* parent
;
753 void SetParentLinks(CSSStyleSheet
* aSheet
) {
754 aSheet
->mParent
= parent
;
755 aSheet
->SetOwningDocument(parent
->mDocument
);
758 static void ReparentChildList(CSSStyleSheet
* aPrimarySheet
,
759 CSSStyleSheet
* aFirstChild
)
761 for (CSSStyleSheet
*child
= aFirstChild
; child
; child
= child
->mNext
) {
762 child
->mParent
= aPrimarySheet
;
763 child
->SetOwningDocument(aPrimarySheet
->mDocument
);
769 CSSStyleSheet::RebuildChildList(css::Rule
* aRule
, void* aBuilder
)
771 int32_t type
= aRule
->GetType();
772 if (type
< css::Rule::IMPORT_RULE
) {
773 // Keep going till we get to the import rules.
777 if (type
!= css::Rule::IMPORT_RULE
) {
778 // We're past all the import rules; stop the enumeration.
782 ChildSheetListBuilder
* builder
=
783 static_cast<ChildSheetListBuilder
*>(aBuilder
);
785 // XXXbz We really need to decomtaminate all this stuff. Is there a reason
786 // that I can't just QI to ImportRule and get a CSSStyleSheet
788 nsCOMPtr
<nsIDOMCSSImportRule
> importRule(do_QueryInterface(aRule
));
789 NS_ASSERTION(importRule
, "GetType lied");
791 nsCOMPtr
<nsIDOMCSSStyleSheet
> childSheet
;
792 importRule
->GetStyleSheet(getter_AddRefs(childSheet
));
794 // Have to do this QI to be safe, since XPConnect can fake
795 // nsIDOMCSSStyleSheets
796 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(childSheet
);
801 (*builder
->sheetSlot
) = cssSheet
;
802 builder
->SetParentLinks(*builder
->sheetSlot
);
803 builder
->sheetSlot
= &(*builder
->sheetSlot
)->mNext
;
808 CSSStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const
811 const CSSStyleSheet
* s
= this;
813 n
+= aMallocSizeOf(s
);
815 // Each inner can be shared by multiple sheets. So we only count the inner
816 // if this sheet is the first one in the list of those sharing it. As a
817 // result, the first such sheet takes all the blame for the memory
818 // consumption of the inner, which isn't ideal but it's better than
819 // double-counting the inner.
820 if (s
->mInner
->mSheets
[0] == s
) {
821 n
+= s
->mInner
->SizeOfIncludingThis(aMallocSizeOf
);
824 // Measurement of the following members may be added later if DMD finds it
828 // - s->mRuleCollection
829 // - s->mRuleProcessors
831 // The following members are not measured:
832 // - s->mOwnerRule, because it's non-owning
839 CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner
& aCopy
,
840 CSSStyleSheet
* aPrimarySheet
)
842 mSheetURI(aCopy
.mSheetURI
),
843 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
844 mBaseURI(aCopy
.mBaseURI
),
845 mPrincipal(aCopy
.mPrincipal
),
846 mCORSMode(aCopy
.mCORSMode
),
847 mComplete(aCopy
.mComplete
)
849 , mPrincipalSet(aCopy
.mPrincipalSet
)
852 MOZ_COUNT_CTOR(CSSStyleSheetInner
);
853 AddSheet(aPrimarySheet
);
854 aCopy
.mOrderedRules
.EnumerateForwards(css::GroupRule::CloneRuleInto
, &mOrderedRules
);
855 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
, aPrimarySheet
);
857 ChildSheetListBuilder builder
= { &mFirstChild
, aPrimarySheet
};
858 mOrderedRules
.EnumerateForwards(CSSStyleSheet::RebuildChildList
, &builder
);
863 CSSStyleSheetInner::~CSSStyleSheetInner()
865 MOZ_COUNT_DTOR(CSSStyleSheetInner
);
866 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
, nullptr);
870 CSSStyleSheetInner::CloneFor(CSSStyleSheet
* aPrimarySheet
)
872 return new CSSStyleSheetInner(*this, aPrimarySheet
);
876 CSSStyleSheetInner::AddSheet(CSSStyleSheet
* aSheet
)
878 mSheets
.AppendElement(aSheet
);
882 CSSStyleSheetInner::RemoveSheet(CSSStyleSheet
* aSheet
)
884 if (1 == mSheets
.Length()) {
885 NS_ASSERTION(aSheet
== mSheets
.ElementAt(0), "bad parent");
889 if (aSheet
== mSheets
.ElementAt(0)) {
890 mSheets
.RemoveElementAt(0);
891 NS_ASSERTION(mSheets
.Length(), "no parents");
892 mOrderedRules
.EnumerateForwards(SetStyleSheetReference
,
893 mSheets
.ElementAt(0));
895 ChildSheetListBuilder::ReparentChildList(mSheets
[0], mFirstChild
);
898 mSheets
.RemoveElement(aSheet
);
903 AddNamespaceRuleToMap(css::Rule
* aRule
, nsXMLNameSpaceMap
* aMap
)
905 NS_ASSERTION(aRule
->GetType() == css::Rule::NAMESPACE_RULE
, "Bogus rule type");
907 nsRefPtr
<css::NameSpaceRule
> nameSpaceRule
= do_QueryObject(aRule
);
909 nsAutoString urlSpec
;
910 nameSpaceRule
->GetURLSpec(urlSpec
);
912 aMap
->AddPrefix(nameSpaceRule
->GetPrefix(), urlSpec
);
916 CreateNameSpace(css::Rule
* aRule
, void* aNameSpacePtr
)
918 int32_t type
= aRule
->GetType();
919 if (css::Rule::NAMESPACE_RULE
== type
) {
920 AddNamespaceRuleToMap(aRule
,
921 static_cast<nsXMLNameSpaceMap
*>(aNameSpacePtr
));
924 // stop if not namespace, import or charset because namespace can't follow
926 return (css::Rule::CHARSET_RULE
== type
|| css::Rule::IMPORT_RULE
== type
);
930 CSSStyleSheetInner::RebuildNameSpaces()
932 // Just nuke our existing namespace map, if any
933 if (NS_SUCCEEDED(CreateNamespaceMap())) {
934 mOrderedRules
.EnumerateForwards(CreateNameSpace
, mNameSpaceMap
);
939 CSSStyleSheetInner::CreateNamespaceMap()
941 mNameSpaceMap
= nsXMLNameSpaceMap::Create(false);
942 NS_ENSURE_TRUE(mNameSpaceMap
, NS_ERROR_OUT_OF_MEMORY
);
943 // Override the default namespace map behavior for the null prefix to
944 // return the wildcard namespace instead of the null namespace.
945 mNameSpaceMap
->AddPrefix(nullptr, kNameSpaceID_Unknown
);
950 CSSStyleSheetInner::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const
952 size_t n
= aMallocSizeOf(this);
953 n
+= mOrderedRules
.SizeOfExcludingThis(css::Rule::SizeOfCOMArrayElementIncludingThis
,
955 n
+= mFirstChild
? mFirstChild
->SizeOfIncludingThis(aMallocSizeOf
) : 0;
957 // Measurement of the following members may be added later if DMD finds it is
960 // - mOriginalSheetURI
965 // The following members are not measured:
966 // - mSheets, because it's non-owning
971 // -------------------------------
975 CSSStyleSheet::CSSStyleSheet(CORSMode aCORSMode
)
980 mOwningNode(nullptr),
983 mScopeElement(nullptr),
984 mRuleProcessors(nullptr)
986 mInner
= new CSSStyleSheetInner(this, aCORSMode
);
991 CSSStyleSheet::CSSStyleSheet(const CSSStyleSheet
& aCopy
,
992 CSSStyleSheet
* aParentToUse
,
993 css::ImportRule
* aOwnerRuleToUse
,
994 nsIDocument
* aDocumentToUse
,
995 nsINode
* aOwningNodeToUse
)
996 : mTitle(aCopy
.mTitle
),
997 mParent(aParentToUse
),
998 mOwnerRule(aOwnerRuleToUse
),
999 mDocument(aDocumentToUse
),
1000 mOwningNode(aOwningNodeToUse
),
1001 mDisabled(aCopy
.mDisabled
),
1002 mDirty(aCopy
.mDirty
),
1003 mScopeElement(nullptr),
1004 mInner(aCopy
.mInner
),
1005 mRuleProcessors(nullptr)
1008 mInner
->AddSheet(this);
1010 if (mDirty
) { // CSSOM's been there, force full copy now
1011 NS_ASSERTION(mInner
->mComplete
, "Why have rules been accessed on an incomplete sheet?");
1012 // FIXME: handle failure?
1013 EnsureUniqueInner();
1017 // XXX This is wrong; we should be keeping @import rules and
1019 mMedia
= aCopy
.mMedia
->Clone();
1025 CSSStyleSheet::~CSSStyleSheet()
1027 for (CSSStyleSheet
* child
= mInner
->mFirstChild
;
1029 child
= child
->mNext
) {
1030 // XXXbz this is a little bogus; see the XXX comment where we
1031 // declare mFirstChild.
1032 if (child
->mParent
== this) {
1033 child
->mParent
= nullptr;
1034 child
->mDocument
= nullptr;
1037 DropRuleCollection();
1039 mInner
->RemoveSheet(this);
1040 // XXX The document reference is not reference counted and should
1041 // not be released. The document will let us know when it is going
1043 if (mRuleProcessors
) {
1044 NS_ASSERTION(mRuleProcessors
->Length() == 0, "destructing sheet with rule processor reference");
1045 delete mRuleProcessors
; // weak refs, should be empty here anyway
1050 CSSStyleSheet::DropRuleCollection()
1052 if (mRuleCollection
) {
1053 mRuleCollection
->DropReference();
1054 mRuleCollection
= nullptr;
1059 CSSStyleSheet::DropMedia()
1062 mMedia
->SetStyleSheet(nullptr);
1068 CSSStyleSheet::UnlinkInner()
1070 // We can only have a cycle through our inner if we have a unique inner,
1071 // because otherwise there are no JS wrappers for anything in the inner.
1072 if (mInner
->mSheets
.Length() != 1) {
1076 mInner
->mOrderedRules
.EnumerateForwards(SetStyleSheetReference
, nullptr);
1077 mInner
->mOrderedRules
.Clear();
1079 // Have to be a bit careful with child sheets, because we want to
1080 // drop their mNext pointers and null out their mParent and
1081 // mDocument, but don't want to work with deleted objects. And we
1082 // don't want to do any addrefing in the process, just to make sure
1083 // we don't confuse the cycle collector (though on the face of it,
1084 // addref/release pairs during unlink should probably be ok).
1085 nsRefPtr
<CSSStyleSheet
> child
;
1086 child
.swap(mInner
->mFirstChild
);
1088 MOZ_ASSERT(child
->mParent
== this, "We have a unique inner!");
1089 child
->mParent
= nullptr;
1090 child
->mDocument
= nullptr;
1091 nsRefPtr
<CSSStyleSheet
> next
;
1092 // Null out child->mNext, but don't let it die yet
1093 next
.swap(child
->mNext
);
1094 // Switch to looking at the old value of child->mNext next iteration
1096 // "next" is now our previous value of child; it'll get released
1097 // as we loop around.
1102 CSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback
&cb
)
1104 // We can only have a cycle through our inner if we have a unique inner,
1105 // because otherwise there are no JS wrappers for anything in the inner.
1106 if (mInner
->mSheets
.Length() != 1) {
1110 nsRefPtr
<CSSStyleSheet
>* childSheetSlot
= &mInner
->mFirstChild
;
1111 while (*childSheetSlot
) {
1112 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "child sheet");
1113 cb
.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIStyleSheet
*, childSheetSlot
->get()));
1114 childSheetSlot
= &(*childSheetSlot
)->mNext
;
1117 const nsCOMArray
<css::Rule
>& rules
= mInner
->mOrderedRules
;
1118 for (int32_t i
= 0, count
= rules
.Count(); i
< count
; ++i
) {
1119 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mOrderedRules[i]");
1120 cb
.NoteXPCOMChild(rules
[i
]->GetExistingDOMRule());
1124 // QueryInterface implementation for CSSStyleSheet
1125 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSStyleSheet
)
1126 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1127 NS_INTERFACE_MAP_ENTRY(nsIStyleSheet
)
1128 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet
)
1129 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet
)
1130 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
1131 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIStyleSheet
)
1132 if (aIID
.Equals(NS_GET_IID(CSSStyleSheet
)))
1133 foundInterface
= reinterpret_cast<nsISupports
*>(this);
1135 NS_INTERFACE_MAP_END
1138 NS_IMPL_CYCLE_COLLECTING_ADDREF(CSSStyleSheet
)
1139 NS_IMPL_CYCLE_COLLECTING_RELEASE(CSSStyleSheet
)
1141 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSStyleSheet
)
1143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSStyleSheet
)
1145 // We do not unlink mNext; our parent will handle that. If we
1146 // unlinked it here, our parent would not be able to walk its list
1147 // of child sheets and null out the back-references to it, if we got
1148 // unlinked before it does.
1149 tmp
->DropRuleCollection();
1151 tmp
->mScopeElement
= nullptr;
1152 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1153 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CSSStyleSheet
)
1155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia
)
1156 // We do not traverse mNext; our parent will handle that. See
1157 // comments in Unlink for why.
1158 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection
)
1159 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement
)
1160 tmp
->TraverseInner(cb
);
1161 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
1162 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1163 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(CSSStyleSheet
)
1166 CSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor
* aProcessor
)
1168 if (! mRuleProcessors
) {
1169 mRuleProcessors
= new nsAutoTArray
<nsCSSRuleProcessor
*, 8>();
1170 if (!mRuleProcessors
)
1171 return NS_ERROR_OUT_OF_MEMORY
;
1173 NS_ASSERTION(mRuleProcessors
->NoIndex
== mRuleProcessors
->IndexOf(aProcessor
),
1174 "processor already registered");
1175 mRuleProcessors
->AppendElement(aProcessor
); // weak ref
1180 CSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor
* aProcessor
)
1182 if (!mRuleProcessors
)
1183 return NS_ERROR_FAILURE
;
1184 return mRuleProcessors
->RemoveElement(aProcessor
)
1191 CSSStyleSheet::SetURIs(nsIURI
* aSheetURI
, nsIURI
* aOriginalSheetURI
,
1194 NS_PRECONDITION(aSheetURI
&& aBaseURI
, "null ptr");
1196 NS_ASSERTION(mInner
->mOrderedRules
.Count() == 0 && !mInner
->mComplete
,
1197 "Can't call SetURL on sheets that are complete or have rules");
1199 mInner
->mSheetURI
= aSheetURI
;
1200 mInner
->mOriginalSheetURI
= aOriginalSheetURI
;
1201 mInner
->mBaseURI
= aBaseURI
;
1205 CSSStyleSheet::SetPrincipal(nsIPrincipal
* aPrincipal
)
1207 NS_PRECONDITION(!mInner
->mPrincipalSet
,
1208 "Should have an inner whose principal has not yet been set");
1210 mInner
->mPrincipal
= aPrincipal
;
1212 mInner
->mPrincipalSet
= true;
1217 /* virtual */ nsIURI
*
1218 CSSStyleSheet::GetSheetURI() const
1220 return mInner
->mSheetURI
;
1223 /* virtual */ nsIURI
*
1224 CSSStyleSheet::GetBaseURI() const
1226 return mInner
->mBaseURI
;
1230 CSSStyleSheet::GetType(nsString
& aType
) const
1232 aType
.AssignLiteral("text/css");
1236 CSSStyleSheet::UseForPresentation(nsPresContext
* aPresContext
,
1237 nsMediaQueryResultCacheKey
& aKey
) const
1240 return mMedia
->Matches(aPresContext
, &aKey
);
1247 CSSStyleSheet::SetMedia(nsMediaList
* aMedia
)
1253 CSSStyleSheet::HasRules() const
1255 return StyleRuleCount() != 0;
1259 CSSStyleSheet::IsApplicable() const
1261 return !mDisabled
&& mInner
->mComplete
;
1265 CSSStyleSheet::SetEnabled(bool aEnabled
)
1267 // Internal method, so callers must handle BeginUpdate/EndUpdate
1268 bool oldDisabled
= mDisabled
;
1269 mDisabled
= !aEnabled
;
1271 if (mInner
->mComplete
&& oldDisabled
!= mDisabled
) {
1272 ClearRuleCascades();
1275 mDocument
->SetStyleSheetApplicableState(this, !mDisabled
);
1281 CSSStyleSheet::IsComplete() const
1283 return mInner
->mComplete
;
1287 CSSStyleSheet::SetComplete()
1289 NS_ASSERTION(!mDirty
, "Can't set a dirty sheet complete!");
1290 mInner
->mComplete
= true;
1291 if (mDocument
&& !mDisabled
) {
1292 // Let the document know
1293 mDocument
->BeginUpdate(UPDATE_STYLE
);
1294 mDocument
->SetStyleSheetApplicableState(this, true);
1295 mDocument
->EndUpdate(UPDATE_STYLE
);
1298 if (mOwningNode
&& !mDisabled
&&
1299 mOwningNode
->HasFlag(NODE_IS_IN_SHADOW_TREE
) &&
1300 mOwningNode
->IsContent()) {
1301 ShadowRoot
* shadowRoot
= mOwningNode
->AsContent()->GetContainingShadow();
1302 shadowRoot
->StyleSheetChanged();
1306 /* virtual */ nsIStyleSheet
*
1307 CSSStyleSheet::GetParentSheet() const
1312 /* virtual */ nsIDocument
*
1313 CSSStyleSheet::GetOwningDocument() const
1319 CSSStyleSheet::SetOwningDocument(nsIDocument
* aDocument
)
1320 { // not ref counted
1321 mDocument
= aDocument
;
1322 // Now set the same document on all our child sheets....
1323 // XXXbz this is a little bogus; see the XXX comment where we
1324 // declare mFirstChild.
1325 for (CSSStyleSheet
* child
= mInner
->mFirstChild
;
1326 child
; child
= child
->mNext
) {
1327 if (child
->mParent
== this) {
1328 child
->SetOwningDocument(aDocument
);
1334 CSSStyleSheet::FindOwningWindowInnerID() const
1336 uint64_t windowID
= 0;
1338 windowID
= mDocument
->InnerWindowID();
1341 if (windowID
== 0 && mOwningNode
) {
1342 windowID
= mOwningNode
->OwnerDoc()->InnerWindowID();
1345 if (windowID
== 0 && mOwnerRule
) {
1346 nsCOMPtr
<nsIStyleSheet
> sheet
= static_cast<css::Rule
*>(mOwnerRule
)->GetStyleSheet();
1348 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(sheet
);
1350 windowID
= cssSheet
->FindOwningWindowInnerID();
1355 if (windowID
== 0 && mParent
) {
1356 windowID
= mParent
->FindOwningWindowInnerID();
1363 CSSStyleSheet::AppendStyleSheet(CSSStyleSheet
* aSheet
)
1365 NS_PRECONDITION(nullptr != aSheet
, "null arg");
1368 nsRefPtr
<CSSStyleSheet
>* tail
= &mInner
->mFirstChild
;
1370 tail
= &(*tail
)->mNext
;
1374 // This is not reference counted. Our parent tells us when
1376 aSheet
->mParent
= this;
1377 aSheet
->mDocument
= mDocument
;
1382 CSSStyleSheet::InsertStyleSheetAt(CSSStyleSheet
* aSheet
, int32_t aIndex
)
1384 NS_PRECONDITION(nullptr != aSheet
, "null arg");
1387 nsRefPtr
<CSSStyleSheet
>* tail
= &mInner
->mFirstChild
;
1388 while (*tail
&& aIndex
) {
1390 tail
= &(*tail
)->mNext
;
1392 aSheet
->mNext
= *tail
;
1395 // This is not reference counted. Our parent tells us when
1397 aSheet
->mParent
= this;
1398 aSheet
->mDocument
= mDocument
;
1403 CSSStyleSheet::PrependStyleRule(css::Rule
* aRule
)
1405 NS_PRECONDITION(nullptr != aRule
, "null arg");
1408 mInner
->mOrderedRules
.InsertObjectAt(aRule
, 0);
1409 aRule
->SetStyleSheet(this);
1412 if (css::Rule::NAMESPACE_RULE
== aRule
->GetType()) {
1413 // no api to prepend a namespace (ugh), release old ones and re-create them all
1414 mInner
->RebuildNameSpaces();
1419 CSSStyleSheet::AppendStyleRule(css::Rule
* aRule
)
1421 NS_PRECONDITION(nullptr != aRule
, "null arg");
1424 mInner
->mOrderedRules
.AppendObject(aRule
);
1425 aRule
->SetStyleSheet(this);
1428 if (css::Rule::NAMESPACE_RULE
== aRule
->GetType()) {
1432 RegisterNamespaceRule(aRule
);
1433 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv
),
1434 "RegisterNamespaceRule returned error");
1439 CSSStyleSheet::ReplaceStyleRule(css::Rule
* aOld
, css::Rule
* aNew
)
1441 NS_PRECONDITION(mInner
->mOrderedRules
.Count() != 0, "can't have old rule");
1442 NS_PRECONDITION(mInner
->mComplete
, "No replacing in an incomplete sheet!");
1445 int32_t index
= mInner
->mOrderedRules
.IndexOf(aOld
);
1446 if (MOZ_UNLIKELY(index
== -1)) {
1447 NS_NOTREACHED("Couldn't find old rule");
1450 mInner
->mOrderedRules
.ReplaceObjectAt(aNew
, index
);
1452 aNew
->SetStyleSheet(this);
1453 aOld
->SetStyleSheet(nullptr);
1455 NS_ASSERTION(css::Rule::NAMESPACE_RULE
!= aNew
->GetType(), "not yet implemented");
1456 NS_ASSERTION(css::Rule::NAMESPACE_RULE
!= aOld
->GetType(), "not yet implemented");
1460 CSSStyleSheet::StyleRuleCount() const
1462 return mInner
->mOrderedRules
.Count();
1466 CSSStyleSheet::GetStyleRuleAt(int32_t aIndex
) const
1468 // Important: If this function is ever made scriptable, we must add
1469 // a security check here. See GetCssRules below for an example.
1470 return mInner
->mOrderedRules
.SafeObjectAt(aIndex
);
1474 CSSStyleSheet::StyleSheetCount() const
1476 // XXX Far from an ideal way to do this, but the hope is that
1477 // it won't be done too often. If it is, we might want to
1478 // consider storing the children in an array.
1481 const CSSStyleSheet
* child
= mInner
->mFirstChild
;
1484 child
= child
->mNext
;
1490 CSSStyleSheet::EnsureUniqueInnerResult
1491 CSSStyleSheet::EnsureUniqueInner()
1495 NS_ABORT_IF_FALSE(mInner
->mSheets
.Length() != 0,
1496 "unexpected number of outers");
1497 if (mInner
->mSheets
.Length() == 1) {
1498 return eUniqueInner_AlreadyUnique
;
1500 CSSStyleSheetInner
* clone
= mInner
->CloneFor(this);
1502 mInner
->RemoveSheet(this);
1505 // otherwise the rule processor has pointers to the old rules
1506 ClearRuleCascades();
1508 return eUniqueInner_ClonedInner
;
1512 CSSStyleSheet::AppendAllChildSheets(nsTArray
<CSSStyleSheet
*>& aArray
)
1514 for (CSSStyleSheet
* child
= mInner
->mFirstChild
; child
;
1515 child
= child
->mNext
) {
1516 aArray
.AppendElement(child
);
1520 already_AddRefed
<CSSStyleSheet
>
1521 CSSStyleSheet::Clone(CSSStyleSheet
* aCloneParent
,
1522 css::ImportRule
* aCloneOwnerRule
,
1523 nsIDocument
* aCloneDocument
,
1524 nsINode
* aCloneOwningNode
) const
1526 nsRefPtr
<CSSStyleSheet
> clone
= new CSSStyleSheet(*this,
1531 return clone
.forget();
1536 ListRules(const nsCOMArray
<css::Rule
>& aRules
, FILE* aOut
, int32_t aIndent
)
1538 for (int32_t index
= aRules
.Count() - 1; index
>= 0; --index
) {
1539 aRules
.ObjectAt(index
)->List(aOut
, aIndent
);
1543 struct ListEnumData
{
1544 ListEnumData(FILE* aOut
, int32_t aIndent
)
1554 CSSStyleSheet::List(FILE* out
, int32_t aIndent
) const
1560 for (index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
1562 fputs("CSS Style Sheet: ", out
);
1563 nsAutoCString urlSpec
;
1564 nsresult rv
= mInner
->mSheetURI
->GetSpec(urlSpec
);
1565 if (NS_SUCCEEDED(rv
) && !urlSpec
.IsEmpty()) {
1566 fputs(urlSpec
.get(), out
);
1570 fputs(" media: ", out
);
1571 nsAutoString buffer
;
1572 mMedia
->GetText(buffer
);
1573 fputs(NS_ConvertUTF16toUTF8(buffer
).get(), out
);
1577 for (const CSSStyleSheet
* child
= mInner
->mFirstChild
;
1579 child
= child
->mNext
) {
1580 child
->List(out
, aIndent
+ 1);
1583 fputs("Rules in source order:\n", out
);
1584 ListRules(mInner
->mOrderedRules
, out
, aIndent
);
1589 CSSStyleSheet::ClearRuleCascades()
1591 if (mRuleProcessors
) {
1592 nsCSSRuleProcessor
**iter
= mRuleProcessors
->Elements(),
1593 **end
= iter
+ mRuleProcessors
->Length();
1594 for(; iter
!= end
; ++iter
) {
1595 (*iter
)->ClearRuleCascades();
1599 CSSStyleSheet
* parent
= (CSSStyleSheet
*)mParent
;
1600 parent
->ClearRuleCascades();
1605 CSSStyleSheet::WillDirty()
1607 if (mInner
->mComplete
) {
1608 EnsureUniqueInner();
1613 CSSStyleSheet::DidDirty()
1615 NS_ABORT_IF_FALSE(!mInner
->mComplete
|| mDirty
,
1616 "caller must have called WillDirty()");
1617 ClearRuleCascades();
1621 CSSStyleSheet::SubjectSubsumesInnerPrincipal()
1623 nsCOMPtr
<nsIPrincipal
> subjectPrincipal
= nsContentUtils::SubjectPrincipal();
1624 if (subjectPrincipal
->Subsumes(mInner
->mPrincipal
)) {
1628 // Allow access only if CORS mode is not NONE
1629 if (GetCORSMode() == CORS_NONE
) {
1630 return NS_ERROR_DOM_SECURITY_ERR
;
1633 // Now make sure we set the principal of our inner to the
1634 // subjectPrincipal. That means we need a unique inner, of
1635 // course. But we don't want to do that if we're not complete
1636 // yet. Luckily, all the callers of this method throw anyway if
1637 // not complete, so we can just do that here too.
1638 if (!mInner
->mComplete
) {
1639 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1644 mInner
->mPrincipal
= subjectPrincipal
;
1652 CSSStyleSheet::RegisterNamespaceRule(css::Rule
* aRule
)
1654 if (!mInner
->mNameSpaceMap
) {
1655 nsresult rv
= mInner
->CreateNamespaceMap();
1656 NS_ENSURE_SUCCESS(rv
, rv
);
1659 AddNamespaceRuleToMap(aRule
, mInner
->mNameSpaceMap
);
1663 // nsIDOMStyleSheet interface
1665 CSSStyleSheet::GetType(nsAString
& aType
)
1667 aType
.AssignLiteral("text/css");
1672 CSSStyleSheet::GetDisabled(bool* aDisabled
)
1674 *aDisabled
= Disabled();
1679 CSSStyleSheet::SetDisabled(bool aDisabled
)
1681 // DOM method, so handle BeginUpdate/EndUpdate
1682 MOZ_AUTO_DOC_UPDATE(mDocument
, UPDATE_STYLE
, true);
1683 CSSStyleSheet::SetEnabled(!aDisabled
);
1688 CSSStyleSheet::GetOwnerNode(nsIDOMNode
** aOwnerNode
)
1690 nsCOMPtr
<nsIDOMNode
> ownerNode
= do_QueryInterface(GetOwnerNode());
1691 ownerNode
.forget(aOwnerNode
);
1696 CSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet
** aParentStyleSheet
)
1698 NS_ENSURE_ARG_POINTER(aParentStyleSheet
);
1700 NS_IF_ADDREF(*aParentStyleSheet
= mParent
);
1706 CSSStyleSheet::GetHref(nsAString
& aHref
)
1708 if (mInner
->mOriginalSheetURI
) {
1710 mInner
->mOriginalSheetURI
->GetSpec(str
);
1711 CopyUTF8toUTF16(str
, aHref
);
1713 SetDOMStringToNull(aHref
);
1720 CSSStyleSheet::GetTitle(nsString
& aTitle
) const
1726 CSSStyleSheet::GetTitle(nsAString
& aTitle
)
1728 aTitle
.Assign(mTitle
);
1733 CSSStyleSheet::GetMedia(nsIDOMMediaList
** aMedia
)
1735 NS_ADDREF(*aMedia
= Media());
1740 CSSStyleSheet::Media()
1743 mMedia
= new nsMediaList();
1744 mMedia
->SetStyleSheet(this);
1751 CSSStyleSheet::GetOwnerRule(nsIDOMCSSRule
** aOwnerRule
)
1753 NS_IF_ADDREF(*aOwnerRule
= GetOwnerRule());
1758 CSSStyleSheet::GetDOMOwnerRule() const
1760 return mOwnerRule
? mOwnerRule
->GetDOMRule() : nullptr;
1764 CSSStyleSheet::GetCssRules(nsIDOMCSSRuleList
** aCssRules
)
1767 nsCOMPtr
<nsIDOMCSSRuleList
> rules
= GetCssRules(rv
);
1768 rules
.forget(aCssRules
);
1769 return rv
.ErrorCode();
1773 CSSStyleSheet::GetCssRules(ErrorResult
& aRv
)
1775 // No doing this on incomplete sheets!
1776 if (!mInner
->mComplete
) {
1777 aRv
.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
1781 //-- Security check: Only scripts whose principal subsumes that of the
1782 // style sheet can access rule collections.
1783 nsresult rv
= SubjectSubsumesInnerPrincipal();
1784 if (NS_FAILED(rv
)) {
1789 // OK, security check passed, so get the rule collection
1790 if (!mRuleCollection
) {
1791 mRuleCollection
= new CSSRuleListImpl(this);
1794 return mRuleCollection
;
1798 CSSStyleSheet::InsertRule(const nsAString
& aRule
,
1802 //-- Security check: Only scripts whose principal subsumes that of the
1803 // style sheet can modify rule collections.
1804 nsresult rv
= SubjectSubsumesInnerPrincipal();
1805 NS_ENSURE_SUCCESS(rv
, rv
);
1807 return InsertRuleInternal(aRule
, aIndex
, aReturn
);
1811 RuleHasPendingChildSheet(css::Rule
*cssRule
)
1813 nsCOMPtr
<nsIDOMCSSImportRule
> importRule(do_QueryInterface(cssRule
));
1814 NS_ASSERTION(importRule
, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
1815 nsCOMPtr
<nsIDOMCSSStyleSheet
> childSheet
;
1816 importRule
->GetStyleSheet(getter_AddRefs(childSheet
));
1817 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(childSheet
);
1818 return cssSheet
!= nullptr && !cssSheet
->IsComplete();
1822 CSSStyleSheet::InsertRuleInternal(const nsAString
& aRule
,
1826 // No doing this if the sheet is not complete!
1827 if (!mInner
->mComplete
) {
1828 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1833 if (aIndex
> uint32_t(mInner
->mOrderedRules
.Count()))
1834 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
1836 NS_ASSERTION(uint32_t(mInner
->mOrderedRules
.Count()) <= INT32_MAX
,
1837 "Too many style rules!");
1839 // Hold strong ref to the CSSLoader in case the document update
1840 // kills the document
1841 nsRefPtr
<css::Loader
> loader
;
1843 loader
= mDocument
->CSSLoader();
1844 NS_ASSERTION(loader
, "Document with no CSS loader!");
1847 nsCSSParser
css(loader
, this);
1849 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
1851 nsRefPtr
<css::Rule
> rule
;
1852 nsresult result
= css
.ParseRule(aRule
, mInner
->mSheetURI
, mInner
->mBaseURI
,
1853 mInner
->mPrincipal
, getter_AddRefs(rule
));
1854 if (NS_FAILED(result
))
1857 // Hierarchy checking.
1858 int32_t newType
= rule
->GetType();
1860 // check that we're not inserting before a charset rule
1861 css::Rule
* nextRule
= mInner
->mOrderedRules
.SafeObjectAt(aIndex
);
1863 int32_t nextType
= nextRule
->GetType();
1864 if (nextType
== css::Rule::CHARSET_RULE
) {
1865 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1868 if (nextType
== css::Rule::IMPORT_RULE
&&
1869 newType
!= css::Rule::CHARSET_RULE
&&
1870 newType
!= css::Rule::IMPORT_RULE
) {
1871 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1874 if (nextType
== css::Rule::NAMESPACE_RULE
&&
1875 newType
!= css::Rule::CHARSET_RULE
&&
1876 newType
!= css::Rule::IMPORT_RULE
&&
1877 newType
!= css::Rule::NAMESPACE_RULE
) {
1878 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1883 // no inserting charset at nonzero position
1884 if (newType
== css::Rule::CHARSET_RULE
) {
1885 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1888 css::Rule
* prevRule
= mInner
->mOrderedRules
.SafeObjectAt(aIndex
- 1);
1889 int32_t prevType
= prevRule
->GetType();
1891 if (newType
== css::Rule::IMPORT_RULE
&&
1892 prevType
!= css::Rule::CHARSET_RULE
&&
1893 prevType
!= css::Rule::IMPORT_RULE
) {
1894 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1897 if (newType
== css::Rule::NAMESPACE_RULE
&&
1898 prevType
!= css::Rule::CHARSET_RULE
&&
1899 prevType
!= css::Rule::IMPORT_RULE
&&
1900 prevType
!= css::Rule::NAMESPACE_RULE
) {
1901 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
1905 bool insertResult
= mInner
->mOrderedRules
.InsertObjectAt(rule
, aIndex
);
1906 NS_ENSURE_TRUE(insertResult
, NS_ERROR_OUT_OF_MEMORY
);
1909 rule
->SetStyleSheet(this);
1911 int32_t type
= rule
->GetType();
1912 if (type
== css::Rule::NAMESPACE_RULE
) {
1913 // XXXbz does this screw up when inserting a namespace rule before
1914 // another namespace rule that binds the same prefix to a different
1916 result
= RegisterNamespaceRule(rule
);
1917 NS_ENSURE_SUCCESS(result
, result
);
1920 // We don't notify immediately for @import rules, but rather when
1921 // the sheet the rule is importing is loaded (see StyleSheetLoaded)
1922 if ((type
!= css::Rule::IMPORT_RULE
|| !RuleHasPendingChildSheet(rule
)) &&
1924 mDocument
->StyleRuleAdded(this, rule
);
1932 CSSStyleSheet::DeleteRule(uint32_t aIndex
)
1934 // No doing this if the sheet is not complete!
1935 if (!mInner
->mComplete
) {
1936 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
1939 //-- Security check: Only scripts whose principal subsumes that of the
1940 // style sheet can modify rule collections.
1941 nsresult rv
= SubjectSubsumesInnerPrincipal();
1942 NS_ENSURE_SUCCESS(rv
, rv
);
1944 // XXX TBI: handle @rule types
1945 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
1949 if (aIndex
>= uint32_t(mInner
->mOrderedRules
.Count()))
1950 return NS_ERROR_DOM_INDEX_SIZE_ERR
;
1952 NS_ASSERTION(uint32_t(mInner
->mOrderedRules
.Count()) <= INT32_MAX
,
1953 "Too many style rules!");
1955 // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
1956 nsRefPtr
<css::Rule
> rule
= mInner
->mOrderedRules
.ObjectAt(aIndex
);
1958 mInner
->mOrderedRules
.RemoveObjectAt(aIndex
);
1959 if (mDocument
&& mDocument
->StyleSheetChangeEventsEnabled()) {
1960 // Force creation of the DOM rule, so that it can be put on the
1961 // StyleRuleRemoved event object.
1964 rule
->SetStyleSheet(nullptr);
1968 mDocument
->StyleRuleRemoved(this, rule
);
1976 CSSStyleSheet::DeleteRuleFromGroup(css::GroupRule
* aGroup
, uint32_t aIndex
)
1978 NS_ENSURE_ARG_POINTER(aGroup
);
1979 NS_ASSERTION(mInner
->mComplete
, "No deleting from an incomplete sheet!");
1980 nsRefPtr
<css::Rule
> rule
= aGroup
->GetStyleRuleAt(aIndex
);
1981 NS_ENSURE_TRUE(rule
, NS_ERROR_ILLEGAL_VALUE
);
1983 // check that the rule actually belongs to this sheet!
1984 if (this != rule
->GetStyleSheet()) {
1985 return NS_ERROR_INVALID_ARG
;
1988 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
1992 nsresult result
= aGroup
->DeleteStyleRuleAt(aIndex
);
1993 NS_ENSURE_SUCCESS(result
, result
);
1995 rule
->SetStyleSheet(nullptr);
2000 mDocument
->StyleRuleRemoved(this, rule
);
2007 CSSStyleSheet::InsertRuleIntoGroup(const nsAString
& aRule
,
2008 css::GroupRule
* aGroup
,
2012 NS_ASSERTION(mInner
->mComplete
, "No inserting into an incomplete sheet!");
2013 // check that the group actually belongs to this sheet!
2014 if (this != aGroup
->GetStyleSheet()) {
2015 return NS_ERROR_INVALID_ARG
;
2018 // Hold strong ref to the CSSLoader in case the document update
2019 // kills the document
2020 nsRefPtr
<css::Loader
> loader
;
2022 loader
= mDocument
->CSSLoader();
2023 NS_ASSERTION(loader
, "Document with no CSS loader!");
2026 nsCSSParser
css(loader
, this);
2028 // parse and grab the rule
2029 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
2033 nsRefPtr
<css::Rule
> rule
;
2034 nsresult result
= css
.ParseRule(aRule
, mInner
->mSheetURI
, mInner
->mBaseURI
,
2035 mInner
->mPrincipal
, getter_AddRefs(rule
));
2036 if (NS_FAILED(result
))
2039 switch (rule
->GetType()) {
2040 case css::Rule::STYLE_RULE
:
2041 case css::Rule::MEDIA_RULE
:
2042 case css::Rule::FONT_FACE_RULE
:
2043 case css::Rule::PAGE_RULE
:
2044 case css::Rule::KEYFRAMES_RULE
:
2045 case css::Rule::COUNTER_STYLE_RULE
:
2046 case css::Rule::DOCUMENT_RULE
:
2047 case css::Rule::SUPPORTS_RULE
:
2048 // these types are OK to insert into a group
2050 case css::Rule::CHARSET_RULE
:
2051 case css::Rule::IMPORT_RULE
:
2052 case css::Rule::NAMESPACE_RULE
:
2054 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
2056 NS_NOTREACHED("unexpected rule type");
2057 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR
;
2060 result
= aGroup
->InsertStyleRuleAt(aIndex
, rule
);
2061 NS_ENSURE_SUCCESS(result
, result
);
2065 mDocument
->StyleRuleAdded(this, rule
);
2073 CSSStyleSheet::ReplaceRuleInGroup(css::GroupRule
* aGroup
,
2074 css::Rule
* aOld
, css::Rule
* aNew
)
2076 NS_PRECONDITION(mInner
->mComplete
, "No replacing in an incomplete sheet!");
2077 NS_ASSERTION(this == aGroup
->GetStyleSheet(), "group doesn't belong to this sheet");
2081 nsresult result
= aGroup
->ReplaceStyleRule(aOld
, aNew
);
2086 // nsICSSLoaderObserver implementation
2088 CSSStyleSheet::StyleSheetLoaded(CSSStyleSheet
* aSheet
,
2092 if (aSheet
->GetParentSheet() == nullptr) {
2093 return NS_OK
; // ignore if sheet has been detached already (see parseSheet)
2095 NS_ASSERTION(this == aSheet
->GetParentSheet(),
2096 "We are being notified of a sheet load for a sheet that is not our child!");
2098 if (mDocument
&& NS_SUCCEEDED(aStatus
)) {
2099 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
2101 // XXXldb @import rules shouldn't even implement nsIStyleRule (but
2103 mDocument
->StyleRuleAdded(this, aSheet
->GetOwnerRule());
2110 CSSStyleSheet::ParseSheet(const nsAString
& aInput
)
2112 // Not doing this if the sheet is not complete!
2113 if (!mInner
->mComplete
) {
2114 return NS_ERROR_DOM_INVALID_ACCESS_ERR
;
2117 // Hold strong ref to the CSSLoader in case the document update
2118 // kills the document
2119 nsRefPtr
<css::Loader
> loader
;
2121 loader
= mDocument
->CSSLoader();
2122 NS_ASSERTION(loader
, "Document with no CSS loader!");
2124 loader
= new css::Loader();
2127 mozAutoDocUpdate
updateBatch(mDocument
, UPDATE_STYLE
, true);
2131 // detach existing rules (including child sheets via import rules)
2133 while ((ruleCount
= mInner
->mOrderedRules
.Count()) != 0) {
2134 nsRefPtr
<css::Rule
> rule
= mInner
->mOrderedRules
.ObjectAt(ruleCount
- 1);
2135 mInner
->mOrderedRules
.RemoveObjectAt(ruleCount
- 1);
2136 rule
->SetStyleSheet(nullptr);
2138 mDocument
->StyleRuleRemoved(this, rule
);
2142 // nuke child sheets list and current namespace map
2143 for (CSSStyleSheet
* child
= mInner
->mFirstChild
; child
; child
= child
->mNext
) {
2144 NS_ASSERTION(child
->mParent
== this, "Child sheet is not parented to this!");
2145 child
->mParent
= nullptr;
2146 child
->mDocument
= nullptr;
2148 mInner
->mFirstChild
= nullptr;
2149 mInner
->mNameSpaceMap
= nullptr;
2151 // allow unsafe rules if the style sheet's principal is the system principal
2152 bool allowUnsafeRules
= nsContentUtils::IsSystemPrincipal(mInner
->mPrincipal
);
2154 nsCSSParser
parser(loader
, this);
2155 nsresult rv
= parser
.ParseSheet(aInput
, mInner
->mSheetURI
, mInner
->mBaseURI
,
2156 mInner
->mPrincipal
, 1, allowUnsafeRules
);
2157 DidDirty(); // we are always 'dirty' here since we always remove rules first
2158 NS_ENSURE_SUCCESS(rv
, rv
);
2160 // notify document of all new rules
2162 for (int32_t index
= 0; index
< mInner
->mOrderedRules
.Count(); ++index
) {
2163 nsRefPtr
<css::Rule
> rule
= mInner
->mOrderedRules
.ObjectAt(index
);
2164 if (rule
->GetType() == css::Rule::IMPORT_RULE
&&
2165 RuleHasPendingChildSheet(rule
)) {
2166 continue; // notify when loaded (see StyleSheetLoaded)
2168 mDocument
->StyleRuleAdded(this, rule
);
2174 /* virtual */ nsIURI
*
2175 CSSStyleSheet::GetOriginalURI() const
2177 return mInner
->mOriginalSheetURI
;
2182 CSSStyleSheet::WrapObject(JSContext
* aCx
)
2184 return CSSStyleSheetBinding::Wrap(aCx
, this);
2187 } // namespace mozilla