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/FetchPriority.h"
17 #include "mozilla/dom/MediaList.h"
18 #include "mozilla/dom/Promise.h"
19 #include "mozilla/dom/ReferrerInfo.h"
20 #include "mozilla/dom/ShadowRoot.h"
21 #include "mozilla/dom/ShadowRootBinding.h"
22 #include "mozilla/NullPrincipal.h"
23 #include "mozilla/ServoBindings.h"
24 #include "mozilla/ServoCSSRuleList.h"
25 #include "mozilla/ServoStyleSet.h"
26 #include "mozilla/StaticPrefs_layout.h"
27 #include "mozilla/StyleSheetInlines.h"
28 #include "mozilla/css/SheetLoadData.h"
30 #include "mozAutoDocUpdate.h"
31 #include "SheetLoadData.h"
37 StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode
, CORSMode aCORSMode
,
38 const dom::SRIMetadata
& aIntegrity
)
39 : mParentSheet(nullptr),
40 mConstructorDocument(nullptr),
41 mDocumentOrShadowRoot(nullptr),
42 mParsingMode(aParsingMode
),
43 mState(static_cast<State
>(0)),
44 mInner(new StyleSheetInfo(aCORSMode
, aIntegrity
, aParsingMode
)) {
45 mInner
->AddSheet(this);
48 StyleSheet::StyleSheet(const StyleSheet
& aCopy
, StyleSheet
* aParentSheetToUse
,
49 dom::DocumentOrShadowRoot
* aDocOrShadowRootToUse
,
50 dom::Document
* aConstructorDocToUse
)
51 : mParentSheet(aParentSheetToUse
),
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 auto referrerInfo
= MakeRefPtr
<ReferrerInfo
>(*constructorDocument
);
127 sheet
->SetReferrerInfo(referrerInfo
);
128 sheet
->mConstructorDocument
= constructorDocument
;
130 // 2. Set the sheet's media according to aOptions.
131 if (aOptions
.mMedia
.IsUTF8String()) {
132 sheet
->SetMedia(MediaList::Create(aOptions
.mMedia
.GetAsUTF8String()));
134 sheet
->SetMedia(aOptions
.mMedia
.GetAsMediaList()->Clone());
137 // 3. Set the sheet's disabled flag according to aOptions.
138 sheet
->SetDisabled(aOptions
.mDisabled
);
139 sheet
->SetComplete();
142 return sheet
.forget();
145 StyleSheet::~StyleSheet() {
146 MOZ_ASSERT(!mInner
, "Inner should have been dropped in LastRelease");
149 bool StyleSheet::HasRules() const {
150 return Servo_StyleSheet_HasRules(Inner().mContents
);
153 Document
* StyleSheet::GetAssociatedDocument() const {
154 auto* associated
= GetAssociatedDocumentOrShadowRoot();
155 return associated
? associated
->AsNode().OwnerDoc() : nullptr;
158 dom::DocumentOrShadowRoot
* StyleSheet::GetAssociatedDocumentOrShadowRoot()
160 const StyleSheet
& outer
= OutermostSheet();
161 if (outer
.mDocumentOrShadowRoot
) {
162 return outer
.mDocumentOrShadowRoot
;
164 if (outer
.IsConstructed()) {
165 return outer
.mConstructorDocument
;
170 void StyleSheet::UpdateRelevantGlobal() {
171 if (mRelevantGlobal
|| !IsComplete()) {
174 if (Document
* doc
= GetAssociatedDocument()) {
175 mRelevantGlobal
= doc
->GetScopeObject();
179 Document
* StyleSheet::GetKeptAliveByDocument() const {
180 const StyleSheet
& outer
= OutermostSheet();
181 if (outer
.mDocumentOrShadowRoot
) {
182 return outer
.mDocumentOrShadowRoot
->AsNode().GetComposedDoc();
184 if (outer
.IsConstructed()) {
185 for (DocumentOrShadowRoot
* adopter
: outer
.mAdopters
) {
186 MOZ_ASSERT(adopter
->AsNode().OwnerDoc() == outer
.mConstructorDocument
);
187 if (adopter
->AsNode().IsInComposedDoc()) {
188 return outer
.mConstructorDocument
.get();
195 void StyleSheet::LastRelease() {
196 MOZ_DIAGNOSTIC_ASSERT(mAdopters
.IsEmpty(),
197 "Should have no adopters at time of destruction.");
200 MOZ_ASSERT(mInner
->mSheets
.Contains(this), "Our mInner should include us.");
201 mInner
->RemoveSheet(this);
209 void StyleSheet::UnlinkInner() {
214 // We can only have a cycle through our inner if we have a unique inner,
215 // because otherwise there are no JS wrappers for anything in the inner.
216 if (mInner
->mSheets
.Length() != 1) {
217 mInner
->RemoveSheet(this);
222 for (StyleSheet
* child
: ChildSheets()) {
223 MOZ_ASSERT(child
->mParentSheet
== this, "We have a unique inner!");
224 child
->mParentSheet
= nullptr;
226 Inner().mChildren
.Clear();
229 void StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback
& cb
) {
234 for (StyleSheet
* child
: ChildSheets()) {
235 if (child
->mParentSheet
== this) {
236 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "child sheet");
237 cb
.NoteXPCOMChild(child
);
242 // QueryInterface implementation for StyleSheet
243 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet
)
244 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
245 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
246 NS_INTERFACE_MAP_ENTRY(nsISupports
)
249 NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet
)
250 // We want to disconnect from our inner as soon as our refcount drops to zero,
251 // without waiting for async deletion by the cycle collector. Otherwise we
252 // might end up cloning the inner if someone mutates another sheet that shares
253 // it with us, even though there is only one such sheet and we're about to go
254 // away. This situation arises easily with sheet preloading.
255 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(StyleSheet
, LastRelease())
257 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(StyleSheet
)
259 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StyleSheet
)
260 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia
)
261 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleList
)
262 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelevantGlobal
)
263 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConstructorDocument
)
264 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReplacePromise
)
265 tmp
->TraverseInner(cb
);
266 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
268 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StyleSheet
)
272 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelevantGlobal
)
273 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructorDocument
)
274 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReplacePromise
)
275 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
276 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
278 dom::CSSStyleSheetParsingMode
StyleSheet::ParsingModeDOM() {
279 #define CHECK_MODE(X, Y) \
281 static_cast<int>(X) == static_cast<int>(Y), \
282 "mozilla::dom::CSSStyleSheetParsingMode and " \
283 "mozilla::css::SheetParsingMode should have identical values");
285 CHECK_MODE(dom::CSSStyleSheetParsingMode::Agent
, css::eAgentSheetFeatures
);
286 CHECK_MODE(dom::CSSStyleSheetParsingMode::User
, css::eUserSheetFeatures
);
287 CHECK_MODE(dom::CSSStyleSheetParsingMode::Author
, css::eAuthorSheetFeatures
);
291 return static_cast<dom::CSSStyleSheetParsingMode
>(mParsingMode
);
294 void StyleSheet::SetComplete() {
295 // HasForcedUniqueInner() is okay if the sheet is constructed, because
296 // constructed sheets are always unique and they may be set to complete
297 // multiple times if their rules are replaced via Replace()
298 MOZ_ASSERT(IsConstructed() || !HasForcedUniqueInner(),
299 "Can't complete a sheet that's already been forced unique.");
300 MOZ_ASSERT(!IsComplete(), "Already complete?");
301 mState
|= State::Complete
;
303 UpdateRelevantGlobal();
306 ApplicableStateChanged(true);
308 MaybeResolveReplacePromise();
311 void StyleSheet::ApplicableStateChanged(bool aApplicable
) {
312 MOZ_ASSERT(aApplicable
== IsApplicable());
313 Document
* docToPostEvent
= nullptr;
314 auto Notify
= [&](DocumentOrShadowRoot
& target
) {
315 nsINode
& node
= target
.AsNode();
316 if (ShadowRoot
* shadow
= ShadowRoot::FromNode(node
)) {
317 shadow
->StyleSheetApplicableStateChanged(*this);
318 MOZ_ASSERT(!docToPostEvent
|| !shadow
->IsInComposedDoc() ||
319 docToPostEvent
== shadow
->GetComposedDoc());
320 if (!docToPostEvent
) {
321 docToPostEvent
= shadow
->GetComposedDoc();
324 Document
* doc
= node
.AsDocument();
325 MOZ_ASSERT(!docToPostEvent
|| docToPostEvent
== doc
);
326 doc
->StyleSheetApplicableStateChanged(*this);
327 docToPostEvent
= doc
;
331 const StyleSheet
& sheet
= OutermostSheet();
332 if (sheet
.mDocumentOrShadowRoot
) {
333 Notify(*sheet
.mDocumentOrShadowRoot
);
336 if (sheet
.mConstructorDocument
) {
337 Notify(*sheet
.mConstructorDocument
);
340 for (DocumentOrShadowRoot
* adopter
: sheet
.mAdopters
) {
341 MOZ_ASSERT(adopter
, "adopters should never be null");
342 if (adopter
!= sheet
.mConstructorDocument
) {
347 if (docToPostEvent
) {
348 docToPostEvent
->PostStyleSheetApplicableStateChangeEvent(*this);
352 void StyleSheet::SetDisabled(bool aDisabled
) {
357 if (aDisabled
== Disabled()) {
362 mState
|= State::Disabled
;
364 mState
&= ~State::Disabled
;
368 ApplicableStateChanged(!aDisabled
);
372 void StyleSheet::SetURLExtraData() {
374 new URLExtraData(GetBaseURI(), GetReferrerInfo(), Principal());
377 nsISupports
* StyleSheet::GetRelevantGlobal() const {
378 const StyleSheet
& outer
= OutermostSheet();
379 return outer
.mRelevantGlobal
;
382 StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode
,
383 const SRIMetadata
& aIntegrity
,
384 css::SheetParsingMode aParsingMode
)
385 : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes()),
386 mCORSMode(aCORSMode
),
387 mReferrerInfo(new ReferrerInfo(nullptr)),
388 mIntegrity(aIntegrity
),
389 mContents(Servo_StyleSheet_Empty(aParsingMode
).Consume()),
390 mURLData(URLExtraData::Dummy()) {
392 MOZ_CRASH("NullPrincipal::Init failed");
394 MOZ_COUNT_CTOR(StyleSheetInfo
);
397 StyleSheetInfo::StyleSheetInfo(StyleSheetInfo
& aCopy
, StyleSheet
* aPrimarySheet
)
398 : mSheetURI(aCopy
.mSheetURI
),
399 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
400 mBaseURI(aCopy
.mBaseURI
),
401 mPrincipal(aCopy
.mPrincipal
),
402 mCORSMode(aCopy
.mCORSMode
),
403 mReferrerInfo(aCopy
.mReferrerInfo
),
404 mIntegrity(aCopy
.mIntegrity
),
405 // We don't rebuild the child because we're making a copy without
407 mSourceMapURL(aCopy
.mSourceMapURL
),
408 mContents(Servo_StyleSheet_Clone(aCopy
.mContents
.get(), aPrimarySheet
)
410 mURLData(aCopy
.mURLData
)
413 mPrincipalSet(aCopy
.mPrincipalSet
)
416 AddSheet(aPrimarySheet
);
418 // Our child list is fixed up by our parent.
419 MOZ_COUNT_CTOR(StyleSheetInfo
);
422 StyleSheetInfo::~StyleSheetInfo() { MOZ_COUNT_DTOR(StyleSheetInfo
); }
424 StyleSheetInfo
* StyleSheetInfo::CloneFor(StyleSheet
* aPrimarySheet
) {
425 return new StyleSheetInfo(*this, aPrimarySheet
);
428 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSheetMallocSizeOf
)
429 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf
)
431 size_t StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
432 size_t n
= aMallocSizeOf(this);
434 n
+= Servo_StyleSheet_SizeOfIncludingThis(
435 ServoStyleSheetMallocSizeOf
, ServoStyleSheetMallocEnclosingSizeOf
,
441 void StyleSheetInfo::AddSheet(StyleSheet
* aSheet
) {
442 mSheets
.AppendElement(aSheet
);
445 void StyleSheetInfo::RemoveSheet(StyleSheet
* aSheet
) {
446 // Fix up the parent pointer in children lists.
447 StyleSheet
* newParent
=
448 aSheet
== mSheets
[0] ? mSheets
.SafeElementAt(1) : mSheets
[0];
449 for (StyleSheet
* child
: mChildren
) {
450 MOZ_ASSERT(child
->mParentSheet
);
451 MOZ_ASSERT(child
->mParentSheet
->mInner
== this);
452 if (child
->mParentSheet
== aSheet
) {
453 child
->mParentSheet
= newParent
;
457 if (1 == mSheets
.Length()) {
458 NS_ASSERTION(aSheet
== mSheets
.ElementAt(0), "bad parent");
463 mSheets
.RemoveElement(aSheet
);
466 void StyleSheet::GetType(nsAString
& aType
) { aType
.AssignLiteral("text/css"); }
468 void StyleSheet::GetHref(nsAString
& aHref
, ErrorResult
& aRv
) {
469 if (nsIURI
* sheetURI
= Inner().mOriginalSheetURI
) {
471 nsresult rv
= sheetURI
->GetSpec(str
);
476 CopyUTF8toUTF16(str
, aHref
);
478 SetDOMStringToNull(aHref
);
482 void StyleSheet::GetTitle(nsAString
& aTitle
) {
483 // From https://drafts.csswg.org/cssom/#dom-stylesheet-title:
485 // The title attribute must return the title or null if title is the empty
488 if (!mTitle
.IsEmpty()) {
489 aTitle
.Assign(mTitle
);
491 SetDOMStringToNull(aTitle
);
495 void StyleSheet::WillDirty() {
496 MOZ_ASSERT(!IsReadOnly());
503 void StyleSheet::AddStyleSet(ServoStyleSet
* aStyleSet
) {
504 MOZ_DIAGNOSTIC_ASSERT(!mStyleSets
.Contains(aStyleSet
),
505 "style set already registered");
506 mStyleSets
.AppendElement(aStyleSet
);
509 void StyleSheet::DropStyleSet(ServoStyleSet
* aStyleSet
) {
510 bool found
= mStyleSets
.RemoveElement(aStyleSet
);
511 MOZ_DIAGNOSTIC_ASSERT(found
, "didn't find style set");
512 #ifndef MOZ_DIAGNOSTIC_ASSERT_ENABLED
517 // NOTE(emilio): Composed doc and containing shadow root are set in child sheets
518 // too, so no need to do it for each ancestor.
519 #define NOTIFY(function_, args_) \
521 StyleSheet* current = this; \
523 for (ServoStyleSet * set : current->mStyleSets) { \
524 set->function_ args_; \
526 if (auto* docOrShadow = current->mDocumentOrShadowRoot) { \
527 if (auto* shadow = ShadowRoot::FromNode(docOrShadow->AsNode())) { \
528 shadow->function_ args_; \
530 docOrShadow->AsNode().AsDocument()->function_ args_; \
533 for (auto* adopter : mAdopters) { \
534 if (auto* shadow = ShadowRoot::FromNode(adopter->AsNode())) { \
535 shadow->function_ args_; \
537 adopter->AsNode().AsDocument()->function_ args_; \
540 current = current->mParentSheet; \
544 void StyleSheet::EnsureUniqueInner() {
545 MOZ_ASSERT(mInner
->mSheets
.Length() != 0, "unexpected number of outers");
548 // Sheets that can't be modified don't need a unique inner.
552 mState
|= State::ForcedUniqueInner
;
554 if (HasUniqueInner()) {
559 StyleSheetInfo
* clone
= mInner
->CloneFor(this);
562 mInner
->RemoveSheet(this);
565 // Fixup the child lists and parent links in the Servo sheet. This is done
566 // here instead of in StyleSheetInner::CloneFor, because it's just more
567 // convenient to do so instead.
568 FixUpAfterInnerClone();
570 // let our containing style sets know that if we call
571 // nsPresContext::EnsureSafeToHandOutCSSRules we will need to restyle the
573 NOTIFY(SheetCloned
, (*this));
576 // WebIDL CSSStyleSheet API
578 dom::CSSRuleList
* StyleSheet::GetCssRules(nsIPrincipal
& aSubjectPrincipal
,
580 if (!AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
583 return GetCssRulesInternal();
586 void StyleSheet::GetSourceMapURL(nsACString
& aSourceMapURL
) {
587 if (!mInner
->mSourceMapURL
.IsEmpty()) {
588 aSourceMapURL
= mInner
->mSourceMapURL
;
591 Servo_StyleSheet_GetSourceMapURL(mInner
->mContents
, &aSourceMapURL
);
594 void StyleSheet::SetSourceMapURL(nsCString
&& aSourceMapURL
) {
595 mInner
->mSourceMapURL
= std::move(aSourceMapURL
);
598 void StyleSheet::GetSourceURL(nsACString
& aSourceURL
) {
599 Servo_StyleSheet_GetSourceURL(mInner
->mContents
, &aSourceURL
);
602 css::Rule
* StyleSheet::GetDOMOwnerRule() const { return GetOwnerRule(); }
604 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule
605 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-insertrule
606 uint32_t StyleSheet::InsertRule(const nsACString
& aRule
, uint32_t aIndex
,
607 nsIPrincipal
& aSubjectPrincipal
,
609 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
613 if (ModificationDisallowed()) {
614 aRv
.ThrowNotAllowedError(
615 "This method can only be called on "
616 "modifiable style sheets");
620 return InsertRuleInternal(aRule
, aIndex
, aRv
);
623 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
624 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-deleterule
625 void StyleSheet::DeleteRule(uint32_t aIndex
, nsIPrincipal
& aSubjectPrincipal
,
627 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
631 if (ModificationDisallowed()) {
632 return aRv
.ThrowNotAllowedError(
633 "This method can only be called on "
634 "modifiable style sheets");
637 return DeleteRuleInternal(aIndex
, aRv
);
640 int32_t StyleSheet::AddRule(const nsACString
& aSelector
,
641 const nsACString
& aBlock
,
642 const Optional
<uint32_t>& aIndex
,
643 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
644 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
649 rule
.Append(aSelector
);
650 rule
.AppendLiteral(" { ");
651 if (!aBlock
.IsEmpty()) {
658 aIndex
.WasPassed() ? aIndex
.Value() : GetCssRulesInternal()->Length();
660 InsertRuleInternal(rule
, index
, aRv
);
665 void StyleSheet::MaybeResolveReplacePromise() {
666 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
667 if (!mReplacePromise
) {
671 SetModificationDisallowed(false);
672 mReplacePromise
->MaybeResolve(this);
673 mReplacePromise
= nullptr;
676 void StyleSheet::MaybeRejectReplacePromise() {
677 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
678 if (!mReplacePromise
) {
682 SetModificationDisallowed(false);
683 mReplacePromise
->MaybeRejectWithNetworkError(
684 "@import style sheet load failed");
685 mReplacePromise
= nullptr;
688 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace
689 already_AddRefed
<dom::Promise
> StyleSheet::Replace(const nsACString
& aText
,
691 nsIGlobalObject
* globalObject
= nullptr;
692 const StyleSheet
& outer
= OutermostSheet();
693 if (outer
.mRelevantGlobal
) {
694 globalObject
= outer
.mRelevantGlobal
;
695 } else if (Document
* doc
= outer
.GetAssociatedDocument()) {
696 globalObject
= doc
->GetScopeObject();
699 RefPtr
<dom::Promise
> promise
= dom::Promise::Create(globalObject
, aRv
);
704 // Step 1 and 4 are variable declarations
706 // 2.1 Check if sheet is constructed, else reject promise.
707 if (!IsConstructed()) {
708 promise
->MaybeRejectWithNotAllowedError(
709 "This method can only be called on "
710 "constructed style sheets");
711 return promise
.forget();
714 // 2.2 Check if sheet is modifiable, else throw.
715 if (ModificationDisallowed()) {
716 promise
->MaybeRejectWithNotAllowedError(
717 "This method can only be called on "
718 "modifiable style sheets");
719 return promise
.forget();
722 // 3. Disallow modifications until finished.
723 SetModificationDisallowed(true);
725 // TODO(emilio, 1642227): Should constructable stylesheets notify global
726 // observers (i.e., set mMustNotify to true)?
727 auto* loader
= mConstructorDocument
->CSSLoader();
728 auto loadData
= MakeRefPtr
<css::SheetLoadData
>(
729 loader
, /* aURI = */ nullptr, this, css::SyncLoad::No
,
730 css::Loader::UseSystemPrincipal::No
, css::StylePreloadKind::None
,
731 /* aPreloadEncoding */ nullptr, /* aObserver */ nullptr,
732 mConstructorDocument
->NodePrincipal(), GetReferrerInfo(),
733 /* aNonce */ u
""_ns
, FetchPriority::Auto
);
736 // 5.1 Parse aText into rules.
737 // 5.2 Load import rules, throw NetworkError if failed.
738 // 5.3 Set sheet's rules to new rules.
739 nsISerialEventTarget
* target
= GetMainThreadSerialEventTarget();
740 loadData
->mIsBeingParsed
= true;
741 MOZ_ASSERT(!mReplacePromise
);
742 mReplacePromise
= promise
;
743 ParseSheet(*loader
, aText
, *loadData
)
746 [loadData
] { loadData
->SheetFinishedParsingAsync(); },
747 [] { MOZ_CRASH("This MozPromise should never be rejected."); });
749 // 6. Return the promise
750 return promise
.forget();
753 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replacesync
754 void StyleSheet::ReplaceSync(const nsACString
& aText
, ErrorResult
& aRv
) {
755 // Step 1 is a variable declaration
757 // 2.1 Check if sheet is constructed, else throw.
758 if (!IsConstructed()) {
759 return aRv
.ThrowNotAllowedError(
760 "Can only be called on constructed style sheets");
763 // 2.2 Check if sheet is modifiable, else throw.
764 if (ModificationDisallowed()) {
765 return aRv
.ThrowNotAllowedError(
766 "Can only be called on modifiable style sheets");
769 // 3. Parse aText into rules.
770 // 4. If rules contain @imports, skip them and continue parsing.
771 auto* loader
= mConstructorDocument
->CSSLoader();
773 RefPtr
<const StyleStylesheetContents
> rawContent
=
774 Servo_StyleSheet_FromUTF8Bytes(
776 /* load_data = */ nullptr, &aText
, mParsingMode
, URLData(),
777 mConstructorDocument
->GetCompatibilityMode(),
778 /* reusable_sheets = */ nullptr,
779 mConstructorDocument
->GetStyleUseCounters(),
780 StyleAllowImportRules::No
, StyleSanitizationKind::None
,
781 /* sanitized_output = */ nullptr)
784 // 5. Set sheet's rules to the new rules.
785 Inner().mContents
= std::move(rawContent
);
786 FixUpRuleListAfterContentsChangeIfNeeded();
787 RuleChanged(nullptr, StyleRuleChangeKind::Generic
);
790 nsresult
StyleSheet::DeleteRuleFromGroup(css::GroupRule
* aGroup
,
792 NS_ENSURE_ARG_POINTER(aGroup
);
793 NS_ASSERTION(IsComplete(), "No deleting from an incomplete sheet!");
794 RefPtr
<css::Rule
> rule
= aGroup
->GetStyleRuleAt(aIndex
);
795 NS_ENSURE_TRUE(rule
, NS_ERROR_ILLEGAL_VALUE
);
797 // check that the rule actually belongs to this sheet!
798 if (this != rule
->GetStyleSheet()) {
799 return NS_ERROR_INVALID_ARG
;
808 nsresult result
= aGroup
->DeleteStyleRuleAt(aIndex
);
809 NS_ENSURE_SUCCESS(result
, result
);
811 rule
->DropReferences();
817 void StyleSheet::RuleAdded(css::Rule
& aRule
) {
819 NOTIFY(RuleAdded
, (*this, aRule
));
822 void StyleSheet::RuleRemoved(css::Rule
& aRule
) {
824 NOTIFY(RuleRemoved
, (*this, aRule
));
827 void StyleSheet::RuleChanged(css::Rule
* aRule
, StyleRuleChangeKind aKind
) {
828 MOZ_ASSERT(!aRule
|| HasUniqueInner(),
829 "Shouldn't have mutated a shared sheet");
831 NOTIFY(RuleChanged
, (*this, aRule
, aKind
));
834 // nsICSSLoaderObserver implementation
836 StyleSheet::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
838 if (!aSheet
->GetParentSheet()) {
839 return NS_OK
; // ignore if sheet has been detached already
841 MOZ_ASSERT(this == aSheet
->GetParentSheet(),
842 "We are being notified of a sheet load for a sheet that is not "
844 if (NS_FAILED(aStatus
)) {
848 MOZ_ASSERT(aSheet
->GetOwnerRule());
849 NOTIFY(ImportRuleLoaded
, (*aSheet
->GetOwnerRule(), *aSheet
));
855 nsresult
StyleSheet::InsertRuleIntoGroup(const nsACString
& aRule
,
856 css::GroupRule
* aGroup
,
858 NS_ASSERTION(IsComplete(), "No inserting into an incomplete sheet!");
859 // check that the group actually belongs to this sheet!
860 if (this != aGroup
->GetStyleSheet()) {
861 return NS_ERROR_INVALID_ARG
;
868 if (ModificationDisallowed()) {
869 return NS_ERROR_DOM_NOT_ALLOWED_ERR
;
874 nsresult result
= InsertRuleIntoGroupInternal(aRule
, aGroup
, aIndex
);
875 NS_ENSURE_SUCCESS(result
, result
);
876 RuleAdded(*aGroup
->GetStyleRuleAt(aIndex
));
880 uint64_t StyleSheet::FindOwningWindowInnerID() const {
881 uint64_t windowID
= 0;
882 if (Document
* doc
= GetAssociatedDocument()) {
883 windowID
= doc
->InnerWindowID();
886 if (windowID
== 0 && mOwningNode
) {
887 windowID
= mOwningNode
->OwnerDoc()->InnerWindowID();
890 RefPtr
<css::Rule
> ownerRule
;
891 if (windowID
== 0 && (ownerRule
= GetDOMOwnerRule())) {
892 RefPtr
<StyleSheet
> sheet
= ownerRule
->GetStyleSheet();
894 windowID
= sheet
->FindOwningWindowInnerID();
898 if (windowID
== 0 && mParentSheet
) {
899 windowID
= mParentSheet
->FindOwningWindowInnerID();
905 void StyleSheet::RemoveFromParent() {
910 MOZ_ASSERT(mParentSheet
->ChildSheets().Contains(this));
911 mParentSheet
->Inner().mChildren
.RemoveElement(this);
912 mParentSheet
= nullptr;
915 void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal
& aSubjectPrincipal
,
917 StyleSheetInfo
& info
= Inner();
919 if (aSubjectPrincipal
.Subsumes(info
.mPrincipal
)) {
923 // Allow access only if CORS mode is not NONE and the security flag
924 // is not turned off.
925 if (GetCORSMode() == CORS_NONE
&& !nsContentUtils::BypassCSSOMOriginCheck()) {
926 aRv
.ThrowSecurityError("Not allowed to access cross-origin stylesheet");
930 // Now make sure we set the principal of our inner to the subjectPrincipal.
931 // We do this because we're in a situation where the caller would not normally
932 // be able to access the sheet, but the sheet has opted in to being read.
933 // Unfortunately, that means it's also opted in to being _edited_, and if the
934 // caller now makes edits to the sheet we want the resulting resource loads,
935 // if any, to look as if they are coming from the caller's principal, not the
936 // original sheet principal.
938 // That means we need a unique inner, of course. But we don't want to do that
939 // if we're not complete yet. Luckily, all the callers of this method throw
940 // anyway if not complete, so we can just do that here too.
942 aRv
.ThrowInvalidAccessError(
943 "Not allowed to access still-loading stylesheet");
949 info
.mPrincipal
= &aSubjectPrincipal
;
952 bool StyleSheet::AreRulesAvailable(nsIPrincipal
& aSubjectPrincipal
,
954 // Rules are not available on incomplete sheets.
956 aRv
.ThrowInvalidAccessError(
957 "Can't access rules of still-loading style sheet");
960 //-- Security check: Only scripts whose principal subsumes that of the
961 // style sheet can access rule collections.
962 SubjectSubsumesInnerPrincipal(aSubjectPrincipal
, aRv
);
963 if (NS_WARN_IF(aRv
.Failed())) {
969 void StyleSheet::SetAssociatedDocumentOrShadowRoot(
970 DocumentOrShadowRoot
* aDocOrShadowRoot
) {
971 MOZ_ASSERT(!IsConstructed());
972 MOZ_ASSERT(!mParentSheet
|| !aDocOrShadowRoot
,
973 "Shouldn't be set on child sheets");
976 mDocumentOrShadowRoot
= aDocOrShadowRoot
;
977 UpdateRelevantGlobal();
980 void StyleSheet::AppendStyleSheet(StyleSheet
& aSheet
) {
982 AppendStyleSheetSilently(aSheet
);
985 void StyleSheet::AppendStyleSheetSilently(StyleSheet
& aSheet
) {
986 MOZ_ASSERT(!IsReadOnly());
988 Inner().mChildren
.AppendElement(&aSheet
);
990 // This is not reference counted. Our parent tells us when
992 aSheet
.mParentSheet
= this;
995 size_t StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
997 n
+= aMallocSizeOf(this);
999 // We want to measure the inner with only one of the children, and it makes
1000 // sense for it to be the latest as it is the most likely to be reachable.
1001 if (Inner().mSheets
.LastElement() == this) {
1002 n
+= Inner().SizeOfIncludingThis(aMallocSizeOf
);
1005 // Measurement of the following members may be added later if DMD finds it
1015 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
1016 void StyleSheet::List(FILE* aOut
, int32_t aIndent
) {
1017 for (StyleSheet
* child
: ChildSheets()) {
1018 child
->List(aOut
, aIndent
);
1022 for (int i
= 0; i
< aIndent
; ++i
) {
1023 line
.AppendLiteral(" ");
1026 line
.AppendLiteral("/* ");
1029 GetSheetURI()->GetSpec(url
);
1030 if (url
.IsEmpty()) {
1031 line
.AppendLiteral("(no URL)");
1036 line
.AppendLiteral(" (");
1038 switch (GetOrigin()) {
1039 case StyleOrigin::UserAgent
:
1040 line
.AppendLiteral("User Agent");
1042 case StyleOrigin::User
:
1043 line
.AppendLiteral("User");
1045 case StyleOrigin::Author
:
1046 line
.AppendLiteral("Author");
1051 nsAutoCString buffer
;
1052 mMedia
->GetText(buffer
);
1054 if (!buffer
.IsEmpty()) {
1055 line
.AppendLiteral(", ");
1056 line
.Append(buffer
);
1060 line
.AppendLiteral(") */");
1062 fprintf_stderr(aOut
, "%s\n\n", line
.get());
1064 nsCString newlineIndent
;
1065 newlineIndent
.Append('\n');
1066 for (int i
= 0; i
< aIndent
; ++i
) {
1067 newlineIndent
.AppendLiteral(" ");
1070 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1071 for (uint32_t i
= 0, len
= ruleList
->Length(); i
< len
; ++i
) {
1072 css::Rule
* rule
= ruleList
->GetRule(i
);
1074 nsAutoCString cssText
;
1075 rule
->GetCssText(cssText
);
1076 cssText
.ReplaceSubstring("\n"_ns
, newlineIndent
);
1077 fprintf_stderr(aOut
, "%s\n", cssText
.get());
1080 if (ruleList
->Length() != 0) {
1081 fprintf_stderr(aOut
, "\n");
1086 void StyleSheet::SetMedia(already_AddRefed
<dom::MediaList
> aMedia
) {
1089 mMedia
->SetStyleSheet(this);
1093 void StyleSheet::DropMedia() {
1095 mMedia
->SetStyleSheet(nullptr);
1100 dom::MediaList
* StyleSheet::Media() {
1102 mMedia
= dom::MediaList::Create(EmptyCString());
1103 mMedia
->SetStyleSheet(this);
1111 JSObject
* StyleSheet::WrapObject(JSContext
* aCx
,
1112 JS::Handle
<JSObject
*> aGivenProto
) {
1113 return dom::CSSStyleSheet_Binding::Wrap(aCx
, this, aGivenProto
);
1116 void StyleSheet::FixUpRuleListAfterContentsChangeIfNeeded(bool aFromClone
) {
1121 RefPtr
<StyleLockedCssRules
> rules
=
1122 Servo_StyleSheet_GetRules(Inner().mContents
.get()).Consume();
1123 mRuleList
->SetRawContents(std::move(rules
), aFromClone
);
1126 void StyleSheet::FixUpAfterInnerClone() {
1127 MOZ_ASSERT(Inner().mSheets
.Length() == 1, "Should've just cloned");
1128 MOZ_ASSERT(Inner().mSheets
[0] == this);
1129 MOZ_ASSERT(Inner().mChildren
.IsEmpty());
1131 FixUpRuleListAfterContentsChangeIfNeeded(/* aFromClone = */ true);
1133 RefPtr
<StyleLockedCssRules
> rules
=
1134 Servo_StyleSheet_GetRules(Inner().mContents
.get()).Consume();
1137 uint32_t line
, column
; // Actually unused.
1138 RefPtr
<StyleLockedImportRule
> import
=
1139 Servo_CssRules_GetImportRuleAt(rules
, index
, &line
, &column
).Consume();
1141 // Note that only @charset rules come before @import rules, and @charset
1142 // rules are parsed but skipped, so we can stop iterating as soon as we
1143 // find something that isn't an @import rule.
1146 auto* sheet
= const_cast<StyleSheet
*>(Servo_ImportRule_GetSheet(import
));
1148 AppendStyleSheetSilently(*sheet
);
1153 already_AddRefed
<StyleSheet
> StyleSheet::CreateEmptyChildSheet(
1154 already_AddRefed
<dom::MediaList
> aMediaList
) const {
1155 RefPtr
<StyleSheet
> child
=
1156 new StyleSheet(ParsingMode(), CORSMode::CORS_NONE
, SRIMetadata());
1158 child
->mMedia
= aMediaList
;
1159 return child
.forget();
1162 // We disable parallel stylesheet parsing if the browser is recording CSS errors
1163 // (which parallel parsing can't handle).
1164 static bool AllowParallelParse(css::Loader
& aLoader
, URLExtraData
* aUrlData
) {
1165 Document
* doc
= aLoader
.GetDocument();
1166 if (doc
&& css::ErrorReporter::ShouldReportErrors(*doc
)) {
1169 // Otherwise we can parse in parallel.
1173 RefPtr
<StyleSheetParsePromise
> StyleSheet::ParseSheet(
1174 css::Loader
& aLoader
, const nsACString
& aBytes
,
1175 css::SheetLoadData
& aLoadData
) {
1176 MOZ_ASSERT(mParsePromise
.IsEmpty());
1177 RefPtr
<StyleSheetParsePromise
> p
= mParsePromise
.Ensure(__func__
);
1178 if (!aLoadData
.ShouldDefer()) {
1179 mParsePromise
.SetTaskPriority(nsIRunnablePriority::PRIORITY_RENDER_BLOCKING
,
1184 // @import rules are disallowed due to this decision:
1185 // https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418
1186 // We may allow @import rules again in the future.
1187 auto allowImportRules
= SelfOrAncestorIsConstructed()
1188 ? StyleAllowImportRules::No
1189 : StyleAllowImportRules::Yes
;
1190 URLExtraData
* urlData
= URLData();
1191 const bool shouldRecordCounters
=
1192 aLoader
.GetDocument() && aLoader
.GetDocument()->GetStyleUseCounters() &&
1193 !urlData
->ChromeRulesEnabled();
1194 if (!AllowParallelParse(aLoader
, urlData
)) {
1195 UniquePtr
<StyleUseCounters
> counters
;
1196 if (shouldRecordCounters
) {
1197 counters
.reset(Servo_UseCounters_Create());
1200 RefPtr
<StyleStylesheetContents
> contents
=
1201 Servo_StyleSheet_FromUTF8Bytes(
1202 &aLoader
, this, &aLoadData
, &aBytes
, mParsingMode
, urlData
,
1203 aLoadData
.mCompatMode
,
1204 /* reusable_sheets = */ nullptr, counters
.get(), allowImportRules
,
1205 StyleSanitizationKind::None
,
1206 /* sanitized_output = */ nullptr)
1208 FinishAsyncParse(contents
.forget(), std::move(counters
));
1210 auto holder
= MakeRefPtr
<css::SheetLoadDataHolder
>(__func__
, &aLoadData
);
1211 Servo_StyleSheet_FromUTF8BytesAsync(holder
, urlData
, &aBytes
, mParsingMode
,
1212 aLoadData
.mCompatMode
,
1213 shouldRecordCounters
, allowImportRules
);
1219 void StyleSheet::FinishAsyncParse(
1220 already_AddRefed
<StyleStylesheetContents
> aSheetContents
,
1221 UniquePtr
<StyleUseCounters
> aUseCounters
) {
1222 MOZ_ASSERT(NS_IsMainThread());
1223 MOZ_ASSERT(!mParsePromise
.IsEmpty());
1224 Inner().mContents
= aSheetContents
;
1225 Inner().mUseCounters
= std::move(aUseCounters
);
1226 FixUpRuleListAfterContentsChangeIfNeeded();
1227 mParsePromise
.Resolve(true, __func__
);
1230 void StyleSheet::ParseSheetSync(
1231 css::Loader
* aLoader
, const nsACString
& aBytes
,
1232 css::SheetLoadData
* aLoadData
,
1233 css::LoaderReusableStyleSheets
* aReusableSheets
) {
1234 const nsCompatibility compatMode
= [&] {
1236 return aLoadData
->mCompatMode
;
1239 return aLoader
->CompatMode(css::StylePreloadKind::None
);
1241 return eCompatibility_FullStandards
;
1246 URLExtraData
* urlData
= URLData();
1247 const StyleUseCounters
* useCounters
=
1248 aLoader
&& aLoader
->GetDocument() && !urlData
->ChromeRulesEnabled()
1249 ? aLoader
->GetDocument()->GetStyleUseCounters()
1252 auto allowImportRules
= SelfOrAncestorIsConstructed()
1253 ? StyleAllowImportRules::No
1254 : StyleAllowImportRules::Yes
;
1256 Inner().mContents
= Servo_StyleSheet_FromUTF8Bytes(
1257 aLoader
, this, aLoadData
, &aBytes
, mParsingMode
,
1258 urlData
, compatMode
, aReusableSheets
, useCounters
,
1259 allowImportRules
, StyleSanitizationKind::None
,
1260 /* sanitized_output = */ nullptr)
1264 void StyleSheet::ReparseSheet(const nsACString
& aInput
, ErrorResult
& aRv
) {
1265 if (!IsComplete()) {
1266 return aRv
.ThrowInvalidAccessError("Cannot reparse still-loading sheet");
1269 // Allowing to modify UA sheets is dangerous (in the sense that C++ code
1270 // relies on rules in those sheets), plus they're probably going to be shared
1271 // across processes in which case this is directly a no-go.
1276 // Hold strong ref to the CSSLoader in case the document update
1277 // kills the document
1278 RefPtr
<css::Loader
> loader
;
1279 if (Document
* doc
= GetAssociatedDocument()) {
1280 loader
= doc
->CSSLoader();
1281 NS_ASSERTION(loader
, "Document with no CSS loader!");
1283 loader
= new css::Loader
;
1288 // cache child sheets to reuse
1289 css::LoaderReusableStyleSheets reusableSheets
;
1290 for (StyleSheet
* child
: ChildSheets()) {
1291 if (child
->GetOriginalURI()) {
1292 reusableSheets
.AddReusableSheet(child
);
1296 // Clean up child sheets list.
1297 for (StyleSheet
* child
: ChildSheets()) {
1298 child
->mParentSheet
= nullptr;
1300 Inner().mChildren
.Clear();
1302 // Notify to the stylesets about the old rules going away.
1304 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1305 MOZ_ASSERT(ruleList
);
1307 uint32_t ruleCount
= ruleList
->Length();
1308 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1309 css::Rule
* rule
= ruleList
->GetRule(i
);
1314 // We need to clear the rule list here (rather than after parsing) because
1315 // ParseSheetSync may reuse child sheets, which would cause us to end up
1316 // with a wrong mChilden array.
1317 ruleList
->SetRawContents(nullptr, /* aFromClone = */ false);
1320 ParseSheetSync(loader
, aInput
, /* aLoadData = */ nullptr, &reusableSheets
);
1322 FixUpRuleListAfterContentsChangeIfNeeded();
1324 // Notify the stylesets about the new rules.
1326 // Get the rule list (which will need to be regenerated after ParseSheet).
1327 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1328 MOZ_ASSERT(ruleList
);
1330 uint32_t ruleCount
= ruleList
->Length();
1331 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1332 css::Rule
* rule
= ruleList
->GetRule(i
);
1338 // Our rules are no longer considered modified for devtools.
1339 mState
&= ~State::ModifiedRulesForDevtools
;
1342 void StyleSheet::DropRuleList() {
1344 mRuleList
->DropReferences();
1345 mRuleList
= nullptr;
1349 already_AddRefed
<StyleSheet
> StyleSheet::Clone(
1350 StyleSheet
* aCloneParent
,
1351 dom::DocumentOrShadowRoot
* aCloneDocumentOrShadowRoot
) const {
1352 MOZ_ASSERT(!IsConstructed(),
1353 "Cannot create a non-constructed sheet from a constructed sheet");
1354 RefPtr
<StyleSheet
> clone
=
1355 new StyleSheet(*this, aCloneParent
, aCloneDocumentOrShadowRoot
,
1356 /* aConstructorDocToUse */ nullptr);
1357 return clone
.forget();
1360 already_AddRefed
<StyleSheet
> StyleSheet::CloneAdoptedSheet(
1361 Document
& aConstructorDocument
) const {
1362 MOZ_ASSERT(IsConstructed(),
1363 "Cannot create a constructed sheet from a non-constructed sheet");
1364 MOZ_ASSERT(aConstructorDocument
.IsStaticDocument(),
1365 "Should never clone adopted sheets for a non-static document");
1366 RefPtr
<StyleSheet
> clone
= new StyleSheet(*this,
1367 /* aParentSheetToUse */ nullptr,
1368 /* aDocOrShadowRootToUse */ nullptr,
1369 &aConstructorDocument
);
1370 return clone
.forget();
1373 ServoCSSRuleList
* StyleSheet::GetCssRulesInternal() {
1375 // TODO(emilio): This should go away, but we need to fix the CC setup for
1376 // @import rules first, see bug 1719963.
1377 EnsureUniqueInner();
1379 RefPtr
<StyleLockedCssRules
> rawRules
=
1380 Servo_StyleSheet_GetRules(Inner().mContents
).Consume();
1381 MOZ_ASSERT(rawRules
);
1382 mRuleList
= new ServoCSSRuleList(rawRules
.forget(), this, nullptr);
1387 uint32_t StyleSheet::InsertRuleInternal(const nsACString
& aRule
,
1388 uint32_t aIndex
, ErrorResult
& aRv
) {
1389 MOZ_ASSERT(!IsReadOnly());
1390 MOZ_ASSERT(!ModificationDisallowed());
1392 // Ensure mRuleList is constructed.
1393 GetCssRulesInternal();
1395 aRv
= mRuleList
->InsertRule(aRule
, aIndex
);
1400 // XXX We may not want to get the rule when stylesheet change event
1402 css::Rule
* rule
= mRuleList
->GetRule(aIndex
);
1408 void StyleSheet::DeleteRuleInternal(uint32_t aIndex
, ErrorResult
& aRv
) {
1409 MOZ_ASSERT(!IsReadOnly());
1410 MOZ_ASSERT(!ModificationDisallowed());
1412 // Ensure mRuleList is constructed.
1413 GetCssRulesInternal();
1414 if (aIndex
>= mRuleList
->Length()) {
1415 aRv
.ThrowIndexSizeError(
1416 nsPrintfCString("Cannot delete rule at index %u"
1417 " because the number of rules is only %u",
1418 aIndex
, mRuleList
->Length()));
1422 // Hold a strong ref to the rule so it doesn't die when we remove it
1423 // from the list. XXX We may not want to hold it if stylesheet change
1424 // event is not enabled.
1425 RefPtr
<css::Rule
> rule
= mRuleList
->GetRule(aIndex
);
1426 aRv
= mRuleList
->DeleteRule(aIndex
);
1427 if (!aRv
.Failed()) {
1432 nsresult
StyleSheet::InsertRuleIntoGroupInternal(const nsACString
& aRule
,
1433 css::GroupRule
* aGroup
,
1435 MOZ_ASSERT(!IsReadOnly());
1437 ServoCSSRuleList
* rules
= aGroup
->CssRules();
1438 MOZ_ASSERT(rules
&& rules
->GetParentRule() == aGroup
);
1439 return rules
->InsertRule(aRule
, aIndex
);
1442 StyleOrigin
StyleSheet::GetOrigin() const {
1443 return Servo_StyleSheet_GetOrigin(Inner().mContents
);
1446 void StyleSheet::SetSharedContents(const StyleLockedCssRules
* aSharedRules
) {
1447 MOZ_ASSERT(!IsComplete());
1452 Servo_StyleSheet_FromSharedData(URLData(), aSharedRules
).Consume();
1455 const StyleLockedCssRules
* StyleSheet::ToShared(
1456 StyleSharedMemoryBuilder
* aBuilder
, nsCString
& aErrorMessage
) {
1457 // Assert some things we assume when creating a StyleSheet using shared
1459 MOZ_ASSERT(GetReferrerInfo()->ReferrerPolicy() == ReferrerPolicy::_empty
);
1460 MOZ_ASSERT(GetReferrerInfo()->GetSendReferrer());
1461 MOZ_ASSERT(!nsCOMPtr
<nsIURI
>(GetReferrerInfo()->GetComputedReferrer()));
1462 MOZ_ASSERT(GetCORSMode() == CORS_NONE
);
1463 MOZ_ASSERT(Inner().mIntegrity
.IsEmpty());
1464 MOZ_ASSERT(Principal()->IsSystemPrincipal());
1466 const StyleLockedCssRules
* rules
= Servo_SharedMemoryBuilder_AddStylesheet(
1467 aBuilder
, Inner().mContents
, &aErrorMessage
);
1471 // Print the ToShmem error message so that developers know what to fix.
1472 printf_stderr("%s\n", aErrorMessage
.get());
1473 MOZ_CRASH("UA style sheet contents failed shared memory requirements");
1480 bool StyleSheet::IsReadOnly() const {
1481 return IsComplete() && GetOrigin() == StyleOrigin::UserAgent
;
1484 } // namespace mozilla