1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "mozilla/StyleSheet.h"
8 #include "mozilla/Assertions.h"
9 #include "mozilla/BasePrincipal.h"
10 #include "mozilla/ComputedStyleInlines.h"
11 #include "mozilla/css/ErrorReporter.h"
12 #include "mozilla/css/GroupRule.h"
13 #include "mozilla/dom/CSSImportRule.h"
14 #include "mozilla/dom/CSSRuleList.h"
15 #include "mozilla/dom/Element.h"
16 #include "mozilla/dom/MediaList.h"
17 #include "mozilla/dom/Promise.h"
18 #include "mozilla/dom/ShadowRoot.h"
19 #include "mozilla/dom/ShadowRootBinding.h"
20 #include "mozilla/NullPrincipal.h"
21 #include "mozilla/ServoBindings.h"
22 #include "mozilla/ServoCSSRuleList.h"
23 #include "mozilla/ServoStyleSet.h"
24 #include "mozilla/StaticPrefs_layout.h"
25 #include "mozilla/StyleSheetInlines.h"
26 #include "mozilla/css/SheetLoadData.h"
28 #include "mozAutoDocUpdate.h"
29 #include "SheetLoadData.h"
35 StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode
, CORSMode aCORSMode
,
36 const dom::SRIMetadata
& aIntegrity
)
37 : mParentSheet(nullptr),
38 mRelevantGlobal(nullptr),
39 mConstructorDocument(nullptr),
40 mDocumentOrShadowRoot(nullptr),
41 mParsingMode(aParsingMode
),
42 mState(static_cast<State
>(0)),
43 mInner(new StyleSheetInfo(aCORSMode
, aIntegrity
, aParsingMode
)) {
44 mInner
->AddSheet(this);
47 StyleSheet::StyleSheet(const StyleSheet
& aCopy
, StyleSheet
* aParentSheetToUse
,
48 dom::DocumentOrShadowRoot
* aDocOrShadowRootToUse
,
49 dom::Document
* aConstructorDocToUse
)
50 : mParentSheet(aParentSheetToUse
),
51 mRelevantGlobal(nullptr),
52 mConstructorDocument(aConstructorDocToUse
),
54 mDocumentOrShadowRoot(aDocOrShadowRootToUse
),
55 mParsingMode(aCopy
.mParsingMode
),
57 // Shallow copy, but concrete subclasses will fix up.
58 mInner(aCopy
.mInner
) {
59 MOZ_ASSERT(!aConstructorDocToUse
|| aCopy
.IsConstructed());
60 MOZ_ASSERT(!aConstructorDocToUse
|| !aDocOrShadowRootToUse
,
61 "Should never have both of these together.");
62 MOZ_ASSERT(mInner
, "Should only copy StyleSheets with an mInner.");
63 mInner
->AddSheet(this);
64 // CSSOM's been there, force full copy now.
65 if (HasForcedUniqueInner()) {
66 MOZ_ASSERT(IsComplete(),
67 "Why have rules been accessed on an incomplete sheet?");
69 // But CSSOM hasn't been on _this_ stylesheet yet, so no need to clone
71 mState
&= ~(State::ForcedUniqueInner
| State::ModifiedRules
|
72 State::ModifiedRulesForDevtools
);
76 // XXX This is wrong; we should be keeping @import rules and
78 mMedia
= aCopy
.mMedia
->Clone();
83 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-cssstylesheet
84 already_AddRefed
<StyleSheet
> StyleSheet::Constructor(
85 const dom::GlobalObject
& aGlobal
, const dom::CSSStyleSheetInit
& aOptions
,
87 nsCOMPtr
<nsPIDOMWindowInner
> window
=
88 do_QueryInterface(aGlobal
.GetAsSupports());
91 aRv
.ThrowNotSupportedError("Not supported when there is no document");
95 Document
* constructorDocument
= window
->GetExtantDoc();
96 if (!constructorDocument
) {
97 aRv
.ThrowNotSupportedError("Not supported when there is no document");
101 // 1. Construct a sheet and set its properties (see spec).
103 MakeRefPtr
<StyleSheet
>(css::SheetParsingMode::eAuthorSheetFeatures
,
104 CORSMode::CORS_NONE
, dom::SRIMetadata());
106 // baseURL not yet in the spec. Implemented based on the following discussion:
107 // https://github.com/WICG/construct-stylesheets/issues/95#issuecomment-594217180
108 RefPtr
<nsIURI
> baseURI
;
109 if (!aOptions
.mBaseURL
.WasPassed()) {
110 baseURI
= constructorDocument
->GetBaseURI();
112 nsresult rv
= NS_NewURI(getter_AddRefs(baseURI
), aOptions
.mBaseURL
.Value(),
113 nullptr, constructorDocument
->GetBaseURI());
115 aRv
.ThrowNotAllowedError(
116 "Constructed style sheets must have a valid base URL");
121 nsIURI
* sheetURI
= constructorDocument
->GetDocumentURI();
122 nsIURI
* originalURI
= nullptr;
123 sheet
->SetURIs(sheetURI
, originalURI
, baseURI
);
125 sheet
->SetPrincipal(constructorDocument
->NodePrincipal());
126 sheet
->SetReferrerInfo(constructorDocument
->GetReferrerInfo());
127 sheet
->mConstructorDocument
= constructorDocument
;
128 if (constructorDocument
) {
129 sheet
->mRelevantGlobal
= constructorDocument
->GetParentObject();
132 // 2. Set the sheet's media according to aOptions.
133 if (aOptions
.mMedia
.IsUTF8String()) {
134 sheet
->SetMedia(MediaList::Create(aOptions
.mMedia
.GetAsUTF8String()));
136 sheet
->SetMedia(aOptions
.mMedia
.GetAsMediaList()->Clone());
139 // 3. Set the sheet's disabled flag according to aOptions.
140 sheet
->SetDisabled(aOptions
.mDisabled
);
141 sheet
->SetComplete();
144 return sheet
.forget();
147 StyleSheet::~StyleSheet() {
148 MOZ_ASSERT(!mInner
, "Inner should have been dropped in LastRelease");
151 bool StyleSheet::HasRules() const {
152 return Servo_StyleSheet_HasRules(Inner().mContents
);
155 Document
* StyleSheet::GetAssociatedDocument() const {
156 auto* associated
= GetAssociatedDocumentOrShadowRoot();
157 return associated
? associated
->AsNode().OwnerDoc() : nullptr;
160 dom::DocumentOrShadowRoot
* StyleSheet::GetAssociatedDocumentOrShadowRoot()
162 const StyleSheet
& outer
= OutermostSheet();
163 if (outer
.mDocumentOrShadowRoot
) {
164 return outer
.mDocumentOrShadowRoot
;
166 if (outer
.IsConstructed()) {
167 return outer
.mConstructorDocument
;
172 Document
* StyleSheet::GetKeptAliveByDocument() const {
173 const StyleSheet
& outer
= OutermostSheet();
174 if (outer
.mDocumentOrShadowRoot
) {
175 return outer
.mDocumentOrShadowRoot
->AsNode().GetComposedDoc();
177 if (outer
.IsConstructed()) {
178 for (DocumentOrShadowRoot
* adopter
: outer
.mAdopters
) {
179 MOZ_ASSERT(adopter
->AsNode().OwnerDoc() == outer
.mConstructorDocument
);
180 if (adopter
->AsNode().IsInComposedDoc()) {
181 return outer
.mConstructorDocument
.get();
188 void StyleSheet::LastRelease() {
189 MOZ_DIAGNOSTIC_ASSERT(mAdopters
.IsEmpty(),
190 "Should have no adopters at time of destruction.");
193 MOZ_ASSERT(mInner
->mSheets
.Contains(this), "Our mInner should include us.");
194 mInner
->RemoveSheet(this);
202 void StyleSheet::UnlinkInner() {
207 // We can only have a cycle through our inner if we have a unique inner,
208 // because otherwise there are no JS wrappers for anything in the inner.
209 if (mInner
->mSheets
.Length() != 1) {
210 mInner
->RemoveSheet(this);
215 for (StyleSheet
* child
: ChildSheets()) {
216 MOZ_ASSERT(child
->mParentSheet
== this, "We have a unique inner!");
217 child
->mParentSheet
= nullptr;
219 Inner().mChildren
.Clear();
222 void StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback
& cb
) {
227 for (StyleSheet
* child
: ChildSheets()) {
228 if (child
->mParentSheet
== this) {
229 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "child sheet");
230 cb
.NoteXPCOMChild(child
);
235 // QueryInterface implementation for StyleSheet
236 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet
)
237 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
238 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
239 NS_INTERFACE_MAP_ENTRY(nsISupports
)
242 NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet
)
243 // We want to disconnect from our inner as soon as our refcount drops to zero,
244 // without waiting for async deletion by the cycle collector. Otherwise we
245 // might end up cloning the inner if someone mutates another sheet that shares
246 // it with us, even though there is only one such sheet and we're about to go
247 // away. This situation arises easily with sheet preloading.
248 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(StyleSheet
, LastRelease())
250 NS_IMPL_CYCLE_COLLECTION_CLASS(StyleSheet
)
252 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StyleSheet
)
253 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia
)
254 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleList
)
255 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelevantGlobal
)
256 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConstructorDocument
)
257 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReplacePromise
)
258 tmp
->TraverseInner(cb
);
259 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
261 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StyleSheet
)
265 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelevantGlobal
)
266 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructorDocument
)
267 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReplacePromise
)
268 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
269 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
271 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(StyleSheet
)
273 dom::CSSStyleSheetParsingMode
StyleSheet::ParsingModeDOM() {
274 #define CHECK_MODE(X, Y) \
276 static_cast<int>(X) == static_cast<int>(Y), \
277 "mozilla::dom::CSSStyleSheetParsingMode and " \
278 "mozilla::css::SheetParsingMode should have identical values");
280 CHECK_MODE(dom::CSSStyleSheetParsingMode::Agent
, css::eAgentSheetFeatures
);
281 CHECK_MODE(dom::CSSStyleSheetParsingMode::User
, css::eUserSheetFeatures
);
282 CHECK_MODE(dom::CSSStyleSheetParsingMode::Author
, css::eAuthorSheetFeatures
);
286 return static_cast<dom::CSSStyleSheetParsingMode
>(mParsingMode
);
289 void StyleSheet::SetComplete() {
290 // HasForcedUniqueInner() is okay if the sheet is constructed, because
291 // constructed sheets are always unique and they may be set to complete
292 // multiple times if their rules are replaced via Replace()
293 MOZ_ASSERT(IsConstructed() || !HasForcedUniqueInner(),
294 "Can't complete a sheet that's already been forced unique.");
295 MOZ_ASSERT(!IsComplete(), "Already complete?");
296 mState
|= State::Complete
;
298 ApplicableStateChanged(true);
300 MaybeResolveReplacePromise();
303 void StyleSheet::ApplicableStateChanged(bool aApplicable
) {
304 MOZ_ASSERT(aApplicable
== IsApplicable());
305 auto Notify
= [this](DocumentOrShadowRoot
& target
) {
306 nsINode
& node
= target
.AsNode();
307 if (ShadowRoot
* shadow
= ShadowRoot::FromNode(node
)) {
308 shadow
->StyleSheetApplicableStateChanged(*this);
310 node
.AsDocument()->StyleSheetApplicableStateChanged(*this);
314 const StyleSheet
& sheet
= OutermostSheet();
315 if (sheet
.mDocumentOrShadowRoot
) {
316 Notify(*sheet
.mDocumentOrShadowRoot
);
319 for (DocumentOrShadowRoot
* adopter
: sheet
.mAdopters
) {
320 MOZ_ASSERT(adopter
, "adopters should never be null");
325 void StyleSheet::SetDisabled(bool aDisabled
) {
330 if (aDisabled
== Disabled()) {
335 mState
|= State::Disabled
;
337 mState
&= ~State::Disabled
;
341 ApplicableStateChanged(!aDisabled
);
345 void StyleSheet::SetURLExtraData() {
347 new URLExtraData(GetBaseURI(), GetReferrerInfo(), Principal());
350 nsISupports
* StyleSheet::GetRelevantGlobal() const {
351 const StyleSheet
& outer
= OutermostSheet();
352 return outer
.mRelevantGlobal
;
355 StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode
,
356 const SRIMetadata
& aIntegrity
,
357 css::SheetParsingMode aParsingMode
)
358 : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes()),
359 mCORSMode(aCORSMode
),
360 mReferrerInfo(new ReferrerInfo(nullptr)),
361 mIntegrity(aIntegrity
),
362 mContents(Servo_StyleSheet_Empty(aParsingMode
).Consume()),
363 mURLData(URLExtraData::Dummy())
370 MOZ_CRASH("NullPrincipal::Init failed");
372 MOZ_COUNT_CTOR(StyleSheetInfo
);
375 StyleSheetInfo::StyleSheetInfo(StyleSheetInfo
& aCopy
, StyleSheet
* aPrimarySheet
)
376 : mSheetURI(aCopy
.mSheetURI
),
377 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
378 mBaseURI(aCopy
.mBaseURI
),
379 mPrincipal(aCopy
.mPrincipal
),
380 mCORSMode(aCopy
.mCORSMode
),
381 mReferrerInfo(aCopy
.mReferrerInfo
),
382 mIntegrity(aCopy
.mIntegrity
),
383 // We don't rebuild the child because we're making a copy without
385 mSourceMapURL(aCopy
.mSourceMapURL
),
386 mSourceMapURLFromComment(aCopy
.mSourceMapURLFromComment
),
387 mSourceURL(aCopy
.mSourceURL
),
388 mContents(Servo_StyleSheet_Clone(aCopy
.mContents
.get(), aPrimarySheet
)
390 mURLData(aCopy
.mURLData
)
393 mPrincipalSet(aCopy
.mPrincipalSet
)
396 AddSheet(aPrimarySheet
);
398 // Our child list is fixed up by our parent.
399 MOZ_COUNT_CTOR(StyleSheetInfo
);
402 StyleSheetInfo::~StyleSheetInfo() { MOZ_COUNT_DTOR(StyleSheetInfo
); }
404 StyleSheetInfo
* StyleSheetInfo::CloneFor(StyleSheet
* aPrimarySheet
) {
405 return new StyleSheetInfo(*this, aPrimarySheet
);
408 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSheetMallocSizeOf
)
409 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf
)
411 size_t StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
412 size_t n
= aMallocSizeOf(this);
414 n
+= Servo_StyleSheet_SizeOfIncludingThis(
415 ServoStyleSheetMallocSizeOf
, ServoStyleSheetMallocEnclosingSizeOf
,
421 void StyleSheetInfo::AddSheet(StyleSheet
* aSheet
) {
422 mSheets
.AppendElement(aSheet
);
425 void StyleSheetInfo::RemoveSheet(StyleSheet
* aSheet
) {
426 // Fix up the parent pointer in children lists.
427 StyleSheet
* newParent
=
428 aSheet
== mSheets
[0] ? mSheets
.SafeElementAt(1) : mSheets
[0];
429 for (StyleSheet
* child
: mChildren
) {
430 MOZ_ASSERT(child
->mParentSheet
);
431 MOZ_ASSERT(child
->mParentSheet
->mInner
== this);
432 if (child
->mParentSheet
== aSheet
) {
433 child
->mParentSheet
= newParent
;
437 if (1 == mSheets
.Length()) {
438 NS_ASSERTION(aSheet
== mSheets
.ElementAt(0), "bad parent");
443 mSheets
.RemoveElement(aSheet
);
446 void StyleSheet::GetType(nsAString
& aType
) { aType
.AssignLiteral("text/css"); }
448 void StyleSheet::GetHref(nsAString
& aHref
, ErrorResult
& aRv
) {
449 if (nsIURI
* sheetURI
= Inner().mOriginalSheetURI
) {
451 nsresult rv
= sheetURI
->GetSpec(str
);
456 CopyUTF8toUTF16(str
, aHref
);
458 SetDOMStringToNull(aHref
);
462 void StyleSheet::GetTitle(nsAString
& aTitle
) {
463 // From https://drafts.csswg.org/cssom/#dom-stylesheet-title:
465 // The title attribute must return the title or null if title is the empty
468 if (!mTitle
.IsEmpty()) {
469 aTitle
.Assign(mTitle
);
471 SetDOMStringToNull(aTitle
);
475 void StyleSheet::WillDirty() {
476 MOZ_ASSERT(!IsReadOnly());
483 void StyleSheet::AddStyleSet(ServoStyleSet
* aStyleSet
) {
484 MOZ_DIAGNOSTIC_ASSERT(!mStyleSets
.Contains(aStyleSet
),
485 "style set already registered");
486 mStyleSets
.AppendElement(aStyleSet
);
489 void StyleSheet::DropStyleSet(ServoStyleSet
* aStyleSet
) {
490 bool found
= mStyleSets
.RemoveElement(aStyleSet
);
491 MOZ_DIAGNOSTIC_ASSERT(found
, "didn't find style set");
492 #ifndef MOZ_DIAGNOSTIC_ASSERT_ENABLED
497 // NOTE(emilio): Composed doc and containing shadow root are set in child sheets
498 // too, so no need to do it for each ancestor.
499 #define NOTIFY(function_, args_) \
501 StyleSheet* current = this; \
503 for (ServoStyleSet * set : current->mStyleSets) { \
504 set->function_ args_; \
506 if (auto* docOrShadow = current->mDocumentOrShadowRoot) { \
507 if (auto* shadow = ShadowRoot::FromNode(docOrShadow->AsNode())) { \
508 shadow->function_ args_; \
510 docOrShadow->AsNode().AsDocument()->function_ args_; \
513 for (auto* adopter : mAdopters) { \
514 if (auto* shadow = ShadowRoot::FromNode(adopter->AsNode())) { \
515 shadow->function_ args_; \
517 adopter->AsNode().AsDocument()->function_ args_; \
520 current = current->mParentSheet; \
524 void StyleSheet::EnsureUniqueInner() {
525 MOZ_ASSERT(mInner
->mSheets
.Length() != 0, "unexpected number of outers");
528 // Sheets that can't be modified don't need a unique inner.
532 mState
|= State::ForcedUniqueInner
;
534 if (HasUniqueInner()) {
539 StyleSheetInfo
* clone
= mInner
->CloneFor(this);
542 mInner
->RemoveSheet(this);
545 // Fixup the child lists and parent links in the Servo sheet. This is done
546 // here instead of in StyleSheetInner::CloneFor, because it's just more
547 // convenient to do so instead.
548 FixUpAfterInnerClone();
550 // let our containing style sets know that if we call
551 // nsPresContext::EnsureSafeToHandOutCSSRules we will need to restyle the
553 NOTIFY(SheetCloned
, (*this));
556 // WebIDL CSSStyleSheet API
558 dom::CSSRuleList
* StyleSheet::GetCssRules(nsIPrincipal
& aSubjectPrincipal
,
560 if (!AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
563 return GetCssRulesInternal();
566 void StyleSheet::GetSourceMapURL(nsAString
& aSourceMapURL
) {
567 if (mInner
->mSourceMapURL
.IsEmpty()) {
568 aSourceMapURL
= mInner
->mSourceMapURLFromComment
;
570 aSourceMapURL
= mInner
->mSourceMapURL
;
574 void StyleSheet::SetSourceMapURL(const nsAString
& aSourceMapURL
) {
575 mInner
->mSourceMapURL
= aSourceMapURL
;
578 void StyleSheet::SetSourceMapURLFromComment(
579 const nsAString
& aSourceMapURLFromComment
) {
580 mInner
->mSourceMapURLFromComment
= aSourceMapURLFromComment
;
583 void StyleSheet::GetSourceURL(nsAString
& aSourceURL
) {
584 aSourceURL
= mInner
->mSourceURL
;
587 void StyleSheet::SetSourceURL(const nsAString
& aSourceURL
) {
588 mInner
->mSourceURL
= aSourceURL
;
591 css::Rule
* StyleSheet::GetDOMOwnerRule() const { return GetOwnerRule(); }
593 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule
594 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-insertrule
595 uint32_t StyleSheet::InsertRule(const nsACString
& aRule
, uint32_t aIndex
,
596 nsIPrincipal
& aSubjectPrincipal
,
598 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
602 if (ModificationDisallowed()) {
603 aRv
.ThrowNotAllowedError(
604 "This method can only be called on "
605 "modifiable style sheets");
609 return InsertRuleInternal(aRule
, aIndex
, aRv
);
612 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
613 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-deleterule
614 void StyleSheet::DeleteRule(uint32_t aIndex
, nsIPrincipal
& aSubjectPrincipal
,
616 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
620 if (ModificationDisallowed()) {
621 return aRv
.ThrowNotAllowedError(
622 "This method can only be called on "
623 "modifiable style sheets");
626 return DeleteRuleInternal(aIndex
, aRv
);
629 int32_t StyleSheet::AddRule(const nsACString
& aSelector
,
630 const nsACString
& aBlock
,
631 const Optional
<uint32_t>& aIndex
,
632 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
633 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
638 rule
.Append(aSelector
);
639 rule
.AppendLiteral(" { ");
640 if (!aBlock
.IsEmpty()) {
647 aIndex
.WasPassed() ? aIndex
.Value() : GetCssRulesInternal()->Length();
649 InsertRuleInternal(rule
, index
, aRv
);
654 void StyleSheet::MaybeResolveReplacePromise() {
655 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
656 if (!mReplacePromise
) {
660 SetModificationDisallowed(false);
661 mReplacePromise
->MaybeResolve(this);
662 mReplacePromise
= nullptr;
665 void StyleSheet::MaybeRejectReplacePromise() {
666 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
667 if (!mReplacePromise
) {
671 SetModificationDisallowed(false);
672 mReplacePromise
->MaybeRejectWithNetworkError(
673 "@import style sheet load failed");
674 mReplacePromise
= nullptr;
677 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replace
678 already_AddRefed
<dom::Promise
> StyleSheet::Replace(const nsACString
& aText
,
680 nsIGlobalObject
* globalObject
= nullptr;
681 const StyleSheet
& outer
= OutermostSheet();
682 if (outer
.mRelevantGlobal
) {
683 globalObject
= outer
.mRelevantGlobal
;
684 } else if (Document
* doc
= outer
.GetAssociatedDocument()) {
685 globalObject
= doc
->GetScopeObject();
688 RefPtr
<dom::Promise
> promise
= dom::Promise::Create(globalObject
, aRv
);
693 // Step 1 and 4 are variable declarations
695 // 2.1 Check if sheet is constructed, else reject promise.
696 if (!IsConstructed()) {
697 promise
->MaybeRejectWithNotAllowedError(
698 "This method can only be called on "
699 "constructed style sheets");
700 return promise
.forget();
703 // 2.2 Check if sheet is modifiable, else throw.
704 if (ModificationDisallowed()) {
705 promise
->MaybeRejectWithNotAllowedError(
706 "This method can only be called on "
707 "modifiable style sheets");
708 return promise
.forget();
711 // 3. Disallow modifications until finished.
712 SetModificationDisallowed(true);
714 // TODO(emilio, 1642227): Should constructable stylesheets notify global
715 // observers (i.e., set mMustNotify to true)?
716 auto* loader
= mConstructorDocument
->CSSLoader();
717 auto loadData
= MakeRefPtr
<css::SheetLoadData
>(
718 loader
, nullptr, this, /* aSyncLoad */ false,
719 css::Loader::UseSystemPrincipal::No
, css::StylePreloadKind::None
,
720 /* aPreloadEncoding */ nullptr,
721 /* aObserver */ nullptr, mConstructorDocument
->NodePrincipal(),
725 // 5.1 Parse aText into rules.
726 // 5.2 Load import rules, throw NetworkError if failed.
727 // 5.3 Set sheet's rules to new rules.
728 nsCOMPtr
<nsISerialEventTarget
> target
=
729 mConstructorDocument
->EventTargetFor(TaskCategory::Other
);
730 loadData
->mIsBeingParsed
= true;
731 MOZ_ASSERT(!mReplacePromise
);
732 mReplacePromise
= promise
;
733 ParseSheet(*loader
, aText
, *loadData
)
736 [loadData
] { loadData
->SheetFinishedParsingAsync(); },
737 [] { MOZ_CRASH("This MozPromise should never be rejected."); });
739 // 6. Return the promise
740 return promise
.forget();
743 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replacesync
744 void StyleSheet::ReplaceSync(const nsACString
& aText
, ErrorResult
& aRv
) {
745 // Step 1 is a variable declaration
747 // 2.1 Check if sheet is constructed, else throw.
748 if (!IsConstructed()) {
749 return aRv
.ThrowNotAllowedError(
750 "Can only be called on constructed style sheets");
753 // 2.2 Check if sheet is modifiable, else throw.
754 if (ModificationDisallowed()) {
755 return aRv
.ThrowNotAllowedError(
756 "Can only be called on modifiable style sheets");
759 // 3. Parse aText into rules.
760 // 4. If rules contain @imports, skip them and continue parsing.
761 auto* loader
= mConstructorDocument
->CSSLoader();
763 RefPtr
<const RawServoStyleSheetContents
> rawContent
=
764 Servo_StyleSheet_FromUTF8Bytes(
766 /* load_data = */ nullptr, &aText
, mParsingMode
, Inner().mURLData
,
767 /* line_number_offset = */ 0,
768 mConstructorDocument
->GetCompatibilityMode(),
769 /* reusable_sheets = */ nullptr,
770 mConstructorDocument
->GetStyleUseCounters(),
771 StyleAllowImportRules::No
, StyleSanitizationKind::None
,
772 /* sanitized_output = */ nullptr)
775 // 5. Set sheet's rules to the new rules.
777 Inner().mContents
= std::move(rawContent
);
779 RuleChanged(nullptr, StyleRuleChangeKind::Generic
);
782 nsresult
StyleSheet::DeleteRuleFromGroup(css::GroupRule
* aGroup
,
784 NS_ENSURE_ARG_POINTER(aGroup
);
785 NS_ASSERTION(IsComplete(), "No deleting from an incomplete sheet!");
786 RefPtr
<css::Rule
> rule
= aGroup
->GetStyleRuleAt(aIndex
);
787 NS_ENSURE_TRUE(rule
, NS_ERROR_ILLEGAL_VALUE
);
789 // check that the rule actually belongs to this sheet!
790 if (this != rule
->GetStyleSheet()) {
791 return NS_ERROR_INVALID_ARG
;
800 nsresult result
= aGroup
->DeleteStyleRuleAt(aIndex
);
801 NS_ENSURE_SUCCESS(result
, result
);
803 rule
->DropReferences();
809 void StyleSheet::RuleAdded(css::Rule
& aRule
) {
811 NOTIFY(RuleAdded
, (*this, aRule
));
814 void StyleSheet::RuleRemoved(css::Rule
& aRule
) {
816 NOTIFY(RuleRemoved
, (*this, aRule
));
819 void StyleSheet::RuleChanged(css::Rule
* aRule
, StyleRuleChangeKind aKind
) {
820 MOZ_ASSERT(!aRule
|| HasUniqueInner(),
821 "Shouldn't have mutated a shared sheet");
823 NOTIFY(RuleChanged
, (*this, aRule
, aKind
));
826 // nsICSSLoaderObserver implementation
828 StyleSheet::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
830 if (!aSheet
->GetParentSheet()) {
831 return NS_OK
; // ignore if sheet has been detached already
833 MOZ_ASSERT(this == aSheet
->GetParentSheet(),
834 "We are being notified of a sheet load for a sheet that is not "
836 if (NS_FAILED(aStatus
)) {
840 MOZ_ASSERT(aSheet
->GetOwnerRule());
841 NOTIFY(ImportRuleLoaded
, (*aSheet
->GetOwnerRule(), *aSheet
));
847 nsresult
StyleSheet::InsertRuleIntoGroup(const nsACString
& aRule
,
848 css::GroupRule
* aGroup
,
850 NS_ASSERTION(IsComplete(), "No inserting into an incomplete sheet!");
851 // check that the group actually belongs to this sheet!
852 if (this != aGroup
->GetStyleSheet()) {
853 return NS_ERROR_INVALID_ARG
;
860 if (ModificationDisallowed()) {
861 return NS_ERROR_DOM_NOT_ALLOWED_ERR
;
866 nsresult result
= InsertRuleIntoGroupInternal(aRule
, aGroup
, aIndex
);
867 NS_ENSURE_SUCCESS(result
, result
);
868 RuleAdded(*aGroup
->GetStyleRuleAt(aIndex
));
872 uint64_t StyleSheet::FindOwningWindowInnerID() const {
873 uint64_t windowID
= 0;
874 if (Document
* doc
= GetAssociatedDocument()) {
875 windowID
= doc
->InnerWindowID();
878 if (windowID
== 0 && mOwningNode
) {
879 windowID
= mOwningNode
->OwnerDoc()->InnerWindowID();
882 RefPtr
<css::Rule
> ownerRule
;
883 if (windowID
== 0 && (ownerRule
= GetDOMOwnerRule())) {
884 RefPtr
<StyleSheet
> sheet
= ownerRule
->GetStyleSheet();
886 windowID
= sheet
->FindOwningWindowInnerID();
890 if (windowID
== 0 && mParentSheet
) {
891 windowID
= mParentSheet
->FindOwningWindowInnerID();
897 void StyleSheet::RemoveFromParent() {
902 MOZ_ASSERT(mParentSheet
->ChildSheets().Contains(this));
903 mParentSheet
->Inner().mChildren
.RemoveElement(this);
904 mParentSheet
= nullptr;
907 void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal
& aSubjectPrincipal
,
909 StyleSheetInfo
& info
= Inner();
911 if (aSubjectPrincipal
.Subsumes(info
.mPrincipal
)) {
915 // Allow access only if CORS mode is not NONE and the security flag
916 // is not turned off.
917 if (GetCORSMode() == CORS_NONE
&& !nsContentUtils::BypassCSSOMOriginCheck()) {
918 aRv
.ThrowSecurityError("Not allowed to access cross-origin stylesheet");
922 // Now make sure we set the principal of our inner to the subjectPrincipal.
923 // We do this because we're in a situation where the caller would not normally
924 // be able to access the sheet, but the sheet has opted in to being read.
925 // Unfortunately, that means it's also opted in to being _edited_, and if the
926 // caller now makes edits to the sheet we want the resulting resource loads,
927 // if any, to look as if they are coming from the caller's principal, not the
928 // original sheet principal.
930 // That means we need a unique inner, of course. But we don't want to do that
931 // if we're not complete yet. Luckily, all the callers of this method throw
932 // anyway if not complete, so we can just do that here too.
934 aRv
.ThrowInvalidAccessError(
935 "Not allowed to access still-loading stylesheet");
941 info
.mPrincipal
= &aSubjectPrincipal
;
944 bool StyleSheet::AreRulesAvailable(nsIPrincipal
& aSubjectPrincipal
,
946 // Rules are not available on incomplete sheets.
948 aRv
.ThrowInvalidAccessError(
949 "Can't access rules of still-loading style sheet");
952 //-- Security check: Only scripts whose principal subsumes that of the
953 // style sheet can access rule collections.
954 SubjectSubsumesInnerPrincipal(aSubjectPrincipal
, aRv
);
955 if (NS_WARN_IF(aRv
.Failed())) {
961 void StyleSheet::SetAssociatedDocumentOrShadowRoot(
962 DocumentOrShadowRoot
* aDocOrShadowRoot
) {
963 MOZ_ASSERT(!IsConstructed());
964 MOZ_ASSERT(!mParentSheet
|| !aDocOrShadowRoot
,
965 "Shouldn't be set on child sheets");
968 mDocumentOrShadowRoot
= aDocOrShadowRoot
;
970 if (Document
* doc
= GetAssociatedDocument()) {
971 MOZ_ASSERT(!mRelevantGlobal
);
972 mRelevantGlobal
= doc
->GetScopeObject();
976 void StyleSheet::AppendStyleSheet(StyleSheet
& aSheet
) {
978 AppendStyleSheetSilently(aSheet
);
981 void StyleSheet::AppendStyleSheetSilently(StyleSheet
& aSheet
) {
982 MOZ_ASSERT(!IsReadOnly());
984 Inner().mChildren
.AppendElement(&aSheet
);
986 // This is not reference counted. Our parent tells us when
988 aSheet
.mParentSheet
= this;
991 size_t StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
993 n
+= aMallocSizeOf(this);
995 // We want to measure the inner with only one of the children, and it makes
996 // sense for it to be the latest as it is the most likely to be reachable.
997 if (Inner().mSheets
.LastElement() == this) {
998 n
+= Inner().SizeOfIncludingThis(aMallocSizeOf
);
1001 // Measurement of the following members may be added later if DMD finds it
1011 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
1012 void StyleSheet::List(FILE* aOut
, int32_t aIndent
) {
1013 for (StyleSheet
* child
: ChildSheets()) {
1014 child
->List(aOut
, aIndent
);
1018 for (int i
= 0; i
< aIndent
; ++i
) {
1019 line
.AppendLiteral(" ");
1022 line
.AppendLiteral("/* ");
1025 GetSheetURI()->GetSpec(url
);
1026 if (url
.IsEmpty()) {
1027 line
.AppendLiteral("(no URL)");
1032 line
.AppendLiteral(" (");
1034 switch (GetOrigin()) {
1035 case StyleOrigin::UserAgent
:
1036 line
.AppendLiteral("User Agent");
1038 case StyleOrigin::User
:
1039 line
.AppendLiteral("User");
1041 case StyleOrigin::Author
:
1042 line
.AppendLiteral("Author");
1047 nsAutoCString buffer
;
1048 mMedia
->GetText(buffer
);
1050 if (!buffer
.IsEmpty()) {
1051 line
.AppendLiteral(", ");
1052 line
.Append(buffer
);
1056 line
.AppendLiteral(") */");
1058 fprintf_stderr(aOut
, "%s\n\n", line
.get());
1060 nsCString newlineIndent
;
1061 newlineIndent
.Append('\n');
1062 for (int i
= 0; i
< aIndent
; ++i
) {
1063 newlineIndent
.AppendLiteral(" ");
1066 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1067 for (uint32_t i
= 0, len
= ruleList
->Length(); i
< len
; ++i
) {
1068 css::Rule
* rule
= ruleList
->GetRule(i
);
1070 nsAutoCString cssText
;
1071 rule
->GetCssText(cssText
);
1072 cssText
.ReplaceSubstring("\n"_ns
, newlineIndent
);
1073 fprintf_stderr(aOut
, "%s\n", cssText
.get());
1076 if (ruleList
->Length() != 0) {
1077 fprintf_stderr(aOut
, "\n");
1082 void StyleSheet::SetMedia(already_AddRefed
<dom::MediaList
> aMedia
) {
1085 mMedia
->SetStyleSheet(this);
1089 void StyleSheet::DropMedia() {
1091 mMedia
->SetStyleSheet(nullptr);
1096 dom::MediaList
* StyleSheet::Media() {
1098 mMedia
= dom::MediaList::Create(EmptyCString());
1099 mMedia
->SetStyleSheet(this);
1107 JSObject
* StyleSheet::WrapObject(JSContext
* aCx
,
1108 JS::Handle
<JSObject
*> aGivenProto
) {
1109 return dom::CSSStyleSheet_Binding::Wrap(aCx
, this, aGivenProto
);
1112 void StyleSheet::FixUpAfterInnerClone() {
1113 MOZ_ASSERT(Inner().mSheets
.Length() == 1, "Should've just cloned");
1114 MOZ_ASSERT(Inner().mSheets
[0] == this);
1115 MOZ_ASSERT(Inner().mChildren
.IsEmpty());
1117 auto* contents
= Inner().mContents
.get();
1118 RefPtr
<ServoCssRules
> rules
= Servo_StyleSheet_GetRules(contents
).Consume();
1121 mRuleList
->SetRawAfterClone(rules
);
1126 uint32_t line
, column
; // Actually unused.
1127 RefPtr
<RawServoImportRule
> import
=
1128 Servo_CssRules_GetImportRuleAt(rules
, index
, &line
, &column
).Consume();
1130 // Note that only @charset rules come before @import rules, and @charset
1131 // rules are parsed but skipped, so we can stop iterating as soon as we
1132 // find something that isn't an @import rule.
1135 auto* sheet
= const_cast<StyleSheet
*>(Servo_ImportRule_GetSheet(import
));
1137 AppendStyleSheetSilently(*sheet
);
1142 already_AddRefed
<StyleSheet
> StyleSheet::CreateEmptyChildSheet(
1143 already_AddRefed
<dom::MediaList
> aMediaList
) const {
1144 RefPtr
<StyleSheet
> child
=
1145 new StyleSheet(ParsingMode(), CORSMode::CORS_NONE
, SRIMetadata());
1147 child
->mMedia
= aMediaList
;
1148 return child
.forget();
1151 // We disable parallel stylesheet parsing if any of the following three
1154 // (1) The pref is off.
1155 // (2) The browser is recording CSS errors (which parallel parsing can't
1157 // (3) The stylesheet is a chrome stylesheet, since those can use
1158 // -moz-bool-pref, which needs to access the pref service, which is not
1160 static bool AllowParallelParse(css::Loader
& aLoader
, URLExtraData
* aUrlData
) {
1161 // If the browser is recording CSS errors, we need to use the sequential path
1162 // because the parallel path doesn't support that.
1163 Document
* doc
= aLoader
.GetDocument();
1164 if (doc
&& css::ErrorReporter::ShouldReportErrors(*doc
)) {
1168 // If this is a chrome stylesheet, it might use -moz-bool-pref, which needs to
1169 // access the pref service, which is not thread-safe. We could probably expose
1170 // the relevant booleans as thread-safe var caches if we needed to, but
1171 // parsing chrome stylesheets in parallel is unlikely to be a win anyway.
1173 // Note that UA stylesheets can also use -moz-bool-pref, but those are always
1175 if (aUrlData
->ChromeRulesEnabled()) {
1182 RefPtr
<StyleSheetParsePromise
> StyleSheet::ParseSheet(
1183 css::Loader
& aLoader
, const nsACString
& aBytes
,
1184 css::SheetLoadData
& aLoadData
) {
1185 MOZ_ASSERT(mParsePromise
.IsEmpty());
1186 RefPtr
<StyleSheetParsePromise
> p
= mParsePromise
.Ensure(__func__
);
1189 // @import rules are disallowed due to this decision:
1190 // https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418
1191 // We may allow @import rules again in the future.
1192 auto allowImportRules
= SelfOrAncestorIsConstructed()
1193 ? StyleAllowImportRules::No
1194 : StyleAllowImportRules::Yes
;
1195 const bool shouldRecordCounters
=
1196 aLoader
.GetDocument() && aLoader
.GetDocument()->GetStyleUseCounters();
1197 if (!AllowParallelParse(aLoader
, Inner().mURLData
)) {
1198 UniquePtr
<StyleUseCounters
> counters
=
1199 shouldRecordCounters
? Servo_UseCounters_Create().Consume() : nullptr;
1201 RefPtr
<RawServoStyleSheetContents
> contents
=
1202 Servo_StyleSheet_FromUTF8Bytes(
1203 &aLoader
, this, &aLoadData
, &aBytes
, mParsingMode
, Inner().mURLData
,
1204 aLoadData
.mLineNumber
, aLoadData
.mCompatMode
,
1205 /* reusable_sheets = */ nullptr, counters
.get(), allowImportRules
,
1206 StyleSanitizationKind::None
,
1207 /* sanitized_output = */ nullptr)
1209 FinishAsyncParse(contents
.forget(), std::move(counters
));
1211 auto holder
= MakeRefPtr
<css::SheetLoadDataHolder
>(__func__
, &aLoadData
);
1212 Servo_StyleSheet_FromUTF8BytesAsync(
1213 holder
, Inner().mURLData
, &aBytes
, mParsingMode
, aLoadData
.mLineNumber
,
1214 aLoadData
.mCompatMode
, shouldRecordCounters
, allowImportRules
);
1220 void StyleSheet::FinishAsyncParse(
1221 already_AddRefed
<RawServoStyleSheetContents
> aSheetContents
,
1222 UniquePtr
<StyleUseCounters
> aUseCounters
) {
1223 MOZ_ASSERT(NS_IsMainThread());
1224 MOZ_ASSERT(!mParsePromise
.IsEmpty());
1225 Inner().mContents
= aSheetContents
;
1226 Inner().mUseCounters
= std::move(aUseCounters
);
1228 mParsePromise
.Resolve(true, __func__
);
1231 void StyleSheet::ParseSheetSync(
1232 css::Loader
* aLoader
, const nsACString
& aBytes
,
1233 css::SheetLoadData
* aLoadData
, uint32_t aLineNumber
,
1234 css::LoaderReusableStyleSheets
* aReusableSheets
) {
1235 const nsCompatibility compatMode
= [&] {
1237 return aLoadData
->mCompatMode
;
1240 return aLoader
->CompatMode(css::StylePreloadKind::None
);
1242 return eCompatibility_FullStandards
;
1245 const StyleUseCounters
* useCounters
=
1246 aLoader
&& aLoader
->GetDocument()
1247 ? aLoader
->GetDocument()->GetStyleUseCounters()
1250 auto allowImportRules
= SelfOrAncestorIsConstructed()
1251 ? StyleAllowImportRules::No
1252 : StyleAllowImportRules::Yes
;
1256 Servo_StyleSheet_FromUTF8Bytes(
1257 aLoader
, this, aLoadData
, &aBytes
, mParsingMode
, Inner().mURLData
,
1258 aLineNumber
, compatMode
, aReusableSheets
, useCounters
,
1259 allowImportRules
, StyleSanitizationKind::None
,
1260 /* sanitized_output = */ nullptr)
1266 void StyleSheet::FinishParse() {
1267 nsString sourceMapURL
;
1268 Servo_StyleSheet_GetSourceMapURL(Inner().mContents
, &sourceMapURL
);
1269 SetSourceMapURLFromComment(sourceMapURL
);
1272 Servo_StyleSheet_GetSourceURL(Inner().mContents
, &sourceURL
);
1273 SetSourceURL(sourceURL
);
1276 void StyleSheet::ReparseSheet(const nsACString
& aInput
, ErrorResult
& aRv
) {
1277 if (!IsComplete()) {
1278 return aRv
.ThrowInvalidAccessError("Cannot reparse still-loading sheet");
1281 // Allowing to modify UA sheets is dangerous (in the sense that C++ code
1282 // relies on rules in those sheets), plus they're probably going to be shared
1283 // across processes in which case this is directly a no-go.
1288 // Hold strong ref to the CSSLoader in case the document update
1289 // kills the document
1290 RefPtr
<css::Loader
> loader
;
1291 if (Document
* doc
= GetAssociatedDocument()) {
1292 loader
= doc
->CSSLoader();
1293 NS_ASSERTION(loader
, "Document with no CSS loader!");
1295 loader
= new css::Loader
;
1300 // cache child sheets to reuse
1301 css::LoaderReusableStyleSheets reusableSheets
;
1302 for (StyleSheet
* child
: ChildSheets()) {
1303 if (child
->GetOriginalURI()) {
1304 reusableSheets
.AddReusableSheet(child
);
1308 // Clean up child sheets list.
1309 for (StyleSheet
* child
: ChildSheets()) {
1310 child
->mParentSheet
= nullptr;
1312 Inner().mChildren
.Clear();
1314 uint32_t lineNumber
= 1;
1315 if (auto* linkStyle
= LinkStyle::FromNodeOrNull(mOwningNode
)) {
1316 lineNumber
= linkStyle
->GetLineNumber();
1319 // Notify to the stylesets about the old rules going away.
1321 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1322 MOZ_ASSERT(ruleList
);
1324 uint32_t ruleCount
= ruleList
->Length();
1325 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1326 css::Rule
* rule
= ruleList
->GetRule(i
);
1334 ParseSheetSync(loader
, aInput
, /* aLoadData = */ nullptr, lineNumber
,
1337 // Notify the stylesets about the new rules.
1339 // Get the rule list (which will need to be regenerated after ParseSheet).
1340 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1341 MOZ_ASSERT(ruleList
);
1343 uint32_t ruleCount
= ruleList
->Length();
1344 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1345 css::Rule
* rule
= ruleList
->GetRule(i
);
1351 // Our rules are no longer considered modified for devtools.
1352 mState
&= ~State::ModifiedRulesForDevtools
;
1355 void StyleSheet::DropRuleList() {
1357 mRuleList
->DropReferences();
1358 mRuleList
= nullptr;
1362 already_AddRefed
<StyleSheet
> StyleSheet::Clone(
1363 StyleSheet
* aCloneParent
,
1364 dom::DocumentOrShadowRoot
* aCloneDocumentOrShadowRoot
) const {
1365 MOZ_ASSERT(!IsConstructed(),
1366 "Cannot create a non-constructed sheet from a constructed sheet");
1367 RefPtr
<StyleSheet
> clone
=
1368 new StyleSheet(*this, aCloneParent
, aCloneDocumentOrShadowRoot
,
1369 /* aConstructorDocToUse */ nullptr);
1370 return clone
.forget();
1373 already_AddRefed
<StyleSheet
> StyleSheet::CloneAdoptedSheet(
1374 Document
& aConstructorDocument
) const {
1375 MOZ_ASSERT(IsConstructed(),
1376 "Cannot create a constructed sheet from a non-constructed sheet");
1377 MOZ_ASSERT(aConstructorDocument
.IsStaticDocument(),
1378 "Should never clone adopted sheets for a non-static document");
1379 RefPtr
<StyleSheet
> clone
= new StyleSheet(*this,
1380 /* aParentSheetToUse */ nullptr,
1381 /* aDocOrShadowRootToUse */ nullptr,
1382 &aConstructorDocument
);
1383 return clone
.forget();
1386 ServoCSSRuleList
* StyleSheet::GetCssRulesInternal() {
1388 // TODO(emilio): This should go away, but we need to fix the CC setup for
1389 // @import rules first, see bug 1719963.
1390 EnsureUniqueInner();
1392 RefPtr
<ServoCssRules
> rawRules
=
1393 Servo_StyleSheet_GetRules(Inner().mContents
).Consume();
1394 MOZ_ASSERT(rawRules
);
1395 mRuleList
= new ServoCSSRuleList(rawRules
.forget(), this, nullptr);
1400 uint32_t StyleSheet::InsertRuleInternal(const nsACString
& aRule
,
1401 uint32_t aIndex
, ErrorResult
& aRv
) {
1402 MOZ_ASSERT(!IsReadOnly());
1403 MOZ_ASSERT(!ModificationDisallowed());
1405 // Ensure mRuleList is constructed.
1406 GetCssRulesInternal();
1408 aRv
= mRuleList
->InsertRule(aRule
, aIndex
);
1413 // XXX We may not want to get the rule when stylesheet change event
1415 css::Rule
* rule
= mRuleList
->GetRule(aIndex
);
1421 void StyleSheet::DeleteRuleInternal(uint32_t aIndex
, ErrorResult
& aRv
) {
1422 MOZ_ASSERT(!IsReadOnly());
1423 MOZ_ASSERT(!ModificationDisallowed());
1425 // Ensure mRuleList is constructed.
1426 GetCssRulesInternal();
1427 if (aIndex
>= mRuleList
->Length()) {
1428 aRv
.ThrowIndexSizeError(
1429 nsPrintfCString("Cannot delete rule at index %u"
1430 " because the number of rules is only %u",
1431 aIndex
, mRuleList
->Length()));
1435 // Hold a strong ref to the rule so it doesn't die when we remove it
1436 // from the list. XXX We may not want to hold it if stylesheet change
1437 // event is not enabled.
1438 RefPtr
<css::Rule
> rule
= mRuleList
->GetRule(aIndex
);
1439 aRv
= mRuleList
->DeleteRule(aIndex
);
1440 if (!aRv
.Failed()) {
1445 nsresult
StyleSheet::InsertRuleIntoGroupInternal(const nsACString
& aRule
,
1446 css::GroupRule
* aGroup
,
1448 MOZ_ASSERT(!IsReadOnly());
1450 ServoCSSRuleList
* rules
= aGroup
->GetCssRules();
1451 MOZ_ASSERT(rules
&& rules
->GetParentRule() == aGroup
);
1452 return rules
->InsertRule(aRule
, aIndex
);
1455 StyleOrigin
StyleSheet::GetOrigin() const {
1456 return Servo_StyleSheet_GetOrigin(Inner().mContents
);
1459 void StyleSheet::SetSharedContents(const ServoCssRules
* aSharedRules
) {
1460 MOZ_ASSERT(!IsComplete());
1465 Servo_StyleSheet_FromSharedData(Inner().mURLData
, aSharedRules
).Consume();
1467 // Don't call FinishParse(), since that tries to set source map URLs,
1468 // which we don't have.
1471 const ServoCssRules
* StyleSheet::ToShared(RawServoSharedMemoryBuilder
* aBuilder
,
1472 nsCString
& aErrorMessage
) {
1473 // Assert some things we assume when creating a StyleSheet using shared
1475 MOZ_ASSERT(GetReferrerInfo()->ReferrerPolicy() == ReferrerPolicy::_empty
);
1476 MOZ_ASSERT(GetReferrerInfo()->GetSendReferrer());
1477 MOZ_ASSERT(!nsCOMPtr
<nsIURI
>(GetReferrerInfo()->GetComputedReferrer()));
1478 MOZ_ASSERT(GetCORSMode() == CORS_NONE
);
1479 MOZ_ASSERT(Inner().mIntegrity
.IsEmpty());
1480 MOZ_ASSERT(Principal()->IsSystemPrincipal());
1482 const ServoCssRules
* rules
= Servo_SharedMemoryBuilder_AddStylesheet(
1483 aBuilder
, Inner().mContents
, &aErrorMessage
);
1487 // Print the ToShmem error message so that developers know what to fix.
1488 printf_stderr("%s\n", aErrorMessage
.get());
1489 MOZ_CRASH("UA style sheet contents failed shared memory requirements");
1496 bool StyleSheet::IsReadOnly() const {
1497 return IsComplete() && GetOrigin() == StyleOrigin::UserAgent
;
1500 } // namespace mozilla