Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / layout / style / StyleSheet.cpp
blob494618d879b0319c4a8a72e313cb2c349f28f53c
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"
33 namespace mozilla {
35 using namespace dom;
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),
53 mTitle(aCopy.mTitle),
54 mDocumentOrShadowRoot(aDocOrShadowRootToUse),
55 mParsingMode(aCopy.mParsingMode),
56 mState(aCopy.mState),
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?");
68 EnsureUniqueInner();
69 // But CSSOM hasn't been on _this_ stylesheet yet, so no need to clone
70 // ourselves.
71 mState &= ~(State::ForcedUniqueInner | State::ModifiedRules |
72 State::ModifiedRulesForDevtools);
75 if (aCopy.mMedia) {
76 // XXX This is wrong; we should be keeping @import rules and
77 // sheets in sync!
78 mMedia = aCopy.mMedia->Clone();
82 /* static */
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,
86 ErrorResult& aRv) {
87 nsCOMPtr<nsPIDOMWindowInner> window =
88 do_QueryInterface(aGlobal.GetAsSupports());
90 if (!window) {
91 aRv.ThrowNotSupportedError("Not supported when there is no document");
92 return nullptr;
95 Document* constructorDocument = window->GetExtantDoc();
96 if (!constructorDocument) {
97 aRv.ThrowNotSupportedError("Not supported when there is no document");
98 return nullptr;
101 // 1. Construct a sheet and set its properties (see spec).
102 auto sheet =
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();
111 } else {
112 nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aOptions.mBaseURL.Value(),
113 nullptr, constructorDocument->GetBaseURI());
114 if (NS_FAILED(rv)) {
115 aRv.ThrowNotAllowedError(
116 "Constructed style sheets must have a valid base URL");
117 return nullptr;
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()));
133 } else {
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();
141 // 4. Return sheet.
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()
159 const {
160 const StyleSheet& outer = OutermostSheet();
161 if (outer.mDocumentOrShadowRoot) {
162 return outer.mDocumentOrShadowRoot;
164 if (outer.IsConstructed()) {
165 return outer.mConstructorDocument;
167 return nullptr;
170 void StyleSheet::UpdateRelevantGlobal() {
171 if (mRelevantGlobal || !IsComplete()) {
172 return;
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();
192 return nullptr;
195 void StyleSheet::LastRelease() {
196 MOZ_DIAGNOSTIC_ASSERT(mAdopters.IsEmpty(),
197 "Should have no adopters at time of destruction.");
199 if (mInner) {
200 MOZ_ASSERT(mInner->mSheets.Contains(this), "Our mInner should include us.");
201 mInner->RemoveSheet(this);
202 mInner = nullptr;
205 DropMedia();
206 DropRuleList();
209 void StyleSheet::UnlinkInner() {
210 if (!mInner) {
211 return;
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);
218 mInner = nullptr;
219 return;
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) {
230 if (!mInner) {
231 return;
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)
247 NS_INTERFACE_MAP_END
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)
269 tmp->DropMedia();
270 tmp->UnlinkInner();
271 tmp->DropRuleList();
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) \
280 static_assert( \
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);
289 #undef CHECK_MODE
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();
305 if (!Disabled()) {
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();
323 } else {
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) {
343 Notify(*adopter);
347 if (docToPostEvent) {
348 docToPostEvent->PostStyleSheetApplicableStateChangeEvent(*this);
352 void StyleSheet::SetDisabled(bool aDisabled) {
353 if (IsReadOnly()) {
354 return;
357 if (aDisabled == Disabled()) {
358 return;
361 if (aDisabled) {
362 mState |= State::Disabled;
363 } else {
364 mState &= ~State::Disabled;
367 if (IsComplete()) {
368 ApplicableStateChanged(!aDisabled);
372 void StyleSheet::SetURLExtraData() {
373 Inner().mURLData =
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()) {
391 if (!mPrincipal) {
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
406 // children.
407 mSourceMapURL(aCopy.mSourceMapURL),
408 mContents(Servo_StyleSheet_Clone(aCopy.mContents.get(), aPrimarySheet)
409 .Consume()),
410 mURLData(aCopy.mURLData)
411 #ifdef DEBUG
413 mPrincipalSet(aCopy.mPrincipalSet)
414 #endif
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,
436 mContents);
438 return n;
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");
459 delete this;
460 return;
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) {
470 nsAutoCString str;
471 nsresult rv = sheetURI->GetSpec(str);
472 if (NS_FAILED(rv)) {
473 aRv.Throw(rv);
474 return;
476 CopyUTF8toUTF16(str, aHref);
477 } else {
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
486 // string.
488 if (!mTitle.IsEmpty()) {
489 aTitle.Assign(mTitle);
490 } else {
491 SetDOMStringToNull(aTitle);
495 void StyleSheet::WillDirty() {
496 MOZ_ASSERT(!IsReadOnly());
498 if (IsComplete()) {
499 EnsureUniqueInner();
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
513 Unused << found;
514 #endif
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_) \
520 do { \
521 StyleSheet* current = this; \
522 do { \
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_; \
529 } else { \
530 docOrShadow->AsNode().AsDocument()->function_ args_; \
533 for (auto* adopter : mAdopters) { \
534 if (auto* shadow = ShadowRoot::FromNode(adopter->AsNode())) { \
535 shadow->function_ args_; \
536 } else { \
537 adopter->AsNode().AsDocument()->function_ args_; \
540 current = current->mParentSheet; \
541 } while (current); \
542 } while (0)
544 void StyleSheet::EnsureUniqueInner() {
545 MOZ_ASSERT(mInner->mSheets.Length() != 0, "unexpected number of outers");
547 if (IsReadOnly()) {
548 // Sheets that can't be modified don't need a unique inner.
549 return;
552 mState |= State::ForcedUniqueInner;
554 if (HasUniqueInner()) {
555 // already unique
556 return;
559 StyleSheetInfo* clone = mInner->CloneFor(this);
560 MOZ_ASSERT(clone);
562 mInner->RemoveSheet(this);
563 mInner = clone;
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
572 // document
573 NOTIFY(SheetCloned, (*this));
576 // WebIDL CSSStyleSheet API
578 dom::CSSRuleList* StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
579 ErrorResult& aRv) {
580 if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
581 return nullptr;
583 return GetCssRulesInternal();
586 void StyleSheet::GetSourceMapURL(nsACString& aSourceMapURL) {
587 if (!mInner->mSourceMapURL.IsEmpty()) {
588 aSourceMapURL = mInner->mSourceMapURL;
589 return;
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,
608 ErrorResult& aRv) {
609 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal, aRv)) {
610 return 0;
613 if (ModificationDisallowed()) {
614 aRv.ThrowNotAllowedError(
615 "This method can only be called on "
616 "modifiable style sheets");
617 return 0;
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,
626 ErrorResult& aRv) {
627 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal, aRv)) {
628 return;
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)) {
645 return -1;
648 nsAutoCString rule;
649 rule.Append(aSelector);
650 rule.AppendLiteral(" { ");
651 if (!aBlock.IsEmpty()) {
652 rule.Append(aBlock);
653 rule.Append(' ');
655 rule.Append('}');
657 auto index =
658 aIndex.WasPassed() ? aIndex.Value() : GetCssRulesInternal()->Length();
660 InsertRuleInternal(rule, index, aRv);
661 // Always return -1.
662 return -1;
665 void StyleSheet::MaybeResolveReplacePromise() {
666 MOZ_ASSERT(!!mReplacePromise == ModificationDisallowed());
667 if (!mReplacePromise) {
668 return;
671 SetModificationDisallowed(false);
672 mReplacePromise->MaybeResolve(this);
673 mReplacePromise = nullptr;
676 void StyleSheet::MaybeRejectReplacePromise() {
677 MOZ_ASSERT(!!mReplacePromise == ModificationDisallowed());
678 if (!mReplacePromise) {
679 return;
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,
690 ErrorResult& aRv) {
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);
700 if (!promise) {
701 return nullptr;
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);
735 // In parallel
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)
744 ->Then(
745 target, __func__,
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();
772 SetURLExtraData();
773 RefPtr<const StyleStylesheetContents> rawContent =
774 Servo_StyleSheet_FromUTF8Bytes(
775 loader, this,
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)
782 .Consume();
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,
791 uint32_t aIndex) {
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;
802 if (IsReadOnly()) {
803 return NS_OK;
806 WillDirty();
808 nsresult result = aGroup->DeleteStyleRuleAt(aIndex);
809 NS_ENSURE_SUCCESS(result, result);
811 rule->DropReferences();
813 RuleRemoved(*rule);
814 return NS_OK;
817 void StyleSheet::RuleAdded(css::Rule& aRule) {
818 SetModifiedRules();
819 NOTIFY(RuleAdded, (*this, aRule));
822 void StyleSheet::RuleRemoved(css::Rule& aRule) {
823 SetModifiedRules();
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");
830 SetModifiedRules();
831 NOTIFY(RuleChanged, (*this, aRule, aKind));
834 // nsICSSLoaderObserver implementation
835 NS_IMETHODIMP
836 StyleSheet::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
837 nsresult aStatus) {
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 "
843 "our child!");
844 if (NS_FAILED(aStatus)) {
845 return NS_OK;
848 MOZ_ASSERT(aSheet->GetOwnerRule());
849 NOTIFY(ImportRuleLoaded, (*aSheet->GetOwnerRule(), *aSheet));
850 return NS_OK;
853 #undef NOTIFY
855 nsresult StyleSheet::InsertRuleIntoGroup(const nsACString& aRule,
856 css::GroupRule* aGroup,
857 uint32_t aIndex) {
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;
864 if (IsReadOnly()) {
865 return NS_OK;
868 if (ModificationDisallowed()) {
869 return NS_ERROR_DOM_NOT_ALLOWED_ERR;
872 WillDirty();
874 nsresult result = InsertRuleIntoGroupInternal(aRule, aGroup, aIndex);
875 NS_ENSURE_SUCCESS(result, result);
876 RuleAdded(*aGroup->GetStyleRuleAt(aIndex));
877 return NS_OK;
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();
893 if (sheet) {
894 windowID = sheet->FindOwningWindowInnerID();
898 if (windowID == 0 && mParentSheet) {
899 windowID = mParentSheet->FindOwningWindowInnerID();
902 return windowID;
905 void StyleSheet::RemoveFromParent() {
906 if (!mParentSheet) {
907 return;
910 MOZ_ASSERT(mParentSheet->ChildSheets().Contains(this));
911 mParentSheet->Inner().mChildren.RemoveElement(this);
912 mParentSheet = nullptr;
915 void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
916 ErrorResult& aRv) {
917 StyleSheetInfo& info = Inner();
919 if (aSubjectPrincipal.Subsumes(info.mPrincipal)) {
920 return;
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");
927 return;
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.
941 if (!IsComplete()) {
942 aRv.ThrowInvalidAccessError(
943 "Not allowed to access still-loading stylesheet");
944 return;
947 WillDirty();
949 info.mPrincipal = &aSubjectPrincipal;
952 bool StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
953 ErrorResult& aRv) {
954 // Rules are not available on incomplete sheets.
955 if (!IsComplete()) {
956 aRv.ThrowInvalidAccessError(
957 "Can't access rules of still-loading style sheet");
958 return false;
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())) {
964 return false;
966 return true;
969 void StyleSheet::SetAssociatedDocumentOrShadowRoot(
970 DocumentOrShadowRoot* aDocOrShadowRoot) {
971 MOZ_ASSERT(!IsConstructed());
972 MOZ_ASSERT(!mParentSheet || !aDocOrShadowRoot,
973 "Shouldn't be set on child sheets");
975 // not ref counted
976 mDocumentOrShadowRoot = aDocOrShadowRoot;
977 UpdateRelevantGlobal();
980 void StyleSheet::AppendStyleSheet(StyleSheet& aSheet) {
981 WillDirty();
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
991 // it's going away.
992 aSheet.mParentSheet = this;
995 size_t StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
996 size_t n = 0;
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
1006 // is worthwhile:
1007 // - mTitle
1008 // - mMedia
1009 // - mStyleSets
1010 // - mRuleList
1012 return n;
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);
1021 nsCString line;
1022 for (int i = 0; i < aIndent; ++i) {
1023 line.AppendLiteral(" ");
1026 line.AppendLiteral("/* ");
1028 nsCString url;
1029 GetSheetURI()->GetSpec(url);
1030 if (url.IsEmpty()) {
1031 line.AppendLiteral("(no URL)");
1032 } else {
1033 line.Append(url);
1036 line.AppendLiteral(" (");
1038 switch (GetOrigin()) {
1039 case StyleOrigin::UserAgent:
1040 line.AppendLiteral("User Agent");
1041 break;
1042 case StyleOrigin::User:
1043 line.AppendLiteral("User");
1044 break;
1045 case StyleOrigin::Author:
1046 line.AppendLiteral("Author");
1047 break;
1050 if (mMedia) {
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");
1084 #endif
1086 void StyleSheet::SetMedia(already_AddRefed<dom::MediaList> aMedia) {
1087 mMedia = aMedia;
1088 if (mMedia) {
1089 mMedia->SetStyleSheet(this);
1093 void StyleSheet::DropMedia() {
1094 if (mMedia) {
1095 mMedia->SetStyleSheet(nullptr);
1096 mMedia = nullptr;
1100 dom::MediaList* StyleSheet::Media() {
1101 if (!mMedia) {
1102 mMedia = dom::MediaList::Create(EmptyCString());
1103 mMedia->SetStyleSheet(this);
1106 return mMedia;
1109 // nsWrapperCache
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) {
1117 if (!mRuleList) {
1118 return;
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();
1135 uint32_t index = 0;
1136 while (true) {
1137 uint32_t line, column; // Actually unused.
1138 RefPtr<StyleLockedImportRule> import =
1139 Servo_CssRules_GetImportRuleAt(rules, index, &line, &column).Consume();
1140 if (!import) {
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.
1144 break;
1146 auto* sheet = const_cast<StyleSheet*>(Servo_ImportRule_GetSheet(import));
1147 MOZ_ASSERT(sheet);
1148 AppendStyleSheetSilently(*sheet);
1149 index++;
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)) {
1167 return false;
1169 // Otherwise we can parse in parallel.
1170 return true;
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,
1180 __func__);
1182 SetURLExtraData();
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)
1207 .Consume();
1208 FinishAsyncParse(contents.forget(), std::move(counters));
1209 } else {
1210 auto holder = MakeRefPtr<css::SheetLoadDataHolder>(__func__, &aLoadData);
1211 Servo_StyleSheet_FromUTF8BytesAsync(holder, urlData, &aBytes, mParsingMode,
1212 aLoadData.mCompatMode,
1213 shouldRecordCounters, allowImportRules);
1216 return p;
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 = [&] {
1235 if (aLoadData) {
1236 return aLoadData->mCompatMode;
1238 if (aLoader) {
1239 return aLoader->CompatMode(css::StylePreloadKind::None);
1241 return eCompatibility_FullStandards;
1242 }();
1244 SetURLExtraData();
1246 URLExtraData* urlData = URLData();
1247 const StyleUseCounters* useCounters =
1248 aLoader && aLoader->GetDocument() && !urlData->ChromeRulesEnabled()
1249 ? aLoader->GetDocument()->GetStyleUseCounters()
1250 : nullptr;
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)
1261 .Consume();
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.
1272 if (IsReadOnly()) {
1273 return;
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!");
1282 } else {
1283 loader = new css::Loader;
1286 WillDirty();
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);
1310 MOZ_ASSERT(rule);
1311 RuleRemoved(*rule);
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);
1333 MOZ_ASSERT(rule);
1334 RuleAdded(*rule);
1338 // Our rules are no longer considered modified for devtools.
1339 mState &= ~State::ModifiedRulesForDevtools;
1342 void StyleSheet::DropRuleList() {
1343 if (mRuleList) {
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() {
1374 if (!mRuleList) {
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);
1384 return mRuleList;
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);
1396 if (aRv.Failed()) {
1397 return 0;
1400 // XXX We may not want to get the rule when stylesheet change event
1401 // is not enabled.
1402 css::Rule* rule = mRuleList->GetRule(aIndex);
1403 RuleAdded(*rule);
1405 return 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()));
1419 return;
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()) {
1428 RuleRemoved(*rule);
1432 nsresult StyleSheet::InsertRuleIntoGroupInternal(const nsACString& aRule,
1433 css::GroupRule* aGroup,
1434 uint32_t aIndex) {
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());
1449 SetURLExtraData();
1451 Inner().mContents =
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
1458 // memory.
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);
1469 #ifdef DEBUG
1470 if (!rules) {
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");
1475 #endif
1477 return rules;
1480 bool StyleSheet::IsReadOnly() const {
1481 return IsComplete() && GetOrigin() == StyleOrigin::UserAgent;
1484 } // namespace mozilla