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),
43 mParsingMode(aParsingMode
),
44 mState(static_cast<State
>(0)),
45 mInner(new StyleSheetInfo(aCORSMode
, aIntegrity
, aParsingMode
)) {
46 mInner
->AddSheet(this);
49 StyleSheet::StyleSheet(const StyleSheet
& aCopy
, StyleSheet
* aParentSheetToUse
,
50 dom::CSSImportRule
* aOwnerRuleToUse
,
51 dom::DocumentOrShadowRoot
* aDocOrShadowRootToUse
,
52 dom::Document
* aConstructorDocToUse
,
53 nsINode
* aOwningNodeToUse
)
54 : mParentSheet(aParentSheetToUse
),
55 mRelevantGlobal(nullptr),
56 mConstructorDocument(aConstructorDocToUse
),
58 mDocumentOrShadowRoot(aDocOrShadowRootToUse
),
59 mOwningNode(aOwningNodeToUse
),
60 mOwnerRule(aOwnerRuleToUse
),
61 mParsingMode(aCopy
.mParsingMode
),
63 // Shallow copy, but concrete subclasses will fix up.
64 mInner(aCopy
.mInner
) {
65 MOZ_ASSERT(!aConstructorDocToUse
|| aCopy
.IsConstructed());
66 MOZ_ASSERT(!aConstructorDocToUse
|| !aDocOrShadowRootToUse
,
67 "Should never have both of these together.");
68 MOZ_ASSERT(mInner
, "Should only copy StyleSheets with an mInner.");
69 mInner
->AddSheet(this);
70 // CSSOM's been there, force full copy now.
71 if (HasForcedUniqueInner()) {
72 MOZ_ASSERT(IsComplete(),
73 "Why have rules been accessed on an incomplete sheet?");
75 // But CSSOM hasn't been on _this_ stylesheet yet, so no need to clone
77 mState
&= ~(State::ForcedUniqueInner
| State::ModifiedRules
|
78 State::ModifiedRulesForDevtools
);
82 // XXX This is wrong; we should be keeping @import rules and
84 mMedia
= aCopy
.mMedia
->Clone();
89 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-cssstylesheet
90 already_AddRefed
<StyleSheet
> StyleSheet::Constructor(
91 const dom::GlobalObject
& aGlobal
, const dom::CSSStyleSheetInit
& aOptions
,
93 nsCOMPtr
<nsPIDOMWindowInner
> window
=
94 do_QueryInterface(aGlobal
.GetAsSupports());
97 aRv
.ThrowNotSupportedError("Not supported when there is no document");
101 Document
* constructorDocument
= window
->GetExtantDoc();
102 if (!constructorDocument
) {
103 aRv
.ThrowNotSupportedError("Not supported when there is no document");
107 // 1. Construct a sheet and set its properties (see spec).
109 MakeRefPtr
<StyleSheet
>(css::SheetParsingMode::eAuthorSheetFeatures
,
110 CORSMode::CORS_NONE
, dom::SRIMetadata());
112 // baseURL not yet in the spec. Implemented based on the following discussion:
113 // https://github.com/WICG/construct-stylesheets/issues/95#issuecomment-594217180
114 RefPtr
<nsIURI
> baseURI
;
115 if (!aOptions
.mBaseURL
.WasPassed()) {
116 baseURI
= constructorDocument
->GetBaseURI();
118 nsresult rv
= NS_NewURI(getter_AddRefs(baseURI
), aOptions
.mBaseURL
.Value(),
119 nullptr, constructorDocument
->GetBaseURI());
121 aRv
.ThrowNotAllowedError(
122 "Constructed style sheets must have a valid base URL");
127 nsIURI
* sheetURI
= constructorDocument
->GetDocumentURI();
128 nsIURI
* originalURI
= nullptr;
129 sheet
->SetURIs(sheetURI
, originalURI
, baseURI
);
131 sheet
->SetPrincipal(constructorDocument
->NodePrincipal());
132 sheet
->SetReferrerInfo(constructorDocument
->GetReferrerInfo());
133 sheet
->mConstructorDocument
= constructorDocument
;
134 if (constructorDocument
) {
135 sheet
->mRelevantGlobal
= constructorDocument
->GetParentObject();
138 // 2. Set the sheet's media according to aOptions.
139 if (aOptions
.mMedia
.IsUTF8String()) {
140 sheet
->SetMedia(MediaList::Create(aOptions
.mMedia
.GetAsUTF8String()));
142 sheet
->SetMedia(aOptions
.mMedia
.GetAsMediaList()->Clone());
145 // 3. Set the sheet's disabled flag according to aOptions.
146 sheet
->SetDisabled(aOptions
.mDisabled
);
147 sheet
->SetComplete();
150 return sheet
.forget();
153 StyleSheet::~StyleSheet() {
154 MOZ_ASSERT(!mInner
, "Inner should have been dropped in LastRelease");
157 bool StyleSheet::HasRules() const {
158 return Servo_StyleSheet_HasRules(Inner().mContents
);
161 Document
* StyleSheet::GetAssociatedDocument() const {
162 auto* associated
= GetAssociatedDocumentOrShadowRoot();
163 return associated
? associated
->AsNode().OwnerDoc() : nullptr;
166 dom::DocumentOrShadowRoot
* StyleSheet::GetAssociatedDocumentOrShadowRoot()
168 const StyleSheet
& outer
= OutermostSheet();
169 if (outer
.mDocumentOrShadowRoot
) {
170 return outer
.mDocumentOrShadowRoot
;
172 if (outer
.IsConstructed()) {
173 return outer
.mConstructorDocument
;
178 Document
* StyleSheet::GetKeptAliveByDocument() const {
179 const StyleSheet
& outer
= OutermostSheet();
180 if (outer
.mDocumentOrShadowRoot
) {
181 return outer
.mDocumentOrShadowRoot
->AsNode().GetComposedDoc();
183 if (outer
.IsConstructed()) {
184 for (DocumentOrShadowRoot
* adopter
: outer
.mAdopters
) {
185 MOZ_ASSERT(adopter
->AsNode().OwnerDoc() == outer
.mConstructorDocument
);
186 if (adopter
->AsNode().IsInComposedDoc()) {
187 return outer
.mConstructorDocument
.get();
194 void StyleSheet::LastRelease() {
195 MOZ_ASSERT(mInner
, "Should have an mInner at time of destruction.");
196 MOZ_ASSERT(mInner
->mSheets
.Contains(this), "Our mInner should include us.");
197 MOZ_DIAGNOSTIC_ASSERT(mAdopters
.IsEmpty(),
198 "Should have no adopters at time of destruction.");
200 mInner
->RemoveSheet(this);
207 void StyleSheet::UnlinkInner() {
208 // We can only have a cycle through our inner if we have a unique inner,
209 // because otherwise there are no JS wrappers for anything in the inner.
210 if (mInner
->mSheets
.Length() != 1) {
214 for (StyleSheet
* child
: ChildSheets()) {
215 MOZ_ASSERT(child
->mParentSheet
== this, "We have a unique inner!");
216 child
->mParentSheet
= nullptr;
218 Inner().mChildren
.Clear();
221 void StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback
& cb
) {
222 // We can only have a cycle through our inner if we have a unique inner,
223 // because otherwise there are no JS wrappers for anything in the inner.
224 if (mInner
->mSheets
.Length() != 1) {
228 for (StyleSheet
* child
: ChildSheets()) {
229 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "child sheet");
230 cb
.NoteXPCOMChild(child
);
234 // QueryInterface implementation for StyleSheet
235 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet
)
236 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
237 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
238 NS_INTERFACE_MAP_ENTRY(nsISupports
)
241 NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet
)
242 // We want to disconnect from our inner as soon as our refcount drops to zero,
243 // without waiting for async deletion by the cycle collector. Otherwise we
244 // might end up cloning the inner if someone mutates another sheet that shares
245 // it with us, even though there is only one such sheet and we're about to go
246 // away. This situation arises easily with sheet preloading.
247 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(StyleSheet
, LastRelease())
249 NS_IMPL_CYCLE_COLLECTION_CLASS(StyleSheet
)
251 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StyleSheet
)
252 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia
)
253 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleList
)
254 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelevantGlobal
)
255 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConstructorDocument
)
256 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReplacePromise
)
257 tmp
->TraverseInner(cb
);
258 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
260 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StyleSheet
)
264 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelevantGlobal
)
265 NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructorDocument
)
266 NS_IMPL_CYCLE_COLLECTION_UNLINK(mReplacePromise
)
267 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
268 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
270 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(StyleSheet
)
272 dom::CSSStyleSheetParsingMode
StyleSheet::ParsingModeDOM() {
273 #define CHECK_MODE(X, Y) \
275 static_cast<int>(X) == static_cast<int>(Y), \
276 "mozilla::dom::CSSStyleSheetParsingMode and " \
277 "mozilla::css::SheetParsingMode should have identical values");
279 CHECK_MODE(dom::CSSStyleSheetParsingMode::Agent
, css::eAgentSheetFeatures
);
280 CHECK_MODE(dom::CSSStyleSheetParsingMode::User
, css::eUserSheetFeatures
);
281 CHECK_MODE(dom::CSSStyleSheetParsingMode::Author
, css::eAuthorSheetFeatures
);
285 return static_cast<dom::CSSStyleSheetParsingMode
>(mParsingMode
);
288 void StyleSheet::SetComplete() {
289 // HasForcedUniqueInner() is okay if the sheet is constructed, because
290 // constructed sheets are always unique and they may be set to complete
291 // multiple times if their rules are replaced via Replace()
292 MOZ_ASSERT(IsConstructed() || !HasForcedUniqueInner(),
293 "Can't complete a sheet that's already been forced unique.");
294 MOZ_ASSERT(!IsComplete(), "Already complete?");
295 mState
|= State::Complete
;
297 ApplicableStateChanged(true);
299 MaybeResolveReplacePromise();
302 void StyleSheet::ApplicableStateChanged(bool aApplicable
) {
303 MOZ_ASSERT(aApplicable
== IsApplicable());
304 auto Notify
= [this](DocumentOrShadowRoot
& target
) {
305 nsINode
& node
= target
.AsNode();
306 if (ShadowRoot
* shadow
= ShadowRoot::FromNode(node
)) {
307 shadow
->StyleSheetApplicableStateChanged(*this);
309 node
.AsDocument()->StyleSheetApplicableStateChanged(*this);
313 const StyleSheet
& sheet
= OutermostSheet();
314 if (sheet
.mDocumentOrShadowRoot
) {
315 Notify(*sheet
.mDocumentOrShadowRoot
);
318 for (DocumentOrShadowRoot
* adopter
: sheet
.mAdopters
) {
319 MOZ_ASSERT(adopter
, "adopters should never be null");
324 void StyleSheet::SetDisabled(bool aDisabled
) {
329 if (aDisabled
== Disabled()) {
334 mState
|= State::Disabled
;
336 mState
&= ~State::Disabled
;
340 ApplicableStateChanged(!aDisabled
);
344 void StyleSheet::SetURLExtraData() {
346 new URLExtraData(GetBaseURI(), GetReferrerInfo(), Principal());
349 nsISupports
* StyleSheet::GetRelevantGlobal() const {
350 const StyleSheet
& outer
= OutermostSheet();
351 return outer
.mRelevantGlobal
;
354 StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode
,
355 const SRIMetadata
& aIntegrity
,
356 css::SheetParsingMode aParsingMode
)
357 : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes()),
358 mCORSMode(aCORSMode
),
359 mReferrerInfo(new ReferrerInfo(nullptr)),
360 mIntegrity(aIntegrity
),
361 mContents(Servo_StyleSheet_Empty(aParsingMode
).Consume()),
362 mURLData(URLExtraData::Dummy())
369 MOZ_CRASH("NullPrincipal::Init failed");
371 MOZ_COUNT_CTOR(StyleSheetInfo
);
374 StyleSheetInfo::StyleSheetInfo(StyleSheetInfo
& aCopy
, StyleSheet
* aPrimarySheet
)
375 : mSheetURI(aCopy
.mSheetURI
),
376 mOriginalSheetURI(aCopy
.mOriginalSheetURI
),
377 mBaseURI(aCopy
.mBaseURI
),
378 mPrincipal(aCopy
.mPrincipal
),
379 mCORSMode(aCopy
.mCORSMode
),
380 mReferrerInfo(aCopy
.mReferrerInfo
),
381 mIntegrity(aCopy
.mIntegrity
),
382 // We don't rebuild the child because we're making a copy without
384 mSourceMapURL(aCopy
.mSourceMapURL
),
385 mSourceMapURLFromComment(aCopy
.mSourceMapURLFromComment
),
386 mSourceURL(aCopy
.mSourceURL
),
387 mContents(Servo_StyleSheet_Clone(aCopy
.mContents
.get(), aPrimarySheet
)
389 mURLData(aCopy
.mURLData
)
392 mPrincipalSet(aCopy
.mPrincipalSet
)
395 AddSheet(aPrimarySheet
);
397 // Our child list is fixed up by our parent.
398 MOZ_COUNT_CTOR(StyleSheetInfo
);
401 StyleSheetInfo::~StyleSheetInfo() { MOZ_COUNT_DTOR(StyleSheetInfo
); }
403 StyleSheetInfo
* StyleSheetInfo::CloneFor(StyleSheet
* aPrimarySheet
) {
404 return new StyleSheetInfo(*this, aPrimarySheet
);
407 MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSheetMallocSizeOf
)
408 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf
)
410 size_t StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
411 size_t n
= aMallocSizeOf(this);
413 n
+= Servo_StyleSheet_SizeOfIncludingThis(
414 ServoStyleSheetMallocSizeOf
, ServoStyleSheetMallocEnclosingSizeOf
,
420 void StyleSheetInfo::AddSheet(StyleSheet
* aSheet
) {
421 mSheets
.AppendElement(aSheet
);
424 void StyleSheetInfo::RemoveSheet(StyleSheet
* aSheet
) {
425 // Fix up the parent pointer in children lists.
426 StyleSheet
* newParent
=
427 aSheet
== mSheets
[0] ? mSheets
.SafeElementAt(1) : mSheets
[0];
428 for (StyleSheet
* child
: mChildren
) {
429 MOZ_ASSERT(child
->mParentSheet
);
430 MOZ_ASSERT(child
->mParentSheet
->mInner
== this);
431 if (child
->mParentSheet
== aSheet
) {
432 child
->mParentSheet
= newParent
;
436 if (1 == mSheets
.Length()) {
437 NS_ASSERTION(aSheet
== mSheets
.ElementAt(0), "bad parent");
442 mSheets
.RemoveElement(aSheet
);
445 void StyleSheet::GetType(nsAString
& aType
) { aType
.AssignLiteral("text/css"); }
447 void StyleSheet::GetHref(nsAString
& aHref
, ErrorResult
& aRv
) {
448 if (nsIURI
* sheetURI
= Inner().mOriginalSheetURI
) {
450 nsresult rv
= sheetURI
->GetSpec(str
);
455 CopyUTF8toUTF16(str
, aHref
);
457 SetDOMStringToNull(aHref
);
461 void StyleSheet::GetTitle(nsAString
& aTitle
) {
462 // From https://drafts.csswg.org/cssom/#dom-stylesheet-title:
464 // The title attribute must return the title or null if title is the empty
467 if (!mTitle
.IsEmpty()) {
468 aTitle
.Assign(mTitle
);
470 SetDOMStringToNull(aTitle
);
474 void StyleSheet::WillDirty() {
475 MOZ_ASSERT(!IsReadOnly());
482 void StyleSheet::AddStyleSet(ServoStyleSet
* aStyleSet
) {
483 MOZ_DIAGNOSTIC_ASSERT(!mStyleSets
.Contains(aStyleSet
),
484 "style set already registered");
485 mStyleSets
.AppendElement(aStyleSet
);
488 void StyleSheet::DropStyleSet(ServoStyleSet
* aStyleSet
) {
489 bool found
= mStyleSets
.RemoveElement(aStyleSet
);
490 MOZ_DIAGNOSTIC_ASSERT(found
, "didn't find style set");
491 #ifndef MOZ_DIAGNOSTIC_ASSERT_ENABLED
496 // NOTE(emilio): Composed doc and containing shadow root are set in child sheets
497 // too, so no need to do it for each ancestor.
498 #define NOTIFY(function_, args_) \
500 StyleSheet* current = this; \
502 for (ServoStyleSet * set : current->mStyleSets) { \
503 set->function_ args_; \
505 if (auto* docOrShadow = current->mDocumentOrShadowRoot) { \
506 if (auto* shadow = ShadowRoot::FromNode(docOrShadow->AsNode())) { \
507 shadow->function_ args_; \
509 docOrShadow->AsNode().AsDocument()->function_ args_; \
512 for (auto* adopter : mAdopters) { \
513 if (auto* shadow = ShadowRoot::FromNode(adopter->AsNode())) { \
514 shadow->function_ args_; \
516 adopter->AsNode().AsDocument()->function_ args_; \
519 current = current->mParentSheet; \
523 void StyleSheet::EnsureUniqueInner() {
524 MOZ_ASSERT(mInner
->mSheets
.Length() != 0, "unexpected number of outers");
527 // Sheets that can't be modified don't need a unique inner.
531 mState
|= State::ForcedUniqueInner
;
533 if (HasUniqueInner()) {
538 StyleSheetInfo
* clone
= mInner
->CloneFor(this);
540 mInner
->RemoveSheet(this);
543 // Fixup the child lists and parent links in the Servo sheet. This is done
544 // here instead of in StyleSheetInner::CloneFor, because it's just more
545 // convenient to do so instead.
546 BuildChildListAfterInnerClone();
548 // let our containing style sets know that if we call
549 // nsPresContext::EnsureSafeToHandOutCSSRules we will need to restyle the
551 NOTIFY(SheetCloned
, (*this));
554 // WebIDL CSSStyleSheet API
556 dom::CSSRuleList
* StyleSheet::GetCssRules(nsIPrincipal
& aSubjectPrincipal
,
558 if (!AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
561 return GetCssRulesInternal();
564 void StyleSheet::GetSourceMapURL(nsAString
& aSourceMapURL
) {
565 if (mInner
->mSourceMapURL
.IsEmpty()) {
566 aSourceMapURL
= mInner
->mSourceMapURLFromComment
;
568 aSourceMapURL
= mInner
->mSourceMapURL
;
572 void StyleSheet::SetSourceMapURL(const nsAString
& aSourceMapURL
) {
573 mInner
->mSourceMapURL
= aSourceMapURL
;
576 void StyleSheet::SetSourceMapURLFromComment(
577 const nsAString
& aSourceMapURLFromComment
) {
578 mInner
->mSourceMapURLFromComment
= aSourceMapURLFromComment
;
581 void StyleSheet::GetSourceURL(nsAString
& aSourceURL
) {
582 aSourceURL
= mInner
->mSourceURL
;
585 void StyleSheet::SetSourceURL(const nsAString
& aSourceURL
) {
586 mInner
->mSourceURL
= aSourceURL
;
589 css::Rule
* StyleSheet::GetDOMOwnerRule() const { return mOwnerRule
; }
591 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule
592 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-insertrule
593 uint32_t StyleSheet::InsertRule(const nsACString
& aRule
, uint32_t aIndex
,
594 nsIPrincipal
& aSubjectPrincipal
,
596 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
600 if (ModificationDisallowed()) {
601 aRv
.ThrowNotAllowedError(
602 "This method can only be called on "
603 "modifiable style sheets");
607 return InsertRuleInternal(aRule
, aIndex
, aRv
);
610 // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule
611 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-deleterule
612 void StyleSheet::DeleteRule(uint32_t aIndex
, nsIPrincipal
& aSubjectPrincipal
,
614 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
618 if (ModificationDisallowed()) {
619 return aRv
.ThrowNotAllowedError(
620 "This method can only be called on "
621 "modifiable style sheets");
624 return DeleteRuleInternal(aIndex
, aRv
);
627 int32_t StyleSheet::AddRule(const nsACString
& aSelector
,
628 const nsACString
& aBlock
,
629 const Optional
<uint32_t>& aIndex
,
630 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
631 if (IsReadOnly() || !AreRulesAvailable(aSubjectPrincipal
, aRv
)) {
636 rule
.Append(aSelector
);
637 rule
.AppendLiteral(" { ");
638 if (!aBlock
.IsEmpty()) {
645 aIndex
.WasPassed() ? aIndex
.Value() : GetCssRulesInternal()->Length();
647 InsertRuleInternal(rule
, index
, aRv
);
652 void StyleSheet::MaybeResolveReplacePromise() {
653 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
654 if (!mReplacePromise
) {
658 SetModificationDisallowed(false);
659 mReplacePromise
->MaybeResolve(this);
660 mReplacePromise
= nullptr;
663 void StyleSheet::MaybeRejectReplacePromise() {
664 MOZ_ASSERT(!!mReplacePromise
== ModificationDisallowed());
665 if (!mReplacePromise
) {
669 SetModificationDisallowed(false);
670 mReplacePromise
->MaybeRejectWithNetworkError(
671 "@import style sheet load failed");
672 mReplacePromise
= nullptr;
675 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replace
676 already_AddRefed
<dom::Promise
> StyleSheet::Replace(const nsACString
& aText
,
678 nsIGlobalObject
* globalObject
= nullptr;
679 const StyleSheet
& outer
= OutermostSheet();
680 if (outer
.mRelevantGlobal
) {
681 globalObject
= outer
.mRelevantGlobal
;
682 } else if (Document
* doc
= outer
.GetAssociatedDocument()) {
683 globalObject
= doc
->GetScopeObject();
686 RefPtr
<dom::Promise
> promise
= dom::Promise::Create(globalObject
, aRv
);
691 // Step 1 and 4 are variable declarations
693 // 2.1 Check if sheet is constructed, else reject promise.
694 if (!IsConstructed()) {
695 promise
->MaybeRejectWithNotAllowedError(
696 "This method can only be called on "
697 "constructed style sheets");
698 return promise
.forget();
701 // 2.2 Check if sheet is modifiable, else throw.
702 if (ModificationDisallowed()) {
703 promise
->MaybeRejectWithNotAllowedError(
704 "This method can only be called on "
705 "modifiable style sheets");
706 return promise
.forget();
709 // 3. Disallow modifications until finished.
710 SetModificationDisallowed(true);
712 // TODO(emilio, 1642227): Should constructable stylesheets notify global
713 // observers (i.e., set mMustNotify to true)?
714 auto* loader
= mConstructorDocument
->CSSLoader();
715 auto loadData
= MakeRefPtr
<css::SheetLoadData
>(
716 loader
, nullptr, this, /* aSyncLoad */ false,
717 css::Loader::UseSystemPrincipal::No
, css::StylePreloadKind::None
,
718 /* aPreloadEncoding */ nullptr,
719 /* aObserver */ nullptr, mConstructorDocument
->NodePrincipal(),
721 /* aRequestingNode */ nullptr);
724 // 5.1 Parse aText into rules.
725 // 5.2 Load import rules, throw NetworkError if failed.
726 // 5.3 Set sheet's rules to new rules.
727 nsCOMPtr
<nsISerialEventTarget
> target
=
728 mConstructorDocument
->EventTargetFor(TaskCategory::Other
);
729 loadData
->mIsBeingParsed
= true;
730 MOZ_ASSERT(!mReplacePromise
);
731 mReplacePromise
= promise
;
732 ParseSheet(*loader
, aText
, *loadData
)
735 [loadData
] { loadData
->SheetFinishedParsingAsync(); },
736 [] { MOZ_CRASH("This MozPromise should never be rejected."); });
738 // 6. Return the promise
739 return promise
.forget();
742 // https://wicg.github.io/construct-stylesheets/#dom-cssstylesheet-replacesync
743 void StyleSheet::ReplaceSync(const nsACString
& aText
, ErrorResult
& aRv
) {
744 // Step 1 is a variable declaration
746 // 2.1 Check if sheet is constructed, else throw.
747 if (!IsConstructed()) {
748 return aRv
.ThrowNotAllowedError(
749 "Can only be called on constructed style sheets");
752 // 2.2 Check if sheet is modifiable, else throw.
753 if (ModificationDisallowed()) {
754 return aRv
.ThrowNotAllowedError(
755 "Can only be called on modifiable style sheets");
758 // 3. Parse aText into rules.
759 // 4. If rules contain @imports, skip them and continue parsing.
760 auto* loader
= mConstructorDocument
->CSSLoader();
762 RefPtr
<const RawServoStyleSheetContents
> rawContent
=
763 Servo_StyleSheet_FromUTF8Bytes(
765 /* load_data = */ nullptr, &aText
, mParsingMode
, Inner().mURLData
,
766 /* line_number_offset = */ 0,
767 mConstructorDocument
->GetCompatibilityMode(),
768 /* reusable_sheets = */ nullptr,
769 mConstructorDocument
->GetStyleUseCounters(),
770 StyleAllowImportRules::No
, StyleSanitizationKind::None
,
771 /* sanitized_output = */ nullptr)
774 // 5. Set sheet's rules to the new rules.
776 Inner().mContents
= std::move(rawContent
);
778 RuleChanged(nullptr, StyleRuleChangeKind::Generic
);
781 nsresult
StyleSheet::DeleteRuleFromGroup(css::GroupRule
* aGroup
,
783 NS_ENSURE_ARG_POINTER(aGroup
);
784 NS_ASSERTION(IsComplete(), "No deleting from an incomplete sheet!");
785 RefPtr
<css::Rule
> rule
= aGroup
->GetStyleRuleAt(aIndex
);
786 NS_ENSURE_TRUE(rule
, NS_ERROR_ILLEGAL_VALUE
);
788 // check that the rule actually belongs to this sheet!
789 if (this != rule
->GetStyleSheet()) {
790 return NS_ERROR_INVALID_ARG
;
799 nsresult result
= aGroup
->DeleteStyleRuleAt(aIndex
);
800 NS_ENSURE_SUCCESS(result
, result
);
802 rule
->DropReferences();
808 void StyleSheet::RuleAdded(css::Rule
& aRule
) {
810 NOTIFY(RuleAdded
, (*this, aRule
));
813 void StyleSheet::RuleRemoved(css::Rule
& aRule
) {
815 NOTIFY(RuleRemoved
, (*this, aRule
));
818 void StyleSheet::RuleChanged(css::Rule
* aRule
, StyleRuleChangeKind aKind
) {
820 NOTIFY(RuleChanged
, (*this, aRule
, aKind
));
823 // nsICSSLoaderObserver implementation
825 StyleSheet::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
827 if (!aSheet
->GetParentSheet()) {
828 return NS_OK
; // ignore if sheet has been detached already
830 MOZ_ASSERT(this == aSheet
->GetParentSheet(),
831 "We are being notified of a sheet load for a sheet that is not "
833 if (NS_FAILED(aStatus
)) {
837 MOZ_ASSERT(aSheet
->GetOwnerRule());
838 NOTIFY(ImportRuleLoaded
, (*aSheet
->GetOwnerRule(), *aSheet
));
844 nsresult
StyleSheet::InsertRuleIntoGroup(const nsACString
& aRule
,
845 css::GroupRule
* aGroup
,
847 NS_ASSERTION(IsComplete(), "No inserting into an incomplete sheet!");
848 // check that the group actually belongs to this sheet!
849 if (this != aGroup
->GetStyleSheet()) {
850 return NS_ERROR_INVALID_ARG
;
857 if (ModificationDisallowed()) {
858 return NS_ERROR_DOM_NOT_ALLOWED_ERR
;
863 nsresult result
= InsertRuleIntoGroupInternal(aRule
, aGroup
, aIndex
);
864 NS_ENSURE_SUCCESS(result
, result
);
865 RuleAdded(*aGroup
->GetStyleRuleAt(aIndex
));
869 uint64_t StyleSheet::FindOwningWindowInnerID() const {
870 uint64_t windowID
= 0;
871 if (Document
* doc
= GetAssociatedDocument()) {
872 windowID
= doc
->InnerWindowID();
875 if (windowID
== 0 && mOwningNode
) {
876 windowID
= mOwningNode
->OwnerDoc()->InnerWindowID();
879 RefPtr
<css::Rule
> ownerRule
;
880 if (windowID
== 0 && (ownerRule
= GetDOMOwnerRule())) {
881 RefPtr
<StyleSheet
> sheet
= ownerRule
->GetStyleSheet();
883 windowID
= sheet
->FindOwningWindowInnerID();
887 if (windowID
== 0 && mParentSheet
) {
888 windowID
= mParentSheet
->FindOwningWindowInnerID();
894 void StyleSheet::RemoveFromParent() {
899 MOZ_ASSERT(mParentSheet
->ChildSheets().Contains(this));
900 mParentSheet
->Inner().mChildren
.RemoveElement(this);
901 mParentSheet
= nullptr;
904 void StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal
& aSubjectPrincipal
,
906 StyleSheetInfo
& info
= Inner();
908 if (aSubjectPrincipal
.Subsumes(info
.mPrincipal
)) {
912 // Allow access only if CORS mode is not NONE and the security flag
913 // is not turned off.
914 if (GetCORSMode() == CORS_NONE
&& !nsContentUtils::BypassCSSOMOriginCheck()) {
915 aRv
.ThrowSecurityError("Not allowed to access cross-origin stylesheet");
919 // Now make sure we set the principal of our inner to the subjectPrincipal.
920 // We do this because we're in a situation where the caller would not normally
921 // be able to access the sheet, but the sheet has opted in to being read.
922 // Unfortunately, that means it's also opted in to being _edited_, and if the
923 // caller now makes edits to the sheet we want the resulting resource loads,
924 // if any, to look as if they are coming from the caller's principal, not the
925 // original sheet principal.
927 // That means we need a unique inner, of course. But we don't want to do that
928 // if we're not complete yet. Luckily, all the callers of this method throw
929 // anyway if not complete, so we can just do that here too.
931 aRv
.ThrowInvalidAccessError(
932 "Not allowed to access still-loading stylesheet");
938 info
.mPrincipal
= &aSubjectPrincipal
;
941 bool StyleSheet::AreRulesAvailable(nsIPrincipal
& aSubjectPrincipal
,
943 // Rules are not available on incomplete sheets.
945 aRv
.ThrowInvalidAccessError(
946 "Can't access rules of still-loading style sheet");
949 //-- Security check: Only scripts whose principal subsumes that of the
950 // style sheet can access rule collections.
951 SubjectSubsumesInnerPrincipal(aSubjectPrincipal
, aRv
);
952 if (NS_WARN_IF(aRv
.Failed())) {
958 void StyleSheet::SetAssociatedDocumentOrShadowRoot(
959 DocumentOrShadowRoot
* aDocOrShadowRoot
) {
960 MOZ_ASSERT(!IsConstructed());
961 MOZ_ASSERT(!mParentSheet
|| !aDocOrShadowRoot
,
962 "Shouldn't be set on child sheets");
965 mDocumentOrShadowRoot
= aDocOrShadowRoot
;
967 if (Document
* doc
= GetAssociatedDocument()) {
968 MOZ_ASSERT(!mRelevantGlobal
);
969 mRelevantGlobal
= doc
->GetScopeObject();
973 void StyleSheet::AppendStyleSheet(StyleSheet
& aSheet
) {
975 AppendStyleSheetSilently(aSheet
);
978 void StyleSheet::AppendStyleSheetSilently(StyleSheet
& aSheet
) {
979 MOZ_ASSERT(!IsReadOnly());
981 Inner().mChildren
.AppendElement(&aSheet
);
983 // This is not reference counted. Our parent tells us when
985 aSheet
.mParentSheet
= this;
988 size_t StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
990 n
+= aMallocSizeOf(this);
992 // We want to measure the inner with only one of the children, and it makes
993 // sense for it to be the latest as it is the most likely to be reachable.
994 if (Inner().mSheets
.LastElement() == this) {
995 n
+= Inner().SizeOfIncludingThis(aMallocSizeOf
);
998 // Measurement of the following members may be added later if DMD finds it
1008 #if defined(DEBUG) || defined(MOZ_LAYOUT_DEBUGGER)
1009 void StyleSheet::List(FILE* aOut
, int32_t aIndent
) {
1010 for (StyleSheet
* child
: ChildSheets()) {
1011 child
->List(aOut
, aIndent
);
1015 for (int i
= 0; i
< aIndent
; ++i
) {
1016 line
.AppendLiteral(" ");
1019 line
.AppendLiteral("/* ");
1022 GetSheetURI()->GetSpec(url
);
1023 if (url
.IsEmpty()) {
1024 line
.AppendLiteral("(no URL)");
1029 line
.AppendLiteral(" (");
1031 switch (GetOrigin()) {
1032 case StyleOrigin::UserAgent
:
1033 line
.AppendLiteral("User Agent");
1035 case StyleOrigin::User
:
1036 line
.AppendLiteral("User");
1038 case StyleOrigin::Author
:
1039 line
.AppendLiteral("Author");
1044 nsAutoCString buffer
;
1045 mMedia
->GetText(buffer
);
1047 if (!buffer
.IsEmpty()) {
1048 line
.AppendLiteral(", ");
1049 line
.Append(buffer
);
1053 line
.AppendLiteral(") */");
1055 fprintf_stderr(aOut
, "%s\n\n", line
.get());
1057 nsCString newlineIndent
;
1058 newlineIndent
.Append('\n');
1059 for (int i
= 0; i
< aIndent
; ++i
) {
1060 newlineIndent
.AppendLiteral(" ");
1063 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1064 for (uint32_t i
= 0, len
= ruleList
->Length(); i
< len
; ++i
) {
1065 css::Rule
* rule
= ruleList
->GetRule(i
);
1067 nsAutoCString cssText
;
1068 rule
->GetCssText(cssText
);
1069 cssText
.ReplaceSubstring("\n"_ns
, newlineIndent
);
1070 fprintf_stderr(aOut
, "%s\n", cssText
.get());
1073 if (ruleList
->Length() != 0) {
1074 fprintf_stderr(aOut
, "\n");
1079 void StyleSheet::SetMedia(already_AddRefed
<dom::MediaList
> aMedia
) {
1082 mMedia
->SetStyleSheet(this);
1086 void StyleSheet::DropMedia() {
1088 mMedia
->SetStyleSheet(nullptr);
1093 dom::MediaList
* StyleSheet::Media() {
1095 mMedia
= dom::MediaList::Create(EmptyCString());
1096 mMedia
->SetStyleSheet(this);
1104 JSObject
* StyleSheet::WrapObject(JSContext
* aCx
,
1105 JS::Handle
<JSObject
*> aGivenProto
) {
1106 return dom::CSSStyleSheet_Binding::Wrap(aCx
, this, aGivenProto
);
1109 void StyleSheet::BuildChildListAfterInnerClone() {
1110 MOZ_ASSERT(Inner().mSheets
.Length() == 1, "Should've just cloned");
1111 MOZ_ASSERT(Inner().mSheets
[0] == this);
1112 MOZ_ASSERT(Inner().mChildren
.IsEmpty());
1114 auto* contents
= Inner().mContents
.get();
1115 RefPtr
<ServoCssRules
> rules
= Servo_StyleSheet_GetRules(contents
).Consume();
1119 uint32_t line
, column
; // Actually unused.
1120 RefPtr
<RawServoImportRule
> import
=
1121 Servo_CssRules_GetImportRuleAt(rules
, index
, &line
, &column
).Consume();
1123 // Note that only @charset rules come before @import rules, and @charset
1124 // rules are parsed but skipped, so we can stop iterating as soon as we
1125 // find something that isn't an @import rule.
1128 auto* sheet
= const_cast<StyleSheet
*>(Servo_ImportRule_GetSheet(import
));
1130 AppendStyleSheetSilently(*sheet
);
1135 already_AddRefed
<StyleSheet
> StyleSheet::CreateEmptyChildSheet(
1136 already_AddRefed
<dom::MediaList
> aMediaList
) const {
1137 RefPtr
<StyleSheet
> child
=
1138 new StyleSheet(ParsingMode(), CORSMode::CORS_NONE
, SRIMetadata());
1140 child
->mMedia
= aMediaList
;
1141 return child
.forget();
1144 // We disable parallel stylesheet parsing if any of the following three
1147 // (1) The pref is off.
1148 // (2) The browser is recording CSS errors (which parallel parsing can't
1150 // (3) The stylesheet is a chrome stylesheet, since those can use
1151 // -moz-bool-pref, which needs to access the pref service, which is not
1153 static bool AllowParallelParse(css::Loader
& aLoader
, URLExtraData
* aUrlData
) {
1154 // If the browser is recording CSS errors, we need to use the sequential path
1155 // because the parallel path doesn't support that.
1156 Document
* doc
= aLoader
.GetDocument();
1157 if (doc
&& css::ErrorReporter::ShouldReportErrors(*doc
)) {
1161 // If this is a chrome stylesheet, it might use -moz-bool-pref, which needs to
1162 // access the pref service, which is not thread-safe. We could probably expose
1163 // the relevant booleans as thread-safe var caches if we needed to, but
1164 // parsing chrome stylesheets in parallel is unlikely to be a win anyway.
1166 // Note that UA stylesheets can also use -moz-bool-pref, but those are always
1168 if (aUrlData
->ChromeRulesEnabled()) {
1175 RefPtr
<StyleSheetParsePromise
> StyleSheet::ParseSheet(
1176 css::Loader
& aLoader
, const nsACString
& aBytes
,
1177 css::SheetLoadData
& aLoadData
) {
1178 MOZ_ASSERT(mParsePromise
.IsEmpty());
1179 RefPtr
<StyleSheetParsePromise
> p
= mParsePromise
.Ensure(__func__
);
1182 // @import rules are disallowed due to this decision:
1183 // https://github.com/WICG/construct-stylesheets/issues/119#issuecomment-588352418
1184 // We may allow @import rules again in the future.
1185 auto allowImportRules
= SelfOrAncestorIsConstructed()
1186 ? StyleAllowImportRules::No
1187 : StyleAllowImportRules::Yes
;
1188 const bool shouldRecordCounters
=
1189 aLoader
.GetDocument() && aLoader
.GetDocument()->GetStyleUseCounters();
1190 if (!AllowParallelParse(aLoader
, Inner().mURLData
)) {
1191 UniquePtr
<StyleUseCounters
> counters
=
1192 shouldRecordCounters
? Servo_UseCounters_Create().Consume() : nullptr;
1194 RefPtr
<RawServoStyleSheetContents
> contents
=
1195 Servo_StyleSheet_FromUTF8Bytes(
1196 &aLoader
, this, &aLoadData
, &aBytes
, mParsingMode
, Inner().mURLData
,
1197 aLoadData
.mLineNumber
, aLoadData
.mCompatMode
,
1198 /* reusable_sheets = */ nullptr, counters
.get(), allowImportRules
,
1199 StyleSanitizationKind::None
,
1200 /* sanitized_output = */ nullptr)
1202 aLoadData
.mUseCounters
= std::move(counters
);
1203 FinishAsyncParse(contents
.forget());
1205 auto holder
= MakeRefPtr
<css::SheetLoadDataHolder
>(__func__
, &aLoadData
);
1206 Servo_StyleSheet_FromUTF8BytesAsync(
1207 holder
, Inner().mURLData
, &aBytes
, mParsingMode
, aLoadData
.mLineNumber
,
1208 aLoadData
.mCompatMode
, shouldRecordCounters
, allowImportRules
);
1214 void StyleSheet::FinishAsyncParse(
1215 already_AddRefed
<RawServoStyleSheetContents
> aSheetContents
) {
1216 MOZ_ASSERT(NS_IsMainThread());
1217 MOZ_ASSERT(!mParsePromise
.IsEmpty());
1218 Inner().mContents
= aSheetContents
;
1220 mParsePromise
.Resolve(true, __func__
);
1223 void StyleSheet::ParseSheetSync(
1224 css::Loader
* aLoader
, const nsACString
& aBytes
,
1225 css::SheetLoadData
* aLoadData
, uint32_t aLineNumber
,
1226 css::LoaderReusableStyleSheets
* aReusableSheets
) {
1227 const nsCompatibility compatMode
= [&] {
1229 return aLoadData
->mCompatMode
;
1232 return aLoader
->CompatMode(css::StylePreloadKind::None
);
1234 return eCompatibility_FullStandards
;
1237 const StyleUseCounters
* useCounters
=
1238 aLoader
&& aLoader
->GetDocument()
1239 ? aLoader
->GetDocument()->GetStyleUseCounters()
1242 auto allowImportRules
= SelfOrAncestorIsConstructed()
1243 ? StyleAllowImportRules::No
1244 : StyleAllowImportRules::Yes
;
1248 Servo_StyleSheet_FromUTF8Bytes(
1249 aLoader
, this, aLoadData
, &aBytes
, mParsingMode
, Inner().mURLData
,
1250 aLineNumber
, compatMode
, aReusableSheets
, useCounters
,
1251 allowImportRules
, StyleSanitizationKind::None
,
1252 /* sanitized_output = */ nullptr)
1258 void StyleSheet::FinishParse() {
1259 nsString sourceMapURL
;
1260 Servo_StyleSheet_GetSourceMapURL(Inner().mContents
, &sourceMapURL
);
1261 SetSourceMapURLFromComment(sourceMapURL
);
1264 Servo_StyleSheet_GetSourceURL(Inner().mContents
, &sourceURL
);
1265 SetSourceURL(sourceURL
);
1268 void StyleSheet::ReparseSheet(const nsACString
& aInput
, ErrorResult
& aRv
) {
1269 if (!IsComplete()) {
1270 return aRv
.ThrowInvalidAccessError("Cannot reparse still-loading sheet");
1273 // Allowing to modify UA sheets is dangerous (in the sense that C++ code
1274 // relies on rules in those sheets), plus they're probably going to be shared
1275 // across processes in which case this is directly a no-go.
1280 // Hold strong ref to the CSSLoader in case the document update
1281 // kills the document
1282 RefPtr
<css::Loader
> loader
;
1283 if (Document
* doc
= GetAssociatedDocument()) {
1284 loader
= doc
->CSSLoader();
1285 NS_ASSERTION(loader
, "Document with no CSS loader!");
1287 loader
= new css::Loader
;
1292 // cache child sheets to reuse
1293 css::LoaderReusableStyleSheets reusableSheets
;
1294 for (StyleSheet
* child
: ChildSheets()) {
1295 if (child
->GetOriginalURI()) {
1296 reusableSheets
.AddReusableSheet(child
);
1300 // Clean up child sheets list.
1301 for (StyleSheet
* child
: ChildSheets()) {
1302 child
->mParentSheet
= nullptr;
1304 Inner().mChildren
.Clear();
1306 uint32_t lineNumber
= 1;
1307 if (auto* linkStyle
= LinkStyle::FromNodeOrNull(mOwningNode
)) {
1308 lineNumber
= linkStyle
->GetLineNumber();
1311 // Notify to the stylesets about the old rules going away.
1313 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1314 MOZ_ASSERT(ruleList
);
1316 uint32_t ruleCount
= ruleList
->Length();
1317 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1318 css::Rule
* rule
= ruleList
->GetRule(i
);
1326 ParseSheetSync(loader
, aInput
, /* aLoadData = */ nullptr, lineNumber
,
1329 // Notify the stylesets about the new rules.
1331 // Get the rule list (which will need to be regenerated after ParseSheet).
1332 ServoCSSRuleList
* ruleList
= GetCssRulesInternal();
1333 MOZ_ASSERT(ruleList
);
1335 uint32_t ruleCount
= ruleList
->Length();
1336 for (uint32_t i
= 0; i
< ruleCount
; ++i
) {
1337 css::Rule
* rule
= ruleList
->GetRule(i
);
1343 // Our rules are no longer considered modified for devtools.
1344 mState
&= ~State::ModifiedRulesForDevtools
;
1347 void StyleSheet::DropRuleList() {
1349 mRuleList
->DropReferences();
1350 mRuleList
= nullptr;
1354 already_AddRefed
<StyleSheet
> StyleSheet::Clone(
1355 StyleSheet
* aCloneParent
, dom::CSSImportRule
* aCloneOwnerRule
,
1356 dom::DocumentOrShadowRoot
* aCloneDocumentOrShadowRoot
,
1357 nsINode
* aCloneOwningNode
) const {
1358 MOZ_ASSERT(!IsConstructed(),
1359 "Cannot create a non-constructed sheet from a constructed sheet");
1360 RefPtr
<StyleSheet
> clone
= new StyleSheet(
1361 *this, aCloneParent
, aCloneOwnerRule
, aCloneDocumentOrShadowRoot
,
1362 /* aConstructorDocToUse */ nullptr, aCloneOwningNode
);
1363 return clone
.forget();
1366 already_AddRefed
<StyleSheet
> StyleSheet::CloneAdoptedSheet(
1367 Document
& aConstructorDocument
) const {
1368 MOZ_ASSERT(IsConstructed(),
1369 "Cannot create a constructed sheet from a non-constructed sheet");
1370 MOZ_ASSERT(aConstructorDocument
.IsStaticDocument(),
1371 "Should never clone adopted sheets for a non-static document");
1372 RefPtr
<StyleSheet
> clone
=
1373 new StyleSheet(*this,
1374 /* aParentSheetToUse */ nullptr,
1375 /* aOwnerRuleToUse */ nullptr,
1376 /* aDocOrShadowRootToUse */ nullptr, &aConstructorDocument
,
1377 /* aOwningNodeToUse */ nullptr);
1378 return clone
.forget();
1381 ServoCSSRuleList
* StyleSheet::GetCssRulesInternal() {
1383 EnsureUniqueInner();
1385 RefPtr
<ServoCssRules
> rawRules
=
1386 Servo_StyleSheet_GetRules(Inner().mContents
).Consume();
1387 MOZ_ASSERT(rawRules
);
1388 mRuleList
= new ServoCSSRuleList(rawRules
.forget(), this, nullptr);
1393 uint32_t StyleSheet::InsertRuleInternal(const nsACString
& aRule
,
1394 uint32_t aIndex
, ErrorResult
& aRv
) {
1395 MOZ_ASSERT(!IsReadOnly());
1396 MOZ_ASSERT(!ModificationDisallowed());
1398 // Ensure mRuleList is constructed.
1399 GetCssRulesInternal();
1401 aRv
= mRuleList
->InsertRule(aRule
, aIndex
);
1406 // XXX We may not want to get the rule when stylesheet change event
1408 css::Rule
* rule
= mRuleList
->GetRule(aIndex
);
1414 void StyleSheet::DeleteRuleInternal(uint32_t aIndex
, ErrorResult
& aRv
) {
1415 MOZ_ASSERT(!IsReadOnly());
1416 MOZ_ASSERT(!ModificationDisallowed());
1418 // Ensure mRuleList is constructed.
1419 GetCssRulesInternal();
1420 if (aIndex
>= mRuleList
->Length()) {
1421 aRv
.ThrowIndexSizeError(
1422 nsPrintfCString("Cannot delete rule at index %u"
1423 " because the number of rules is only %u",
1424 aIndex
, mRuleList
->Length()));
1428 // Hold a strong ref to the rule so it doesn't die when we remove it
1429 // from the list. XXX We may not want to hold it if stylesheet change
1430 // event is not enabled.
1431 RefPtr
<css::Rule
> rule
= mRuleList
->GetRule(aIndex
);
1432 aRv
= mRuleList
->DeleteRule(aIndex
);
1433 if (!aRv
.Failed()) {
1438 nsresult
StyleSheet::InsertRuleIntoGroupInternal(const nsACString
& aRule
,
1439 css::GroupRule
* aGroup
,
1441 MOZ_ASSERT(!IsReadOnly());
1443 auto rules
= static_cast<ServoCSSRuleList
*>(aGroup
->CssRules());
1444 MOZ_ASSERT(rules
->GetParentRule() == aGroup
);
1445 return rules
->InsertRule(aRule
, aIndex
);
1448 StyleOrigin
StyleSheet::GetOrigin() const {
1449 return Servo_StyleSheet_GetOrigin(Inner().mContents
);
1452 void StyleSheet::SetSharedContents(const ServoCssRules
* aSharedRules
) {
1453 MOZ_ASSERT(!IsComplete());
1458 Servo_StyleSheet_FromSharedData(Inner().mURLData
, aSharedRules
).Consume();
1460 // Don't call FinishParse(), since that tries to set source map URLs,
1461 // which we don't have.
1464 const ServoCssRules
* StyleSheet::ToShared(RawServoSharedMemoryBuilder
* aBuilder
,
1465 nsCString
& aErrorMessage
) {
1466 // Assert some things we assume when creating a StyleSheet using shared
1468 MOZ_ASSERT(GetReferrerInfo()->ReferrerPolicy() == ReferrerPolicy::_empty
);
1469 MOZ_ASSERT(GetReferrerInfo()->GetSendReferrer());
1470 MOZ_ASSERT(!nsCOMPtr
<nsIURI
>(GetReferrerInfo()->GetComputedReferrer()));
1471 MOZ_ASSERT(GetCORSMode() == CORS_NONE
);
1472 MOZ_ASSERT(Inner().mIntegrity
.IsEmpty());
1473 MOZ_ASSERT(Principal()->IsSystemPrincipal());
1475 const ServoCssRules
* rules
= Servo_SharedMemoryBuilder_AddStylesheet(
1476 aBuilder
, Inner().mContents
, &aErrorMessage
);
1480 // Print the ToShmem error message so that developers know what to fix.
1481 printf_stderr("%s\n", aErrorMessage
.get());
1482 MOZ_CRASH("UA style sheet contents failed shared memory requirements");
1489 bool StyleSheet::IsReadOnly() const {
1490 return IsComplete() && GetOrigin() == StyleOrigin::UserAgent
;
1493 } // namespace mozilla